aboutsummaryrefslogtreecommitdiff
path: root/src/rpc/blockchain.cpp
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2021-12-08 10:38:10 +0100
committerMarcoFalke <falke.marco@gmail.com>2021-12-08 10:39:37 +0100
commitf6013265b7f22ce63f5e5fd8700c03d56cb000c8 (patch)
treead077d2e4194df3657e5557521feadef959a1c2a /src/rpc/blockchain.cpp
parent84d921e79c738c7959692a4e7a76327469e8cc50 (diff)
parentdce8c4c38111556ca480aa0e63c46b71f66b508f (diff)
downloadbitcoin-f6013265b7f22ce63f5e5fd8700c03d56cb000c8.tar.xz
Merge bitcoin/bitcoin#20295: rpc: getblockfrompeer
dce8c4c38111556ca480aa0e63c46b71f66b508f rpc: getblockfrompeer (Sjors Provoost) b884ababc29ce963826d8a4327ed6a5e629ff175 rpc: move Ensure* helpers to server_util.h (Sjors Provoost) Pull request description: This adds an RPC method to fetch a block directly from a peer. This can used to fetch stale blocks with lower proof of work that are normally ignored by the node (`headers-only` in `getchaintips`). Usage: ``` bitcoin-cli getblockfrompeer HASH peer_n ``` Closes #20155 Limitations: * you have to specify which peer to fetch the block from * the node must already have the header ACKs for top commit: jnewbery: ACK dce8c4c38111556ca480aa0e63c46b71f66b508f fjahr: re-ACK dce8c4c38111556ca480aa0e63c46b71f66b508f Tree-SHA512: 843ba2b7a308f640770d624d0aa3265fdc5c6ea48e8db32269b96a082b7420f7953d1d8d1ef2e6529392c7172dded9d15639fbc9c24e7bfa5cfb79e13a5498c8
Diffstat (limited to 'src/rpc/blockchain.cpp')
-rw-r--r--src/rpc/blockchain.cpp105
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, },