1919#include < hash.h>
2020#include < index/blockfilterindex.h>
2121#include < index/coinstatsindex.h>
22+ #include < net.h>
23+ #include < net_processing.h>
2224#include < node/blockstorage.h>
2325#include < logging/timer.h>
2426#include < node/coinstats.h>
3032#include < policy/rbf.h>
3133#include < primitives/transaction.h>
3234#include < rpc/server.h>
35+ #include < rpc/server_util.h>
3336#include < rpc/util.h>
3437#include < script/descriptor.h>
3538#include < streams.h>
3942#include < undo.h>
4043#include < util/strencodings.h>
4144#include < util/string.h>
42- #include < util/system.h>
4345#include < util/translation.h>
4446#include < validation.h>
4547#include < validationinterface.h>
@@ -64,54 +66,6 @@ static Mutex cs_blockchange;
6466static std::condition_variable cond_blockchange;
6567static CUpdatedBlock latestblock GUARDED_BY (cs_blockchange);
6668
67- NodeContext& EnsureAnyNodeContext (const std::any& context)
68- {
69- auto node_context = util::AnyPtr<NodeContext>(context);
70- if (!node_context) {
71- throw JSONRPCError (RPC_INTERNAL_ERROR, " Node context not found" );
72- }
73- return *node_context;
74- }
75-
76- CTxMemPool& EnsureMemPool (const NodeContext& node)
77- {
78- if (!node.mempool ) {
79- throw JSONRPCError (RPC_CLIENT_MEMPOOL_DISABLED, " Mempool disabled or instance not found" );
80- }
81- return *node.mempool ;
82- }
83-
84- CTxMemPool& EnsureAnyMemPool (const std::any& context)
85- {
86- return EnsureMemPool (EnsureAnyNodeContext (context));
87- }
88-
89- ChainstateManager& EnsureChainman (const NodeContext& node)
90- {
91- if (!node.chainman ) {
92- throw JSONRPCError (RPC_INTERNAL_ERROR, " Node chainman not found" );
93- }
94- return *node.chainman ;
95- }
96-
97- ChainstateManager& EnsureAnyChainman (const std::any& context)
98- {
99- return EnsureChainman (EnsureAnyNodeContext (context));
100- }
101-
102- CBlockPolicyEstimator& EnsureFeeEstimator (const NodeContext& node)
103- {
104- if (!node.fee_estimator ) {
105- throw JSONRPCError (RPC_INTERNAL_ERROR, " Fee estimation disabled" );
106- }
107- return *node.fee_estimator ;
108- }
109-
110- CBlockPolicyEstimator& EnsureAnyFeeEstimator (const std::any& context)
111- {
112- return EnsureFeeEstimator (EnsureAnyNodeContext (context));
113- }
114-
11569/* Calculate the difficulty for a given block index.
11670 */
11771double GetDifficulty (const CBlockIndex* blockindex)
@@ -821,6 +775,58 @@ static RPCHelpMan getmempoolentry()
821775 };
822776}
823777
778+ static RPCHelpMan getblockfrompeer ()
779+ {
780+ return RPCHelpMan{" getblockfrompeer" ,
781+ " \n Attempt to fetch block from a given peer.\n "
782+ " \n We must have the header for this block, e.g. using submitheader.\n "
783+ " \n Returns {} if a block-request was successfully scheduled\n " ,
784+ {
785+ {" blockhash" , RPCArg::Type::STR_HEX, RPCArg::Optional::NO, " The block hash" },
786+ {" nodeid" , RPCArg::Type::NUM, RPCArg::Optional::NO, " The node ID (see getpeerinfo for node IDs)" },
787+ },
788+ RPCResult{RPCResult::Type::OBJ, " " , " " ,
789+ {
790+ {RPCResult::Type::STR, " warnings" , " any warnings" }
791+ }},
792+ RPCExamples{
793+ HelpExampleCli (" getblockfrompeer" , " \" 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0" )
794+ + HelpExampleRpc (" getblockfrompeer" , " \" 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0" )
795+ },
796+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
797+ {
798+ const NodeContext& node = EnsureAnyNodeContext (request.context );
799+ ChainstateManager& chainman = EnsureChainman (node);
800+ PeerManager& peerman = EnsurePeerman (node);
801+ CConnman& connman = EnsureConnman (node);
802+
803+ uint256 hash (ParseHashV (request.params [0 ], " hash" ));
804+
805+ const NodeId nodeid = static_cast <NodeId>(request.params [1 ].get_int64 ());
806+
807+ // Check that the peer with nodeid exists
808+ if (!connman.ForNode (nodeid, [](CNode* node) {return true ;})) {
809+ throw JSONRPCError (RPC_MISC_ERROR, strprintf (" Peer nodeid %d does not exist" , nodeid));
810+ }
811+
812+ const CBlockIndex* const index = WITH_LOCK (cs_main, return chainman.m_blockman .LookupBlockIndex (hash););
813+
814+ if (!index) {
815+ throw JSONRPCError (RPC_MISC_ERROR, " Block header missing" );
816+ }
817+
818+ UniValue result = UniValue::VOBJ;
819+
820+ if (index->nStatus & BLOCK_HAVE_DATA) {
821+ result.pushKV (" warnings" , " Block already downloaded" );
822+ } else if (!peerman.FetchBlock (nodeid, hash, *index)) {
823+ throw JSONRPCError (RPC_MISC_ERROR, " Failed to fetch block from peer" );
824+ }
825+ return result;
826+ },
827+ };
828+ }
829+
824830static RPCHelpMan getblockhash ()
825831{
826832 return RPCHelpMan{" getblockhash" ,
@@ -2704,6 +2710,7 @@ static const CRPCCommand commands[] =
27042710 { " blockchain" , &getbestblockhash, },
27052711 { " blockchain" , &getblockcount, },
27062712 { " blockchain" , &getblock, },
2713+ { " blockchain" , &getblockfrompeer, },
27072714 { " blockchain" , &getblockhash, },
27082715 { " blockchain" , &getblockheader, },
27092716 { " blockchain" , &getchaintips, },
0 commit comments