diff options
author | MarcoFalke <falke.marco@gmail.com> | 2021-12-08 10:38:10 +0100 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2021-12-08 10:39:37 +0100 |
commit | f6013265b7f22ce63f5e5fd8700c03d56cb000c8 (patch) | |
tree | ad077d2e4194df3657e5557521feadef959a1c2a /test | |
parent | 84d921e79c738c7959692a4e7a76327469e8cc50 (diff) | |
parent | dce8c4c38111556ca480aa0e63c46b71f66b508f (diff) |
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 'test')
-rwxr-xr-x | test/functional/rpc_getblockfrompeer.py | 76 | ||||
-rwxr-xr-x | test/functional/test_runner.py | 1 |
2 files changed, 77 insertions, 0 deletions
diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py new file mode 100755 index 0000000000..e841cba70e --- /dev/null +++ b/test/functional/rpc_getblockfrompeer.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test the getblockfrompeer RPC.""" + +from test_framework.authproxy import JSONRPCException +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, +) + +class GetBlockFromPeerTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 2 + + def setup_network(self): + self.setup_nodes() + + def check_for_block(self, hash): + try: + self.nodes[0].getblock(hash) + return True + except JSONRPCException: + return False + + def run_test(self): + self.log.info("Mine 4 blocks on Node 0") + self.generate(self.nodes[0], 4, sync_fun=self.no_op) + assert_equal(self.nodes[0].getblockcount(), 204) + + self.log.info("Mine competing 3 blocks on Node 1") + self.generate(self.nodes[1], 3, sync_fun=self.no_op) + assert_equal(self.nodes[1].getblockcount(), 203) + short_tip = self.nodes[1].getbestblockhash() + + self.log.info("Connect nodes to sync headers") + self.connect_nodes(0, 1) + self.sync_blocks() + + self.log.info("Node 0 should only have the header for node 1's block 3") + for x in self.nodes[0].getchaintips(): + if x['hash'] == short_tip: + assert_equal(x['status'], "headers-only") + break + else: + raise AssertionError("short tip not synced") + assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, short_tip) + + self.log.info("Fetch block from node 1") + peers = self.nodes[0].getpeerinfo() + assert_equal(len(peers), 1) + peer_0_peer_1_id = peers[0]["id"] + + self.log.info("Arguments must be sensible") + assert_raises_rpc_error(-8, "hash must be of length 64 (not 4, for '1234')", self.nodes[0].getblockfrompeer, "1234", 0) + + self.log.info("We must already have the header") + assert_raises_rpc_error(-1, "Block header missing", self.nodes[0].getblockfrompeer, "00" * 32, 0) + + self.log.info("Non-existent peer generates error") + assert_raises_rpc_error(-1, f"Peer nodeid {peer_0_peer_1_id + 1} does not exist", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id + 1) + + self.log.info("Successful fetch") + result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id) + self.wait_until(lambda: self.check_for_block(short_tip), timeout=1) + assert(not "warnings" in result) + + self.log.info("Don't fetch blocks we already have") + result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id) + assert("warnings" in result) + assert_equal(result["warnings"], "Block already downloaded") + +if __name__ == '__main__': + GetBlockFromPeerTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 8e7e791538..0a764a1755 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -217,6 +217,7 @@ BASE_SCRIPTS = [ 'wallet_txn_clone.py --mineblock', 'feature_notifications.py', 'rpc_getblockfilter.py', + 'rpc_getblockfrompeer.py', 'rpc_invalidateblock.py', 'feature_utxo_set_hash.py', 'feature_rbf.py --legacy-wallet', |