aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
authorfanquake <fanquake@gmail.com>2023-07-04 11:39:19 +0100
committerfanquake <fanquake@gmail.com>2023-07-04 12:00:54 +0100
commit8825983716abbc4d9125c0ee44cf4a0a470a1a27 (patch)
tree860ce2fd48459b455798981b6cb31d3e42fee785 /test/functional
parent642b5dd1b4fc5788ec7ab162a7c6ce0b96e7a6e4 (diff)
parentb8ad3220a9068f10c2b3b14b40f211372aeece31 (diff)
Merge bitcoin/bitcoin#27752: [25.x] Parallel compact block downloads
b8ad3220a9068f10c2b3b14b40f211372aeece31 Unconditionally return when compact block status == READ_STATUS_FAILED (Greg Sanders) cdd3de08e301ec309c179796bedfa2be29042128 Add tests for parallel compact block downloads (Greg Sanders) e66a5cbb56db3dffc119e110472ab1176ea3fe99 Support up to 3 parallel compact block txn fetchings (Greg Sanders) d1a93f5d41f7385af28cee3863976fd75f27415b Only request full blocks from the peer we thought had the block in-flight (Greg Sanders) 38e3af9fad1eb8ef7d6a9d812ded412668b650e3 Convert mapBlocksInFlight to a multimap (Greg Sanders) a45159b8e2a198219d7c46baeb647ff5d18436bf Remove nBlocksInFlight (Greg Sanders) 722361e129342078376b6d30b9d80de17ca7ddfb alias BlockDownloadMap for mapBlocksInFlight (Greg Sanders) Pull request description: Backports: * https://github.com/bitcoin/bitcoin/pull/27626 * https://github.com/bitcoin/bitcoin/pull/27743 ACKs for top commit: instagibbs: utACK https://github.com/bitcoin/bitcoin/pull/27752/commits/b8ad3220a9068f10c2b3b14b40f211372aeece31 ajtowns: ACK b8ad3220a9068f10c2b3b14b40f211372aeece31 ; confirmed patches are clean cherry-picks from master, and already tested patches prior to 25.0 release Tree-SHA512: 438901496a5ed927662e62f936e3d1e7ffb727cb235869854983e8e29a68e144eb3bff307d9fc3ae785fb276b67a216b1cce397689252ca49c5d761efc1380ac
Diffstat (limited to 'test/functional')
-rwxr-xr-xtest/functional/p2p_compactblocks.py88
1 files changed, 85 insertions, 3 deletions
diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py
index 23eeea50bc..d6c06fdeed 100755
--- a/test/functional/p2p_compactblocks.py
+++ b/test/functional/p2p_compactblocks.py
@@ -105,6 +105,10 @@ class TestP2PConn(P2PInterface):
self.last_message.pop("headers", None)
self.last_message.pop("cmpctblock", None)
+ def clear_getblocktxn(self):
+ with p2p_lock:
+ self.last_message.pop("getblocktxn", None)
+
def get_headers(self, locator, hashstop):
msg = msg_getheaders()
msg.locator.vHave = locator
@@ -745,7 +749,7 @@ class CompactBlocksTest(BitcoinTestFramework):
peer.get_headers(locator=[int(tip, 16)], hashstop=0)
peer.send_and_ping(msg_sendcmpct(announce=True, version=2))
- def test_compactblock_reconstruction_multiple_peers(self, stalling_peer, delivery_peer):
+ def test_compactblock_reconstruction_stalling_peer(self, stalling_peer, delivery_peer):
node = self.nodes[0]
assert len(self.utxos)
@@ -823,12 +827,85 @@ class CompactBlocksTest(BitcoinTestFramework):
hb_test_node.send_and_ping(msg_sendcmpct(announce=False, version=2))
assert_highbandwidth_states(self.nodes[0], hb_to=True, hb_from=False)
+ def test_compactblock_reconstruction_parallel_reconstruction(self, stalling_peer, delivery_peer, inbound_peer, outbound_peer):
+ """ All p2p connections are inbound except outbound_peer. We test that ultimate parallel slot
+ can only be taken by an outbound node unless prior attempts were done by an outbound
+ """
+ node = self.nodes[0]
+ assert len(self.utxos)
+
+ def announce_cmpct_block(node, peer, txn_count):
+ utxo = self.utxos.pop(0)
+ block = self.build_block_with_transactions(node, utxo, txn_count)
+
+ cmpct_block = HeaderAndShortIDs()
+ cmpct_block.initialize_from_block(block)
+ msg = msg_cmpctblock(cmpct_block.to_p2p())
+ peer.send_and_ping(msg)
+ with p2p_lock:
+ assert "getblocktxn" in peer.last_message
+ return block, cmpct_block
+
+ for name, peer in [("delivery", delivery_peer), ("inbound", inbound_peer), ("outbound", outbound_peer)]:
+ self.log.info(f"Setting {name} as high bandwidth peer")
+ block, cmpct_block = announce_cmpct_block(node, peer, 1)
+ msg = msg_blocktxn()
+ msg.block_transactions.blockhash = block.sha256
+ msg.block_transactions.transactions = block.vtx[1:]
+ peer.send_and_ping(msg)
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+ peer.clear_getblocktxn()
+
+ # Test the simple parallel download case...
+ for num_missing in [1, 5, 20]:
+
+ # Remaining low-bandwidth peer is stalling_peer, who announces first
+ assert_equal([peer['bip152_hb_to'] for peer in node.getpeerinfo()], [False, True, True, True])
+
+ block, cmpct_block = announce_cmpct_block(node, stalling_peer, num_missing)
+
+ delivery_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ with p2p_lock:
+ # The second peer to announce should still get a getblocktxn
+ assert "getblocktxn" in delivery_peer.last_message
+ assert int(node.getbestblockhash(), 16) != block.sha256
+
+ inbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ with p2p_lock:
+ # The third inbound peer to announce should *not* get a getblocktxn
+ assert "getblocktxn" not in inbound_peer.last_message
+ assert int(node.getbestblockhash(), 16) != block.sha256
+
+ outbound_peer.send_and_ping(msg_cmpctblock(cmpct_block.to_p2p()))
+ with p2p_lock:
+ # The third peer to announce should get a getblocktxn if outbound
+ assert "getblocktxn" in outbound_peer.last_message
+ assert int(node.getbestblockhash(), 16) != block.sha256
+
+ # Second peer completes the compact block first
+ msg = msg_blocktxn()
+ msg.block_transactions.blockhash = block.sha256
+ msg.block_transactions.transactions = block.vtx[1:]
+ delivery_peer.send_and_ping(msg)
+ assert_equal(int(node.getbestblockhash(), 16), block.sha256)
+
+ # Nothing bad should happen if we get a late fill from the first peer...
+ stalling_peer.send_and_ping(msg)
+ self.utxos.append([block.vtx[-1].sha256, 0, block.vtx[-1].vout[0].nValue])
+
+ delivery_peer.clear_getblocktxn()
+ inbound_peer.clear_getblocktxn()
+ outbound_peer.clear_getblocktxn()
+
+
def run_test(self):
self.wallet = MiniWallet(self.nodes[0])
# Setup the p2p connections
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
self.additional_segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
+ self.onemore_inbound_node = self.nodes[0].add_p2p_connection(TestP2PConn())
+ self.outbound_node = self.nodes[0].add_outbound_p2p_connection(TestP2PConn(), p2p_idx=3, connection_type="outbound-full-relay")
# We will need UTXOs to construct transactions in later tests.
self.make_utxos()
@@ -838,6 +915,8 @@ class CompactBlocksTest(BitcoinTestFramework):
self.log.info("Testing SENDCMPCT p2p message... ")
self.test_sendcmpct(self.segwit_node)
self.test_sendcmpct(self.additional_segwit_node)
+ self.test_sendcmpct(self.onemore_inbound_node)
+ self.test_sendcmpct(self.outbound_node)
self.log.info("Testing compactblock construction...")
self.test_compactblock_construction(self.segwit_node)
@@ -860,8 +939,11 @@ class CompactBlocksTest(BitcoinTestFramework):
self.log.info("Testing handling of incorrect blocktxn responses...")
self.test_incorrect_blocktxn_response(self.segwit_node)
- self.log.info("Testing reconstructing compact blocks from all peers...")
- self.test_compactblock_reconstruction_multiple_peers(self.segwit_node, self.additional_segwit_node)
+ self.log.info("Testing reconstructing compact blocks with a stalling peer...")
+ self.test_compactblock_reconstruction_stalling_peer(self.segwit_node, self.additional_segwit_node)
+
+ self.log.info("Testing reconstructing compact blocks from multiple peers...")
+ self.test_compactblock_reconstruction_parallel_reconstruction(stalling_peer=self.segwit_node, inbound_peer=self.onemore_inbound_node, delivery_peer=self.additional_segwit_node, outbound_peer=self.outbound_node)
# Test that if we submitblock to node1, we'll get a compact block
# announcement to all peers.