test: make notfound_on_unannounced more reliable
What changed, and why it matters
This commit only changes a single test file. It makes an existing functional test more reliable by using mock time instead of looping up to 100 times and hoping for the right timing. There is no change to the actual Bitcoin Core node software, so it cannot affect real users, wallets, or network behavior.
No security action needed. Treat as a normal test improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch modifies test/functional/p2p_leak_tx.py. The old test looped up to 100 repeats, sending a self-transfer and a getdata request, trying to catch either a notfound response or an inv announcement. The new version freezes mocktime so the node never announces the transaction, asserts a notfound response, then advances mocktime by 120 seconds, waits for the inv announcement, and finally asserts the tx is delivered. This is purely a test reliability refactor.
Changed components
test/functional/p2p_leak_tx.pyInspect captured patch +25 / −21
diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py
index e09420ba..c347f597 100755
--- a/test/functional/p2p_leak_tx.py
+++ b/test/functional/p2p_leak_tx.py
@@ -102,27 +102,31 @@ class P2PLeakTxTest(BitcoinTestFramework):
self.gen_node.disconnect_p2ps()
inbound_peer = self.gen_node.add_p2p_connection(P2PNode()) # An "attacking" inbound peer
- MAX_REPEATS = 100
- self.log.info("Running test up to {} times.".format(MAX_REPEATS))
- for i in range(MAX_REPEATS):
- self.log.info('Run repeat {}'.format(i + 1))
- wtxid = self.miniwallet.send_self_transfer(from_node=self.gen_node)["wtxid"]
-
- want_tx = msg_getdata()
- want_tx.inv.append(CInv(t=MSG_WTX, h=int(wtxid, 16)))
- with p2p_lock:
- inbound_peer.last_message.pop('notfound', None)
- inbound_peer.send_and_ping(want_tx)
- if inbound_peer.last_message.get('notfound'):
- self.log.debug('tx {} was not yet announced to us.'.format(wtxid))
- self.log.debug("node has responded with a notfound message. End test.")
- assert_equal(inbound_peer.last_message['notfound'].vec[0].hash, int(wtxid, 16))
- with p2p_lock:
- inbound_peer.last_message.pop('notfound')
- break
- else:
- self.log.debug('tx {} was already announced to us. Try test again.'.format(wtxid))
- assert int(wtxid, 16) in [inv.hash for inv in inbound_peer.last_message['inv'].inv]
+ # Set a mock time so that time does not pass, and gen_node never announces the transaction
+ self.gen_node.setmocktime(self.mocktime)
+ wtxid = int(self.miniwallet.send_self_transfer(from_node=self.gen_node)["wtxid"], 16)
+
+ want_tx = msg_getdata()
+ want_tx.inv.append(CInv(t=MSG_WTX, h=wtxid))
+ with p2p_lock:
+ inbound_peer.last_message.pop('notfound', None)
+ inbound_peer.send_and_ping(want_tx)
+ inbound_peer.wait_until(lambda: "notfound" in inbound_peer.last_message)
+ with p2p_lock:
+ assert_equal(inbound_peer.last_message.get("notfound").vec[0].hash, wtxid)
+ inbound_peer.last_message.pop('notfound')
+
+ # Move mocktime forward and wait for the announcement.
+ inbound_peer.last_message.pop('inv', None)
+ self.mocktime += 120
+ self.gen_node.setmocktime(self.mocktime)
+ inbound_peer.wait_for_inv([CInv(t=MSG_WTX, h=wtxid)], timeout=120)
+
+ # Send the getdata again, this time the node should send us a TX message.
+ inbound_peer.last_message.pop('tx', None)
+ inbound_peer.send_and_ping(want_tx)
+ self.wait_until(lambda: "tx" in inbound_peer.last_message)
+ assert_equal(wtxid, int(inbound_peer.last_message["tx"].tx.wtxid_hex, 16))
if __name__ == '__main__':
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.