Skip to content

Commit 4f27e8c

Browse files
committed
Merge bitcoin/bitcoin#33083: qa: test that we do not disconnect a peer for submitting an invalid compact block
c157438 qa: test that we do disconnect upon a second invalid compact block being announced (Antoine Poinsot) fb2dcbb qa: test cached failure for compact block (Antoine Poinsot) f12d8b1 qa: test a compact block with an invalid transaction (Antoine Poinsot) d6c37b2 qa: remove unnecessary tx removal from compact block (Antoine Poinsot) Pull request description: In thinking about bitcoin/bitcoin#33050 and bitcoin/bitcoin#33012 (comment), i went through the code paths for peer disconnection upon submitting an invalid block. It turns out that the fact we exempt a peer from disconnection upon submitting an invalid compact block was not properly tested, as can be checked with these diffs: ```diff diff --git a/src/net_processing.cpp b/src/net_processing.cpp index https://github.com/bitcoin/bitcoin/commit/0c4a89c44cb6e9a61fdd486d576781e5b66c618c..d243fb88d4b 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1805,10 +1805,10 @@ void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati // The node is providing invalid data: case BlockValidationResult::BLOCK_CONSENSUS: case BlockValidationResult::BLOCK_MUTATED: - if (!via_compact_block) { + //if (!via_compact_block) { if (peer) Misbehaving(*peer, message); return; - } + //} break; case BlockValidationResult::BLOCK_CACHED_INVALID: { ``` ```diff diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0c4a89c..e8e0c805367 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1814,10 +1814,10 @@ void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati { // Discourage outbound (but not inbound) peers if on an invalid chain. // Exempt HB compact block peers. Manual connections are always protected from discouragement. - if (peer && !via_compact_block && !peer->m_is_inbound) { + //if (peer && !via_compact_block && !peer->m_is_inbound) { if (peer) Misbehaving(*peer, message); return; - } + //} break; } case BlockValidationResult::BLOCK_INVALID_HEADER: ``` We do have a test for this, but it actually uses a coinbase witness commitment error, which is checked much earlier in `FillBlock`. This PR adds coverage for the two exemptions in `MaybePunishNodeForBlock`. ACKs for top commit: kevkevinpal: ACK [c157438](bitcoin/bitcoin@c157438) nervana21: tACK [c157438](bitcoin/bitcoin@c157438) instagibbs: crACK c157438 stratospher: ACK c157438. Tree-SHA512: a77d5a9768c0d73f122b06db2e416e80d0b3c3fd261dae8e340ecec2ae92d947d31988894bc732cb6dad2e338b3c82f33e75eb3280f8b0933b285657cf3b212c
2 parents bfc9d95 + c157438 commit 4f27e8c

File tree

1 file changed

+35
-1
lines changed

1 file changed

+35
-1
lines changed

test/functional/p2p_compactblocks.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
CScript,
5555
OP_DROP,
5656
OP_TRUE,
57+
OP_RETURN,
5758
)
5859
from test_framework.test_framework import BitcoinTestFramework
5960
from test_framework.util import (
@@ -709,7 +710,6 @@ def test_invalid_tx_in_compactblock(self, test_node):
709710
utxo = self.utxos[0]
710711

711712
block = self.build_block_with_transactions(node, utxo, 5)
712-
del block.vtx[3]
713713
block.hashMerkleRoot = block.calc_merkle_root()
714714
# Drop the coinbase witness but include the witness commitment.
715715
add_witness_commitment(block)
@@ -727,6 +727,37 @@ def test_invalid_tx_in_compactblock(self, test_node):
727727
assert_not_equal(node.getbestblockhash(), block.hash_hex)
728728
test_node.sync_with_ping()
729729

730+
# Re-establish a proper witness commitment with the coinbase witness, but
731+
# invalidate the last tx in the block.
732+
block.vtx[4].vin[0].scriptSig = CScript([OP_RETURN])
733+
block.hashMerkleRoot = block.calc_merkle_root()
734+
add_witness_commitment(block)
735+
block.solve()
736+
737+
# This will lead to a consensus failure for which we also won't be disconnected but which
738+
# will be cached.
739+
comp_block.initialize_from_block(block, prefill_list=list(range(len(block.vtx))), use_witness=True)
740+
msg = msg_cmpctblock(comp_block.to_p2p())
741+
test_node.send_and_ping(msg)
742+
743+
# The tip still didn't advance.
744+
assert_not_equal(node.getbestblockhash(), block.hash_hex)
745+
test_node.sync_with_ping()
746+
747+
# The failure above was cached. Submitting the compact block again will returned a cached
748+
# consensus error (the code path is different) and still not get us disconnected (nor
749+
# advance the tip).
750+
test_node.send_and_ping(msg)
751+
assert_not_equal(node.getbestblockhash(), block.hash_hex)
752+
test_node.sync_with_ping()
753+
754+
# Now, announcing a second block building on top of the invalid one will get us disconnected.
755+
block.hashPrevBlock = block.hash_int
756+
block.solve()
757+
comp_block.initialize_from_block(block, prefill_list=list(range(len(block.vtx))), use_witness=True)
758+
msg = msg_cmpctblock(comp_block.to_p2p())
759+
test_node.send_await_disconnect(msg)
760+
730761
# Helper for enabling cb announcements
731762
# Send the sendcmpct request and sync headers
732763
def request_cb_announcements(self, peer):
@@ -943,6 +974,9 @@ def run_test(self):
943974
self.log.info("Testing handling of invalid compact blocks...")
944975
self.test_invalid_tx_in_compactblock(self.segwit_node)
945976

977+
# The previous test will lead to a disconnection. Reconnect before continuing.
978+
self.segwit_node = self.nodes[0].add_p2p_connection(TestP2PConn())
979+
946980
self.log.info("Testing invalid index in cmpctblock message...")
947981
self.test_invalid_cmpctblock_message()
948982

0 commit comments

Comments
 (0)