mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-06-21 14:22:38 +02:00
test: avoid requesting blocks beyond limited peer threshold
Even when the node believes it completed IBD, need to avoid requesting historical blocks from network-limited peers. Otherwise, the limited peer will disconnect right away.
This commit is contained in:
parent
2f6a05512f
commit
c5b5843d8f
@ -21,8 +21,12 @@ from test_framework.p2p import P2PInterface
|
|||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import (
|
from test_framework.util import (
|
||||||
assert_equal,
|
assert_equal,
|
||||||
|
assert_raises_rpc_error,
|
||||||
|
try_rpc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Minimum blocks required to signal NODE_NETWORK_LIMITED #
|
||||||
|
NODE_NETWORK_LIMITED_MIN_BLOCKS = 288
|
||||||
|
|
||||||
class P2PIgnoreInv(P2PInterface):
|
class P2PIgnoreInv(P2PInterface):
|
||||||
firstAddrnServices = 0
|
firstAddrnServices = 0
|
||||||
@ -54,6 +58,63 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
|
|||||||
self.add_nodes(self.num_nodes, self.extra_args)
|
self.add_nodes(self.num_nodes, self.extra_args)
|
||||||
self.start_nodes()
|
self.start_nodes()
|
||||||
|
|
||||||
|
def test_avoid_requesting_historical_blocks(self):
|
||||||
|
self.log.info("Test full node does not request blocks beyond the limited peer threshold")
|
||||||
|
pruned_node = self.nodes[0]
|
||||||
|
miner = self.nodes[1]
|
||||||
|
full_node = self.nodes[2]
|
||||||
|
|
||||||
|
# Connect and generate block to ensure IBD=false
|
||||||
|
self.connect_nodes(1, 0)
|
||||||
|
self.connect_nodes(1, 2)
|
||||||
|
self.generate(miner, 1)
|
||||||
|
|
||||||
|
# Verify peers are out of IBD
|
||||||
|
for node in self.nodes:
|
||||||
|
assert not node.getblockchaininfo()['initialblockdownload']
|
||||||
|
|
||||||
|
# Isolate full_node (the node will remain out of IBD)
|
||||||
|
full_node.setnetworkactive(False)
|
||||||
|
self.wait_until(lambda: len(full_node.getpeerinfo()) == 0)
|
||||||
|
|
||||||
|
# Mine blocks and sync the pruned node. Surpass the NETWORK_NODE_LIMITED threshold.
|
||||||
|
# Blocks deeper than the threshold are considered "historical blocks"
|
||||||
|
num_historial_blocks = 12
|
||||||
|
self.generate(miner, NODE_NETWORK_LIMITED_MIN_BLOCKS + num_historial_blocks, sync_fun=self.no_op)
|
||||||
|
self.sync_blocks([miner, pruned_node])
|
||||||
|
|
||||||
|
# Connect full_node to prune_node and check peers don't disconnect right away.
|
||||||
|
# (they will disconnect if full_node, which is chain-wise behind, request blocks
|
||||||
|
# older than NODE_NETWORK_LIMITED_MIN_BLOCKS)
|
||||||
|
start_height_full_node = full_node.getblockcount()
|
||||||
|
full_node.setnetworkactive(True)
|
||||||
|
self.connect_nodes(2, 0)
|
||||||
|
assert_equal(len(full_node.getpeerinfo()), 1)
|
||||||
|
|
||||||
|
# Wait until the full_node is headers-wise sync
|
||||||
|
best_block_hash = pruned_node.getbestblockhash()
|
||||||
|
self.wait_until(lambda: next(filter(lambda x: x['hash'] == best_block_hash, full_node.getchaintips()))['status'] == "headers-only")
|
||||||
|
|
||||||
|
# Now, since the node aims to download a window of 1024 blocks,
|
||||||
|
# ensure it requests the blocks below the threshold only (with a
|
||||||
|
# 2-block buffer). And also, ensure it does not request any
|
||||||
|
# historical block.
|
||||||
|
tip_height = pruned_node.getblockcount()
|
||||||
|
limit_buffer = 2
|
||||||
|
# Prevent races by waiting for the tip to arrive first
|
||||||
|
self.wait_until(lambda: not try_rpc(-1, "Block not found", full_node.getblock, pruned_node.getbestblockhash()))
|
||||||
|
for height in range(start_height_full_node + 1, tip_height + 1):
|
||||||
|
if height <= tip_height - (NODE_NETWORK_LIMITED_MIN_BLOCKS - limit_buffer):
|
||||||
|
assert_raises_rpc_error(-1, "Block not found on disk", full_node.getblock, pruned_node.getblockhash(height))
|
||||||
|
else:
|
||||||
|
full_node.getblock(pruned_node.getblockhash(height)) # just assert it does not throw an exception
|
||||||
|
|
||||||
|
# Lastly, ensure the full_node is not sync and verify it can get synced by
|
||||||
|
# establishing a connection with another full node capable of providing them.
|
||||||
|
assert_equal(full_node.getblockcount(), start_height_full_node)
|
||||||
|
self.connect_nodes(2, 1)
|
||||||
|
self.sync_blocks([miner, full_node])
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
|
node = self.nodes[0].add_p2p_connection(P2PIgnoreInv())
|
||||||
|
|
||||||
@ -118,5 +179,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework):
|
|||||||
# sync must be possible, node 1 is no longer in IBD and should therefore connect to node 0 (NODE_NETWORK_LIMITED)
|
# sync must be possible, node 1 is no longer in IBD and should therefore connect to node 0 (NODE_NETWORK_LIMITED)
|
||||||
self.sync_blocks([self.nodes[0], self.nodes[1]])
|
self.sync_blocks([self.nodes[0], self.nodes[1]])
|
||||||
|
|
||||||
|
self.test_avoid_requesting_historical_blocks()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
NodeNetworkLimitedTest().main()
|
NodeNetworkLimitedTest().main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user