aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2021-10-01 08:15:34 +0200
committerMarcoFalke <falke.marco@gmail.com>2021-10-01 08:16:54 +0200
commit4e1de1fc59057c5f6fe15a02acd922e158e91292 (patch)
treebea8b829ef09eed1763fb8e2b2408eb14f24d7ca /test
parent33b0696d3106646d5251ceebbeaee53bc8765e3a (diff)
parent18c5b23a0f7adf9a08bcaa967ed800badf62d90a (diff)
downloadbitcoin-4e1de1fc59057c5f6fe15a02acd922e158e91292.tar.xz
Merge bitcoin/bitcoin#22340: p2p: Use legacy relaying to download blocks in blocks-only mode
18c5b23a0f7adf9a08bcaa967ed800badf62d90a [test] Test that -blocksonly nodes still serve compact blocks. (Niklas Gögge) a79ad65fc2c31a2b1132a6aab389d0197a95c395 [test] Test that getdata(CMPCT) is still sent on regular low bandwidth connections. (Niklas Gögge) 5e231c116ba8165e9d8c795b85ca2833238aed54 [test] Test that -blocksonly nodes do not send getdata(CMPCT) on a low bandwidth connection. (Niklas Gögge) 5bf658745782eb571215d6c1e5fe3c655edb55b3 [test] Test that -blocksonly nodes do not request high bandwidth mode. (Niklas Gögge) 0dc8bf5b925ca876c0b1a100e426056d741aafde [net processing] Dont request compact blocks in blocks-only mode (Niklas Gögge) Pull request description: A blocks-only node does not participate in transaction relay to reduce its own bandwidth usage and therefore does not have a mempool. The use of compact blocks is not beneficial to such a node since it will always have to download full blocks. In both high- and low-bandwidth relaying the `cmpctblock` message is sent. This represent a bandwidth overhead for blocks-only nodes because the `cmpctblock` message is several times larger in the average case than the equivalent `headers` or `inv` announcement. ![compact blocks](https://raw.githubusercontent.com/bitcoin/bips/master/bip-0152/protocol-flow.png) >**Example:** >A block with 2000 txs results in a `cmpctblock` with 2000*6 bytes in short ids. This is several times larger than the equivalent 82 bytes for a `headers` message or 37 bytes for an `inv`. ## Approach This PR makes blocks-only nodes always use the legacy relaying to download new blocks. It does so by making blocks-only nodes never initiate a high-bandwidth block relay connection by disabling the sending of `sendcmpct(1)`. Additionally a blocks-only node will never request a compact block using `getdata(CMPCT)`. A blocks-only node will continue to serve compact blocks to its peers in both high- and low-bandwidth mode. ACKs for top commit: naumenkogs: ACK 18c5b23a0f7adf9a08bcaa967ed800badf62d90a rajarshimaitra: tACK https://github.com/bitcoin/bitcoin/pull/22340/commits/18c5b23a0f7adf9a08bcaa967ed800badf62d90a jnewbery: reACK 18c5b23a0f theStack: re-ACK 18c5b23a0f7adf9a08bcaa967ed800badf62d90a 🥛 Tree-SHA512: 0c78804aa397513d41f97fe314efb815efcd852d452dd903df9d4749280cd3faaa010fa9b51d7d5168b8a77e08c8ab0a491ecdbdb3202f2e9cd5137cddc74624
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/p2p_compactblocks_blocksonly.py130
-rwxr-xr-xtest/functional/test_runner.py1
2 files changed, 131 insertions, 0 deletions
diff --git a/test/functional/p2p_compactblocks_blocksonly.py b/test/functional/p2p_compactblocks_blocksonly.py
new file mode 100755
index 0000000000..4073ec03a6
--- /dev/null
+++ b/test/functional/p2p_compactblocks_blocksonly.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+# Copyright (c) 2021-2021 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 that a node in blocksonly mode does not request compact blocks."""
+
+from test_framework.messages import (
+ MSG_BLOCK,
+ MSG_CMPCT_BLOCK,
+ MSG_WITNESS_FLAG,
+ CBlock,
+ CBlockHeader,
+ CInv,
+ from_hex,
+ msg_block,
+ msg_getdata,
+ msg_headers,
+ msg_sendcmpct,
+)
+from test_framework.p2p import P2PInterface
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+
+class P2PCompactBlocksBlocksOnly(BitcoinTestFramework):
+ def set_test_params(self):
+ self.extra_args = [["-blocksonly"], [], [], []]
+ self.num_nodes = 4
+
+ def setup_network(self):
+ self.setup_nodes()
+ # Start network with everyone disconnected
+ self.sync_all()
+
+ def build_block_on_tip(self):
+ blockhash = self.nodes[2].generate(1)[0]
+ block_hex = self.nodes[2].getblock(blockhash=blockhash, verbosity=0)
+ block = from_hex(CBlock(), block_hex)
+ block.rehash()
+ return block
+
+ def run_test(self):
+ # Nodes will only request hb compact blocks mode when they're out of IBD
+ for node in self.nodes:
+ assert not node.getblockchaininfo()['initialblockdownload']
+
+ p2p_conn_blocksonly = self.nodes[0].add_p2p_connection(P2PInterface())
+ p2p_conn_high_bw = self.nodes[1].add_p2p_connection(P2PInterface())
+ p2p_conn_low_bw = self.nodes[3].add_p2p_connection(P2PInterface())
+ for conn in [p2p_conn_blocksonly, p2p_conn_high_bw, p2p_conn_low_bw]:
+ assert_equal(conn.message_count['sendcmpct'], 2)
+ conn.send_and_ping(msg_sendcmpct(announce=False, version=2))
+
+ # Nodes:
+ # 0 -> blocksonly
+ # 1 -> high bandwidth
+ # 2 -> miner
+ # 3 -> low bandwidth
+ #
+ # Topology:
+ # p2p_conn_blocksonly ---> node0
+ # p2p_conn_high_bw ---> node1
+ # p2p_conn_low_bw ---> node3
+ # node2 (no connections)
+ #
+ # node2 produces blocks that are passed to the rest of the nodes
+ # through the respective p2p connections.
+
+ self.log.info("Test that -blocksonly nodes do not select peers for BIP152 high bandwidth mode")
+
+ block0 = self.build_block_on_tip()
+
+ # A -blocksonly node should not request BIP152 high bandwidth mode upon
+ # receiving a new valid block at the tip.
+ p2p_conn_blocksonly.send_and_ping(msg_block(block0))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), block0.sha256)
+ assert_equal(p2p_conn_blocksonly.message_count['sendcmpct'], 2)
+ assert_equal(p2p_conn_blocksonly.last_message['sendcmpct'].announce, False)
+
+ # A normal node participating in transaction relay should request BIP152
+ # high bandwidth mode upon receiving a new valid block at the tip.
+ p2p_conn_high_bw.send_and_ping(msg_block(block0))
+ assert_equal(int(self.nodes[1].getbestblockhash(), 16), block0.sha256)
+ p2p_conn_high_bw.wait_until(lambda: p2p_conn_high_bw.message_count['sendcmpct'] == 3)
+ assert_equal(p2p_conn_high_bw.last_message['sendcmpct'].announce, True)
+
+ # Don't send a block from the p2p_conn_low_bw so the low bandwidth node
+ # doesn't select it for BIP152 high bandwidth relay.
+ self.nodes[3].submitblock(block0.serialize().hex())
+
+ self.log.info("Test that -blocksonly nodes send getdata(BLOCK) instead"
+ " of getdata(CMPCT) in BIP152 low bandwidth mode")
+
+ block1 = self.build_block_on_tip()
+
+ p2p_conn_blocksonly.send_message(msg_headers(headers=[CBlockHeader(block1)]))
+ p2p_conn_blocksonly.sync_send_with_ping()
+ assert_equal(p2p_conn_blocksonly.last_message['getdata'].inv, [CInv(MSG_BLOCK | MSG_WITNESS_FLAG, block1.sha256)])
+
+ p2p_conn_high_bw.send_message(msg_headers(headers=[CBlockHeader(block1)]))
+ p2p_conn_high_bw.sync_send_with_ping()
+ assert_equal(p2p_conn_high_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.sha256)])
+
+ self.log.info("Test that getdata(CMPCT) is still sent on BIP152 low bandwidth connections"
+ " when no -blocksonly nodes are involved")
+
+ p2p_conn_low_bw.send_and_ping(msg_headers(headers=[CBlockHeader(block1)]))
+ p2p_conn_low_bw.sync_with_ping()
+ assert_equal(p2p_conn_low_bw.last_message['getdata'].inv, [CInv(MSG_CMPCT_BLOCK, block1.sha256)])
+
+ self.log.info("Test that -blocksonly nodes still serve compact blocks")
+
+ def test_for_cmpctblock(block):
+ if 'cmpctblock' not in p2p_conn_blocksonly.last_message:
+ return False
+ return p2p_conn_blocksonly.last_message['cmpctblock'].header_and_shortids.header.rehash() == block.sha256
+
+ p2p_conn_blocksonly.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, block0.sha256)]))
+ p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block0))
+
+ # Request BIP152 high bandwidth mode from the -blocksonly node.
+ p2p_conn_blocksonly.send_and_ping(msg_sendcmpct(announce=True, version=2))
+
+ block2 = self.build_block_on_tip()
+ self.nodes[0].submitblock(block1.serialize().hex())
+ self.nodes[0].submitblock(block2.serialize().hex())
+ p2p_conn_blocksonly.wait_until(lambda: test_for_cmpctblock(block2))
+
+if __name__ == '__main__':
+ P2PCompactBlocksBlocksOnly().main()
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 2c2aaf6020..bb84962b75 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -98,6 +98,7 @@ BASE_SCRIPTS = [
'rpc_fundrawtransaction.py --legacy-wallet',
'rpc_fundrawtransaction.py --descriptors',
'p2p_compactblocks.py',
+ 'p2p_compactblocks_blocksonly.py',
'feature_segwit.py --legacy-wallet',
# vv Tests less than 2m vv
'wallet_basic.py --legacy-wallet',