|
22 | 22 | #include <llmq/context.h>
|
23 | 23 | #include <node/blockstorage.h>
|
24 | 24 | #include <node/coinstats.h>
|
| 25 | +#include <net.h> |
| 26 | +#include <net_processing.h> |
25 | 27 | #include <node/context.h>
|
26 | 28 | #include <node/utxo_snapshot.h>
|
27 | 29 | #include <policy/feerate.h>
|
28 | 30 | #include <policy/fees.h>
|
29 | 31 | #include <policy/policy.h>
|
30 | 32 | #include <primitives/transaction.h>
|
31 | 33 | #include <rpc/server.h>
|
| 34 | +#include <rpc/server_util.h> |
32 | 35 | #include <rpc/util.h>
|
33 | 36 | #include <script/descriptor.h>
|
34 | 37 | #include <streams.h>
|
@@ -73,67 +76,6 @@ static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
|
73 | 76 |
|
74 | 77 | extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, CTxMemPool& mempool, CChainState& active_chainstate, llmq::CChainLocksHandler& clhandler, llmq::CInstantSendManager& isman, UniValue& entry);
|
75 | 78 |
|
76 |
| -NodeContext& EnsureAnyNodeContext(const CoreContext& context) |
77 |
| -{ |
78 |
| - auto* const node_context = GetContext<NodeContext>(context); |
79 |
| - if (!node_context) { |
80 |
| - throw JSONRPCError(RPC_INTERNAL_ERROR, "Node context not found"); |
81 |
| - } |
82 |
| - return *node_context; |
83 |
| -} |
84 |
| - |
85 |
| -CTxMemPool& EnsureMemPool(const NodeContext& node) |
86 |
| -{ |
87 |
| - if (!node.mempool) { |
88 |
| - throw JSONRPCError(RPC_CLIENT_MEMPOOL_DISABLED, "Mempool disabled or instance not found"); |
89 |
| - } |
90 |
| - return *node.mempool; |
91 |
| -} |
92 |
| - |
93 |
| -CTxMemPool& EnsureAnyMemPool(const CoreContext& context) |
94 |
| -{ |
95 |
| - return EnsureMemPool(EnsureAnyNodeContext(context)); |
96 |
| -} |
97 |
| - |
98 |
| -ChainstateManager& EnsureChainman(const NodeContext& node) |
99 |
| -{ |
100 |
| - if (!node.chainman) { |
101 |
| - throw JSONRPCError(RPC_INTERNAL_ERROR, "Node chainman not found"); |
102 |
| - } |
103 |
| - return *node.chainman; |
104 |
| -} |
105 |
| - |
106 |
| -ChainstateManager& EnsureAnyChainman(const CoreContext& context) |
107 |
| -{ |
108 |
| - return EnsureChainman(EnsureAnyNodeContext(context)); |
109 |
| -} |
110 |
| - |
111 |
| -CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node) |
112 |
| -{ |
113 |
| - if (!node.fee_estimator) { |
114 |
| - throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled"); |
115 |
| - } |
116 |
| - return *node.fee_estimator; |
117 |
| -} |
118 |
| - |
119 |
| -CBlockPolicyEstimator& EnsureAnyFeeEstimator(const CoreContext& context) |
120 |
| -{ |
121 |
| - return EnsureFeeEstimator(EnsureAnyNodeContext(context)); |
122 |
| -} |
123 |
| - |
124 |
| -LLMQContext& EnsureLLMQContext(const NodeContext& node) |
125 |
| -{ |
126 |
| - if (!node.llmq_ctx) { |
127 |
| - throw JSONRPCError(RPC_INTERNAL_ERROR, "Node LLMQ context not found"); |
128 |
| - } |
129 |
| - return *node.llmq_ctx; |
130 |
| -} |
131 |
| - |
132 |
| -LLMQContext& EnsureAnyLLMQContext(const CoreContext& context) |
133 |
| -{ |
134 |
| - return EnsureLLMQContext(EnsureAnyNodeContext(context)); |
135 |
| -} |
136 |
| - |
137 | 79 | /* Calculate the difficulty for a given block index.
|
138 | 80 | */
|
139 | 81 | double GetDifficulty(const CBlockIndex* blockindex)
|
@@ -825,6 +767,58 @@ static RPCHelpMan getmempoolentry()
|
825 | 767 | };
|
826 | 768 | }
|
827 | 769 |
|
| 770 | +static RPCHelpMan getblockfrompeer() |
| 771 | +{ |
| 772 | + return RPCHelpMan{"getblockfrompeer", |
| 773 | + "\nAttempt to fetch block from a given peer.\n" |
| 774 | + "\nWe must have the header for this block, e.g. using submitheader.\n" |
| 775 | + "\nReturns {} if a block-request was successfully scheduled\n", |
| 776 | + { |
| 777 | + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, |
| 778 | + {"nodeid", RPCArg::Type::NUM, RPCArg::Optional::NO, "The node ID (see getpeerinfo for node IDs)"}, |
| 779 | + }, |
| 780 | + RPCResult{RPCResult::Type::OBJ, "", "", |
| 781 | + { |
| 782 | + {RPCResult::Type::STR, "warnings", "any warnings"} |
| 783 | + }}, |
| 784 | + RPCExamples{ |
| 785 | + HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0") |
| 786 | + + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0") |
| 787 | + }, |
| 788 | + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 789 | +{ |
| 790 | + const NodeContext& node = EnsureAnyNodeContext(request.context); |
| 791 | + ChainstateManager& chainman = EnsureChainman(node); |
| 792 | + PeerManager& peerman = EnsurePeerman(node); |
| 793 | + CConnman& connman = EnsureConnman(node); |
| 794 | + |
| 795 | + uint256 hash(ParseHashV(request.params[0], "hash")); |
| 796 | + |
| 797 | + const NodeId nodeid = static_cast<NodeId>(request.params[1].get_int64()); |
| 798 | + |
| 799 | + // Check that the peer with nodeid exists |
| 800 | + if (!connman.ForNode(nodeid, [](CNode* node) {return true;})) { |
| 801 | + throw JSONRPCError(RPC_MISC_ERROR, strprintf("Peer nodeid %d does not exist", nodeid)); |
| 802 | + } |
| 803 | + |
| 804 | + const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(hash);); |
| 805 | + |
| 806 | + if (!index) { |
| 807 | + throw JSONRPCError(RPC_MISC_ERROR, "Block header missing"); |
| 808 | + } |
| 809 | + |
| 810 | + UniValue result = UniValue::VOBJ; |
| 811 | + |
| 812 | + if (index->nStatus & BLOCK_HAVE_DATA) { |
| 813 | + result.pushKV("warnings", "Block already downloaded"); |
| 814 | + } else if (!peerman.FetchBlock(nodeid, hash, *index)) { |
| 815 | + throw JSONRPCError(RPC_MISC_ERROR, "Failed to fetch block from peer"); |
| 816 | + } |
| 817 | + return result; |
| 818 | +}, |
| 819 | + }; |
| 820 | +} |
| 821 | + |
828 | 822 | static RPCHelpMan getblockhashes()
|
829 | 823 | {
|
830 | 824 | return RPCHelpMan{"getblockhashes",
|
@@ -3058,6 +3052,7 @@ static const CRPCCommand commands[] =
|
3058 | 3052 | { "blockchain", "getbestchainlock", &getbestchainlock, {} },
|
3059 | 3053 | { "blockchain", "getblockcount", &getblockcount, {} },
|
3060 | 3054 | { "blockchain", "getblock", &getblock, {"blockhash","verbosity|verbose"} },
|
| 3055 | + { "blockchain", "getblockfrompeer", &getblockfrompeer, {"blockhash", "nodeid"}}, |
3061 | 3056 | { "blockchain", "getblockhashes", &getblockhashes, {"high","low"} },
|
3062 | 3057 | { "blockchain", "getblockhash", &getblockhash, {"height"} },
|
3063 | 3058 | { "blockchain", "getblockheader", &getblockheader, {"blockhash","verbose"} },
|
|
0 commit comments