aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2023-02-14 18:38:31 -0500
committerAndrew Chow <github@achow101.com>2023-02-14 18:45:35 -0500
commit576e16e7026fe1e2bed8907b38c7372e8353508d (patch)
tree47ce3f7a5d1ecaf4b18d202bc31e7a0b6786e035 /test
parentfb2f0934799a4e84b9d89fd58d594435358b4366 (diff)
parent772671245d50d94fd5087deb2542854604eba174 (diff)
Merge bitcoin/bitcoin#26184: test: p2p: check that headers message with invalid proof-of-work disconnects peer
772671245d50d94fd5087deb2542854604eba174 test: p2p: check that headers message with invalid proof-of-work disconnects peer (Sebastian Falbesoner) Pull request description: One of the earliest anti-DoS checks done after receiving and deserializing a `headers` message from a peer is verifying whether the proof-of-work is valid (called in method `PeerManagerImpl::ProcessHeadersMessage`): https://github.com/bitcoin/bitcoin/blob/f227e153e80c8c50c30d76e1ac638d7206c7ff61/src/net_processing.cpp#L2752-L2762 The called method `PeerManagerImpl::CheckHeadersPoW` calls `Misbehaving` with a score of 100, i.e. leading to an immediate disconnect of the peer: https://github.com/bitcoin/bitcoin/blob/f227e153e80c8c50c30d76e1ac638d7206c7ff61/src/net_processing.cpp#L2368-L2372 This PR adds a simple test for both the misbehaving log and the resulting disconnect. For creating a block header with invalid proof-of-work, we first create one that is accepted by the node (the difficulty field `nBits` is copied from the genesis block) and based on that the nonce is modified until we have block header hash prefix that is too high to fulfill even the minimum difficulty. ACKs for top commit: Sjors: ACK 772671245d50d94fd5087deb2542854604eba174 achow101: ACK 772671245d50d94fd5087deb2542854604eba174 brunoerg: crACK 772671245d50d94fd5087deb2542854604eba174 furszy: Code review ACK 77267124 with a non-blocking speedup. Tree-SHA512: 680aa7939158d1dc672b90aa6554ba2b3a92584b6d3bcb0227776035858429feb8bc66eed18b47de0fe56df7d9b3ddaee231aaeaa360136603b9ad4b19e6ac11
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/p2p_invalid_messages.py34
1 files changed, 33 insertions, 1 deletions
diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py
index 3109ad2b56..ea4999a965 100755
--- a/test/functional/p2p_invalid_messages.py
+++ b/test/functional/p2p_invalid_messages.py
@@ -13,11 +13,12 @@ from test_framework.messages import (
MAX_HEADERS_RESULTS,
MAX_INV_SIZE,
MAX_PROTOCOL_MESSAGE_LENGTH,
+ MSG_TX,
+ from_hex,
msg_getdata,
msg_headers,
msg_inv,
msg_ping,
- MSG_TX,
msg_version,
ser_string,
)
@@ -73,6 +74,7 @@ class InvalidMessagesTest(BitcoinTestFramework):
self.test_oversized_inv_msg()
self.test_oversized_getdata_msg()
self.test_oversized_headers_msg()
+ self.test_invalid_pow_headers_msg()
self.test_resource_exhaustion()
def test_buffer(self):
@@ -248,6 +250,36 @@ class InvalidMessagesTest(BitcoinTestFramework):
size = MAX_HEADERS_RESULTS + 1
self.test_oversized_msg(msg_headers([CBlockHeader()] * size), size)
+ def test_invalid_pow_headers_msg(self):
+ self.log.info("Test headers message with invalid proof-of-work is logged as misbehaving and disconnects peer")
+ blockheader_tip_hash = self.nodes[0].getbestblockhash()
+ blockheader_tip = from_hex(CBlockHeader(), self.nodes[0].getblockheader(blockheader_tip_hash, False))
+
+ # send valid headers message first
+ assert_equal(self.nodes[0].getblockchaininfo()['headers'], 0)
+ blockheader = CBlockHeader()
+ blockheader.hashPrevBlock = int(blockheader_tip_hash, 16)
+ blockheader.nTime = int(time.time())
+ blockheader.nBits = blockheader_tip.nBits
+ blockheader.rehash()
+ while not blockheader.hash.startswith('0'):
+ blockheader.nNonce += 1
+ blockheader.rehash()
+ peer = self.nodes[0].add_p2p_connection(P2PInterface())
+ peer.send_and_ping(msg_headers([blockheader]))
+ assert_equal(self.nodes[0].getblockchaininfo()['headers'], 1)
+ chaintips = self.nodes[0].getchaintips()
+ assert_equal(chaintips[0]['status'], 'headers-only')
+ assert_equal(chaintips[0]['hash'], blockheader.hash)
+
+ # invalidate PoW
+ while not blockheader.hash.startswith('f'):
+ blockheader.nNonce += 1
+ blockheader.rehash()
+ with self.nodes[0].assert_debug_log(['Misbehaving', 'header with invalid proof of work']):
+ peer.send_message(msg_headers([blockheader]))
+ peer.wait_for_disconnect()
+
def test_resource_exhaustion(self):
self.log.info("Test node stays up despite many large junk messages")
conn = self.nodes[0].add_p2p_connection(P2PDataStore())