diff options
Diffstat (limited to 'src/rpc/blockchain.cpp')
-rw-r--r-- | src/rpc/blockchain.cpp | 105 |
1 files changed, 56 insertions, 49 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index df58052016..9427a9fc59 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -19,6 +19,8 @@ #include <hash.h> #include <index/blockfilterindex.h> #include <index/coinstatsindex.h> +#include <net.h> +#include <net_processing.h> #include <node/blockstorage.h> #include <logging/timer.h> #include <node/coinstats.h> @@ -30,6 +32,7 @@ #include <policy/rbf.h> #include <primitives/transaction.h> #include <rpc/server.h> +#include <rpc/server_util.h> #include <rpc/util.h> #include <script/descriptor.h> #include <streams.h> @@ -39,7 +42,6 @@ #include <undo.h> #include <util/strencodings.h> #include <util/string.h> -#include <util/system.h> #include <util/translation.h> #include <validation.h> #include <validationinterface.h> @@ -64,54 +66,6 @@ static Mutex cs_blockchange; static std::condition_variable cond_blockchange; static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange); -NodeContext& EnsureAnyNodeContext(const std::any& context) -{ - auto node_context = util::AnyPtr<NodeContext>(context); - if (!node_context) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Node context not found"); - } - return *node_context; -} - -CTxMemPool& EnsureMemPool(const NodeContext& node) -{ - if (!node.mempool) { - throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found"); - } - return *node.mempool; -} - -CTxMemPool& EnsureAnyMemPool(const std::any& context) -{ - return EnsureMemPool(EnsureAnyNodeContext(context)); -} - -ChainstateManager& EnsureChainman(const NodeContext& node) -{ - if (!node.chainman) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Node chainman not found"); - } - return *node.chainman; -} - -ChainstateManager& EnsureAnyChainman(const std::any& context) -{ - return EnsureChainman(EnsureAnyNodeContext(context)); -} - -CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node) -{ - if (!node.fee_estimator) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled"); - } - return *node.fee_estimator; -} - -CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context) -{ - return EnsureFeeEstimator(EnsureAnyNodeContext(context)); -} - /* Calculate the difficulty for a given block index. */ double GetDifficulty(const CBlockIndex* blockindex) @@ -821,6 +775,58 @@ static RPCHelpMan getmempoolentry() }; } +static RPCHelpMan getblockfrompeer() +{ + return RPCHelpMan{"getblockfrompeer", + "\nAttempt to fetch block from a given peer.\n" + "\nWe must have the header for this block, e.g. using submitheader.\n" + "\nReturns {} if a block-request was successfully scheduled\n", + { + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, + {"nodeid", RPCArg::Type::NUM, RPCArg::Optional::NO, "The node ID (see getpeerinfo for node IDs)"}, + }, + RPCResult{RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::STR, "warnings", "any warnings"} + }}, + RPCExamples{ + HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0") + + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0") + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + const NodeContext& node = EnsureAnyNodeContext(request.context); + ChainstateManager& chainman = EnsureChainman(node); + PeerManager& peerman = EnsurePeerman(node); + CConnman& connman = EnsureConnman(node); + + uint256 hash(ParseHashV(request.params[0], "hash")); + + const NodeId nodeid = static_cast<NodeId>(request.params[1].get_int64()); + + // Check that the peer with nodeid exists + if (!connman.ForNode(nodeid, [](CNode* node) {return true;})) { + throw JSONRPCError(RPC_MISC_ERROR, strprintf("Peer nodeid %d does not exist", nodeid)); + } + + const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(hash);); + + if (!index) { + throw JSONRPCError(RPC_MISC_ERROR, "Block header missing"); + } + + UniValue result = UniValue::VOBJ; + + if (index->nStatus & BLOCK_HAVE_DATA) { + result.pushKV("warnings", "Block already downloaded"); + } else if (!peerman.FetchBlock(nodeid, hash, *index)) { + throw JSONRPCError(RPC_MISC_ERROR, "Failed to fetch block from peer"); + } + return result; +}, + }; +} + static RPCHelpMan getblockhash() { return RPCHelpMan{"getblockhash", @@ -2704,6 +2710,7 @@ static const CRPCCommand commands[] = { "blockchain", &getbestblockhash, }, { "blockchain", &getblockcount, }, { "blockchain", &getblock, }, + { "blockchain", &getblockfrompeer, }, { "blockchain", &getblockhash, }, { "blockchain", &getblockheader, }, { "blockchain", &getchaintips, }, |