Skip to content
This repository has been archived by the owner on Apr 16, 2023. It is now read-only.

Commit

Permalink
Merge pull request #606 from brandonlehmann/a_smarter_mouse_trap
Browse files Browse the repository at this point in the history
Adding daemon /queryblocksdetailed
  • Loading branch information
brandonlehmann committed Nov 13, 2018
2 parents 2576332 + 0013331 commit b289f2a
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 26 deletions.
88 changes: 86 additions & 2 deletions src/CryptoNoteCore/Core.cpp
Expand Up @@ -448,6 +448,53 @@ bool Core::queryBlocksLite(const std::vector<Crypto::Hash>& knownBlockHashes, ui
}
}

bool Core::queryBlocksDetailed(const std::vector<Crypto::Hash>& knownBlockHashes, uint64_t timestamp, uint32_t& startIndex,
uint32_t& currentIndex, uint32_t& fullOffset, std::vector<BlockDetails>& entries) const {
assert(entries.empty());
assert(!chainsLeaves.empty());
assert(!chainsStorage.empty());

throwIfNotInitialized();

try {
IBlockchainCache* mainChain = chainsLeaves[0];
currentIndex = mainChain->getTopBlockIndex();

startIndex = findBlockchainSupplement(knownBlockHashes); // throws

// Stops bug where wallets fail to sync, because timestamps have been adjusted after syncronisation.
// check for a query of the blocks where the block index is non-zero, but the timestamp is zero
// indicating that the originator did not know the internal time of the block, but knew which block
// was wanted by index. Fullfill this by getting the time of m_blocks[startIndex].timestamp.

if (startIndex > 0 && timestamp == 0) {
if (startIndex <= mainChain->getTopBlockIndex()) {
RawBlock block = mainChain->getBlockByIndex(startIndex);
auto blockTemplate = extractBlockTemplate(block);
timestamp = blockTemplate.timestamp;
}
}

fullOffset = mainChain->getTimestampLowerBoundBlockIndex(timestamp);
if (fullOffset < startIndex) {
fullOffset = startIndex;
}

size_t hashesPushed = pushBlockHashes(startIndex, fullOffset, BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT, entries);

if (startIndex + static_cast<uint32_t>(hashesPushed) != fullOffset) {
return true;
}

fillQueryBlockDetails(fullOffset, currentIndex, BLOCKS_SYNCHRONIZING_DEFAULT_COUNT, entries);

return true;
} catch (std::exception& e) {
logger(Logging::ERROR) << "Failed to query blocks: " << e.what();
return false;
}
}

void Core::getTransactions(const std::vector<Crypto::Hash>& transactionHashes, std::vector<BinaryArray>& transactions,
std::vector<Crypto::Hash>& missedHashes) const {
assert(!chainsLeaves.empty());
Expand Down Expand Up @@ -1741,7 +1788,7 @@ RawBlock Core::getRawBlock(IBlockchainCache* segment, uint32_t blockIndex) const
return segment->getBlockByIndex(blockIndex);
}

//TODO: decompose these two methods
//TODO: decompose these three methods
size_t Core::pushBlockHashes(uint32_t startIndex, uint32_t fullOffset, size_t maxItemsCount,
std::vector<BlockShortInfo>& entries) const {
assert(fullOffset >= startIndex);
Expand All @@ -1763,7 +1810,29 @@ size_t Core::pushBlockHashes(uint32_t startIndex, uint32_t fullOffset, size_t ma
return blockIds.size();
}

//TODO: decompose these two methods
//TODO: decompose these three methods
size_t Core::pushBlockHashes(uint32_t startIndex, uint32_t fullOffset, size_t maxItemsCount,
std::vector<BlockDetails>& entries) const {
assert(fullOffset >= startIndex);

uint32_t itemsCount = std::min(fullOffset - startIndex, static_cast<uint32_t>(maxItemsCount));
if (itemsCount == 0) {
return 0;
}

std::vector<Crypto::Hash> blockIds = getBlockHashes(startIndex, itemsCount);

entries.reserve(entries.size() + blockIds.size());
for (auto& blockHash : blockIds) {
BlockDetails entry;
entry.hash = std::move(blockHash);
entries.emplace_back(std::move(entry));
}

return blockIds.size();
}

//TODO: decompose these three methods
size_t Core::pushBlockHashes(uint32_t startIndex, uint32_t fullOffset, size_t maxItemsCount,
std::vector<BlockFullInfo>& entries) const {
assert(fullOffset >= startIndex);
Expand Down Expand Up @@ -1839,6 +1908,21 @@ void Core::fillQueryBlockShortInfo(uint32_t fullOffset, uint32_t currentIndex, s
}
}

void Core::fillQueryBlockDetails(uint32_t fullOffset, uint32_t currentIndex, size_t maxItemsCount,
std::vector<BlockDetails>& entries) const {
assert(currentIndex >= fullOffset);

uint32_t fullBlocksCount = static_cast<uint32_t>(std::min(static_cast<uint32_t>(maxItemsCount), currentIndex - fullOffset + 1));
entries.reserve(entries.size() + fullBlocksCount);

for (uint32_t blockIndex = fullOffset; blockIndex < fullOffset + fullBlocksCount; ++blockIndex) {
IBlockchainCache* segment = findMainChainSegmentContainingBlock(blockIndex);
Crypto::Hash blockHash = segment->getBlockHash(blockIndex);
BlockDetails block = getBlockDetails(blockHash);
entries.emplace_back(std::move(block));
}
}

void Core::getTransactionPoolDifference(const std::vector<Crypto::Hash>& knownHashes,
std::vector<Crypto::Hash>& newTransactions,
std::vector<Crypto::Hash>& deletedTransactions) const {
Expand Down
4 changes: 4 additions & 0 deletions src/CryptoNoteCore/Core.h
Expand Up @@ -58,6 +58,8 @@ class Core : public ICore, public ICoreInformation {
uint32_t& startIndex, uint32_t& currentIndex, uint32_t& fullOffset, std::vector<BlockFullInfo>& entries) const override;
virtual bool queryBlocksLite(const std::vector<Crypto::Hash>& knownBlockHashes, uint64_t timestamp,
uint32_t& startIndex, uint32_t& currentIndex, uint32_t& fullOffset, std::vector<BlockShortInfo>& entries) const override;
virtual bool queryBlocksDetailed(const std::vector<Crypto::Hash>& knownBlockHashes, uint64_t timestamp,
uint32_t& startIndex, uint32_t& currentIndex, uint32_t& fullOffset, std::vector<BlockDetails>& entries) const override;

virtual bool hasTransaction(const Crypto::Hash& transactionHash) const override;
virtual void getTransactions(const std::vector<Crypto::Hash>& transactionHashes, std::vector<BinaryArray>& transactions, std::vector<Crypto::Hash>& missedHashes) const override;
Expand Down Expand Up @@ -162,9 +164,11 @@ class Core : public ICore, public ICoreInformation {

size_t pushBlockHashes(uint32_t startIndex, uint32_t fullOffset, size_t maxItemsCount, std::vector<BlockShortInfo>& entries) const;
size_t pushBlockHashes(uint32_t startIndex, uint32_t fullOffset, size_t maxItemsCount, std::vector<BlockFullInfo>& entries) const;
size_t pushBlockHashes(uint32_t startIndex, uint32_t fullOffset, size_t maxItemsCount, std::vector<BlockDetails>& entries) const;
bool notifyObservers(BlockchainMessage&& msg);
void fillQueryBlockFullInfo(uint32_t fullOffset, uint32_t currentIndex, size_t maxItemsCount, std::vector<BlockFullInfo>& entries) const;
void fillQueryBlockShortInfo(uint32_t fullOffset, uint32_t currentIndex, size_t maxItemsCount, std::vector<BlockShortInfo>& entries) const;
void fillQueryBlockDetails(uint32_t fullOffset, uint32_t currentIndex, size_t maxItemsCount, std::vector<BlockDetails>& entries) const;

void getTransactionPoolDifference(const std::vector<Crypto::Hash>& knownHashes, std::vector<Crypto::Hash>& newTransactions, std::vector<Crypto::Hash>& deletedTransactions) const;

Expand Down
19 changes: 5 additions & 14 deletions src/CryptoNoteCore/ICore.h
@@ -1,19 +1,7 @@
// Copyright (c) 2012-2017, The CryptoNote developers, The Bytecoin developers
// Copyright (c) 2018, The TurtleCoin Developers
//
// This file is part of Bytecoin.
//
// Bytecoin is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Bytecoin is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
// Please see the included LICENSE file for more information.

#pragma once
#include <vector>
Expand Down Expand Up @@ -64,6 +52,9 @@ class ICore {
virtual bool queryBlocksLite(const std::vector<Crypto::Hash>& knownBlockHashes, uint64_t timestamp,
uint32_t& startIndex, uint32_t& currentIndex, uint32_t& fullOffset,
std::vector<BlockShortInfo>& entries) const = 0;
virtual bool queryBlocksDetailed(const std::vector<Crypto::Hash>& knownBlockHashes, uint64_t timestamp,
uint32_t& startIndex, uint32_t& currentIndex, uint32_t& fullOffset,
std::vector<BlockDetails>& entries) const = 0;

virtual bool hasTransaction(const Crypto::Hash& transactionHash) const = 0;
virtual void getTransactions(const std::vector<Crypto::Hash>& transactionHashes,
Expand Down
42 changes: 35 additions & 7 deletions src/Rpc/CoreRpcServerCommandsDefinitions.h
@@ -1,7 +1,7 @@
// Copyright (c) 2012-2017, The CryptoNote developers, The Bytecoin developers
// Copyright (c) 2018, The TurtleCoin Developers
// Copyright (c) 2018, The Karai Developers
//
//
// Please see the included LICENSE file for more information.

#pragma once
Expand Down Expand Up @@ -54,7 +54,7 @@ struct COMMAND_RPC_GET_BLOCKS_FAST {

struct request {
std::vector<Crypto::Hash> block_ids; //*first 10 blocks id goes sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */

void serialize(ISerializer &s) {
KV_MEMBER(block_ids);
}
Expand Down Expand Up @@ -85,7 +85,7 @@ struct COMMAND_RPC_GET_TRANSACTIONS {
void serialize(ISerializer &s) {
KV_MEMBER(txs_as_hex)
KV_MEMBER(missed_tx)
KV_MEMBER(status)
KV_MEMBER(status)
}
};
};
Expand Down Expand Up @@ -144,7 +144,7 @@ struct COMMAND_RPC_GET_POOL_CHANGES_LITE {

//-----------------------------------------------
struct COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES {

struct request {
Crypto::Hash txid;

Expand Down Expand Up @@ -178,7 +178,7 @@ struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_request {
struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_out_entry {
uint32_t global_amount_index;
Crypto::PublicKey out_key;

void serialize(ISerializer &s) {
KV_MEMBER(global_amount_index)
KV_MEMBER(out_key);
Expand Down Expand Up @@ -516,7 +516,7 @@ struct f_block_short_response {

struct f_block_details_response {
uint8_t major_version;
uint8_t minor_version;
uint8_t minor_version;
uint64_t timestamp;
std::string prev_hash;
uint32_t nonce;
Expand Down Expand Up @@ -723,6 +723,34 @@ struct COMMAND_RPC_QUERY_BLOCKS_LITE {
};
};

struct COMMAND_RPC_QUERY_BLOCKS_DETAILED {
struct request {
std::vector<Crypto::Hash> blockIds;
uint64_t timestamp;

void serialize(ISerializer &s) {
KV_MEMBER(blockIds);
KV_MEMBER(timestamp)
}
};

struct response {
std::string status;
uint64_t startHeight;
uint64_t currentHeight;
uint64_t fullOffset;
std::vector<BlockDetails> blocks;

void serialize(ISerializer &s) {
KV_MEMBER(status)
KV_MEMBER(startHeight)
KV_MEMBER(currentHeight)
KV_MEMBER(fullOffset)
KV_MEMBER(blocks)
}
};
};

struct COMMAND_RPC_GET_BLOCKS_DETAILS_BY_HEIGHTS {
struct request {
std::vector<uint32_t> blockHeights;
Expand Down Expand Up @@ -846,7 +874,7 @@ struct COMMAND_RPC_GET_TRANSACTION_DETAILS_BY_HASHES {
};

struct COMMAND_RPC_GET_PEERS {
// TODO: rename peers to white_peers - do at v1
// TODO: rename peers to white_peers - do at v1
typedef EMPTY_STRUCT request;

struct response {
Expand Down
26 changes: 23 additions & 3 deletions src/Rpc/RpcServer.cpp
Expand Up @@ -85,19 +85,20 @@ std::unordered_map<std::string, RpcServer::RpcHandler<RpcServer::HandlerFunction
{ "/getheight", { jsonMethod<COMMAND_RPC_GET_HEIGHT>(&RpcServer::on_get_height), true } },
{ "/feeinfo", { jsonMethod<COMMAND_RPC_GET_FEE_ADDRESS>(&RpcServer::on_get_fee_info), true } },
{ "/getpeers", { jsonMethod<COMMAND_RPC_GET_PEERS>(&RpcServer::on_get_peers), true } },

// new json handlers
{ "/info", { jsonMethod<COMMAND_RPC_GET_INFO>(&RpcServer::on_get_info), true } },
{ "/height", { jsonMethod<COMMAND_RPC_GET_HEIGHT>(&RpcServer::on_get_height), true } },
{ "/fee", { jsonMethod<COMMAND_RPC_GET_FEE_ADDRESS>(&RpcServer::on_get_fee_info), true } },
{ "/peers", { jsonMethod<COMMAND_RPC_GET_PEERS>(&RpcServer::on_get_peers), true } },

{ "/gettransactions", { jsonMethod<COMMAND_RPC_GET_TRANSACTIONS>(&RpcServer::on_get_transactions), false } },
{ "/sendrawtransaction", { jsonMethod<COMMAND_RPC_SEND_RAW_TX>(&RpcServer::on_send_raw_tx), false } },

{ "/getblocks", { jsonMethod<COMMAND_RPC_GET_BLOCKS_FAST>(&RpcServer::on_get_blocks), false } },
{ "/queryblocks", { jsonMethod<COMMAND_RPC_QUERY_BLOCKS>(&RpcServer::on_query_blocks), false } },
{ "/queryblockslite", { jsonMethod<COMMAND_RPC_QUERY_BLOCKS_LITE>(&RpcServer::on_query_blocks_lite), false } },
{ "/queryblocksdetailed", { jsonMethod<COMMAND_RPC_QUERY_BLOCKS_DETAILED>(&RpcServer::on_query_blocks_detailed), false } },
{ "/get_o_indexes", { jsonMethod<COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES>(&RpcServer::on_get_indexes), false } },
{ "/getrandom_outs", { jsonMethod<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS>(&RpcServer::on_get_random_outs), false } },
{ "/get_pool_changes", { jsonMethod<COMMAND_RPC_GET_POOL_CHANGES>(&RpcServer::onGetPoolChanges), false } },
Expand Down Expand Up @@ -278,6 +279,25 @@ bool RpcServer::on_query_blocks_lite(const COMMAND_RPC_QUERY_BLOCKS_LITE::reques
return true;
}

bool RpcServer::on_query_blocks_detailed(const COMMAND_RPC_QUERY_BLOCKS_DETAILED::request& req, COMMAND_RPC_QUERY_BLOCKS_DETAILED::response& res) {
uint32_t startIndex;
uint32_t currentIndex;
uint32_t fullOffset;

if (!m_core.queryBlocksDetailed(req.blockIds, req.timestamp, startIndex, currentIndex, fullOffset, res.blocks))
{
res.status = "Failed to perform query";
return false;
}

res.startHeight = startIndex;
res.currentHeight = currentIndex;
res.fullOffset = fullOffset;
res.status = CORE_RPC_STATUS_OK;

return true;
}

bool RpcServer::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res) {
std::vector<uint32_t> outputIndexes;
if (!m_core.getTransactionGlobalIndexes(req.txid, outputIndexes)) {
Expand Down
1 change: 1 addition & 0 deletions src/Rpc/RpcServer.h
Expand Up @@ -54,6 +54,7 @@ class RpcServer : public HttpServer {
bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res);
bool on_query_blocks(const COMMAND_RPC_QUERY_BLOCKS::request& req, COMMAND_RPC_QUERY_BLOCKS::response& res);
bool on_query_blocks_lite(const COMMAND_RPC_QUERY_BLOCKS_LITE::request& req, COMMAND_RPC_QUERY_BLOCKS_LITE::response& res);
bool on_query_blocks_detailed(const COMMAND_RPC_QUERY_BLOCKS_DETAILED::request& req, COMMAND_RPC_QUERY_BLOCKS_DETAILED::response& res);
bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res);
bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res);
bool onGetPoolChanges(const COMMAND_RPC_GET_POOL_CHANGES::request& req, COMMAND_RPC_GET_POOL_CHANGES::response& rsp);
Expand Down

0 comments on commit b289f2a

Please sign in to comment.