|
18 | 18 | #include <hash.h> |
19 | 19 | #include <index/blockfilterindex.h> |
20 | 20 | #include <index/coinstatsindex.h> |
| 21 | +#include <net.h> |
| 22 | +#include <net_processing.h> |
21 | 23 | #include <node/blockstorage.h> |
22 | 24 | #include <node/coinstats.h> |
23 | 25 | #include <node/context.h> |
@@ -755,6 +757,58 @@ static RPCHelpMan getmempoolentry() |
755 | 757 | }; |
756 | 758 | } |
757 | 759 |
|
| 760 | +static RPCHelpMan getblockfrompeer() |
| 761 | +{ |
| 762 | + return RPCHelpMan{"getblockfrompeer", |
| 763 | + "\nAttempt to fetch block from a given peer.\n" |
| 764 | + "\nWe must have the header for this block, e.g. using submitheader.\n" |
| 765 | + "\nReturns {} if a block-request was successfully scheduled\n", |
| 766 | + { |
| 767 | + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, |
| 768 | + {"nodeid", RPCArg::Type::NUM, RPCArg::Optional::NO, "The node ID (see getpeerinfo for node IDs)"}, |
| 769 | + }, |
| 770 | + RPCResult{RPCResult::Type::OBJ, "", "", |
| 771 | + { |
| 772 | + {RPCResult::Type::STR, "warnings", "any warnings"} |
| 773 | + }}, |
| 774 | + RPCExamples{ |
| 775 | + HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0") |
| 776 | + + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0") |
| 777 | + }, |
| 778 | + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 779 | +{ |
| 780 | + const NodeContext& node = EnsureAnyNodeContext(request.context); |
| 781 | + ChainstateManager& chainman = EnsureChainman(node); |
| 782 | + PeerManager& peerman = EnsurePeerman(node); |
| 783 | + CConnman& connman = EnsureConnman(node); |
| 784 | + |
| 785 | + uint256 hash(ParseHashV(request.params[0], "hash")); |
| 786 | + |
| 787 | + const NodeId nodeid = static_cast<NodeId>(request.params[1].get_int64()); |
| 788 | + |
| 789 | + // Check that the peer with nodeid exists |
| 790 | + if (!connman.ForNode(nodeid, [](CNode* node) {return true;})) { |
| 791 | + throw JSONRPCError(RPC_MISC_ERROR, strprintf("Peer nodeid %d does not exist", nodeid)); |
| 792 | + } |
| 793 | + |
| 794 | + const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(hash);); |
| 795 | + |
| 796 | + if (!index) { |
| 797 | + throw JSONRPCError(RPC_MISC_ERROR, "Block header missing"); |
| 798 | + } |
| 799 | + |
| 800 | + UniValue result = UniValue::VOBJ; |
| 801 | + |
| 802 | + if (index->nStatus & BLOCK_HAVE_DATA) { |
| 803 | + result.pushKV("warnings", "Block already downloaded"); |
| 804 | + } else if (!peerman.FetchBlock(nodeid, hash, *index)) { |
| 805 | + throw JSONRPCError(RPC_MISC_ERROR, "Failed to fetch block from peer"); |
| 806 | + } |
| 807 | + return result; |
| 808 | +}, |
| 809 | + }; |
| 810 | +} |
| 811 | + |
758 | 812 | static RPCHelpMan getblockhash() |
759 | 813 | { |
760 | 814 | return RPCHelpMan{"getblockhash", |
@@ -2612,6 +2666,7 @@ static const CRPCCommand commands[] = |
2612 | 2666 | { "blockchain", &getbestblockhash, }, |
2613 | 2667 | { "blockchain", &getblockcount, }, |
2614 | 2668 | { "blockchain", &getblock, }, |
| 2669 | + { "blockchain", &getblockfrompeer, }, |
2615 | 2670 | { "blockchain", &getblockhash, }, |
2616 | 2671 | { "blockchain", &getblockheader, }, |
2617 | 2672 | { "blockchain", &getchaintips, }, |
|
0 commit comments