Skip to content

Commit 8d8099e

Browse files
fjahrajtowns
authored andcommitted
test: Add tests for wtxid tx relay in segwit test
Also cleans up some doublicate lines in the rest of the test. co-authored-by: Anthony Towns <[email protected]>
1 parent 9a5392f commit 8d8099e

File tree

1 file changed

+95
-7
lines changed

1 file changed

+95
-7
lines changed

test/functional/p2p_segwit.py

Lines changed: 95 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
MSG_BLOCK,
2626
MSG_TX,
2727
MSG_WITNESS_FLAG,
28+
MSG_WTX,
2829
NODE_NETWORK,
2930
NODE_WITNESS,
3031
msg_no_witness_block,
@@ -34,6 +35,8 @@
3435
msg_tx,
3536
msg_block,
3637
msg_no_witness_tx,
38+
msg_verack,
39+
msg_wtxidrelay,
3740
ser_uint256,
3841
ser_vector,
3942
sha256,
@@ -81,6 +84,7 @@
8184
softfork_active,
8285
hex_str_to_bytes,
8386
assert_raises_rpc_error,
87+
wait_until,
8488
)
8589

8690
# The versionbit bit used to signal activation of SegWit
@@ -143,25 +147,45 @@ def test_witness_block(node, p2p, block, accepted, with_witness=True, reason=Non
143147

144148

145149
class TestP2PConn(P2PInterface):
146-
def __init__(self):
150+
def __init__(self, wtxidrelay=False):
147151
super().__init__()
148152
self.getdataset = set()
153+
self.last_wtxidrelay = []
154+
self.lastgetdata = []
155+
self.wtxidrelay = wtxidrelay
149156

150157
# Avoid sending out msg_getdata in the mininode thread as a reply to invs.
151158
# They are not needed and would only lead to races because we send msg_getdata out in the test thread
152159
def on_inv(self, message):
153160
pass
154161

162+
def on_version(self, message):
163+
if self.wtxidrelay:
164+
self.send_message(msg_wtxidrelay())
165+
super().on_version(message)
166+
155167
def on_getdata(self, message):
168+
self.lastgetdata = message.inv
156169
for inv in message.inv:
157170
self.getdataset.add(inv.hash)
158171

159-
def announce_tx_and_wait_for_getdata(self, tx, timeout=60, success=True):
172+
def on_wtxidrelay(self, message):
173+
self.last_wtxidrelay.append(message)
174+
175+
def announce_tx_and_wait_for_getdata(self, tx, timeout=60, success=True, use_wtxid=False):
160176
with mininode_lock:
161177
self.last_message.pop("getdata", None)
162-
self.send_message(msg_inv(inv=[CInv(MSG_TX, tx.sha256)]))
178+
if use_wtxid:
179+
wtxid = tx.calc_sha256(True)
180+
self.send_message(msg_inv(inv=[CInv(MSG_WTX, wtxid)]))
181+
else:
182+
self.send_message(msg_inv(inv=[CInv(MSG_TX, tx.sha256)]))
183+
163184
if success:
164-
self.wait_for_getdata([tx.sha256], timeout)
185+
if use_wtxid:
186+
self.wait_for_getdata([wtxid], timeout)
187+
else:
188+
self.wait_for_getdata([tx.sha256], timeout)
165189
else:
166190
time.sleep(timeout)
167191
assert not self.last_message.get("getdata")
@@ -277,6 +301,7 @@ def run_test(self):
277301
self.test_upgrade_after_activation()
278302
self.test_witness_sigops()
279303
self.test_superfluous_witness()
304+
self.test_wtxid_relay()
280305

281306
# Individual tests
282307

@@ -1270,7 +1295,6 @@ def test_tx_relay_after_segwit_activation(self):
12701295
test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=True, accepted=False)
12711296

12721297
# Verify that removing the witness succeeds.
1273-
self.test_node.announce_tx_and_wait_for_getdata(tx)
12741298
test_transaction_acceptance(self.nodes[0], self.test_node, tx, with_witness=False, accepted=True)
12751299

12761300
# Now try to add extra witness data to a valid witness tx.
@@ -1297,8 +1321,6 @@ def test_tx_relay_after_segwit_activation(self):
12971321
# Node will not be blinded to the transaction
12981322
self.std_node.announce_tx_and_wait_for_getdata(tx3)
12991323
test_transaction_acceptance(self.nodes[1], self.std_node, tx3, True, False, 'tx-size')
1300-
self.std_node.announce_tx_and_wait_for_getdata(tx3)
1301-
test_transaction_acceptance(self.nodes[1], self.std_node, tx3, True, False)
13021324

13031325
# Remove witness stuffing, instead add extra witness push on stack
13041326
tx3.vout[0] = CTxOut(tx2.vout[0].nValue - 1000, CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE]))
@@ -2016,6 +2038,11 @@ def test_witness_sigops(self):
20162038

20172039
# TODO: test p2sh sigop counting
20182040

2041+
# Cleanup and prep for next test
2042+
self.utxo.pop(0)
2043+
self.utxo.append(UTXO(tx2.sha256, 0, tx2.vout[0].nValue))
2044+
2045+
@subtest # type: ignore
20192046
def test_superfluous_witness(self):
20202047
# Serialization of tx that puts witness flag to 3 always
20212048
def serialize_with_bogus_witness(tx):
@@ -2059,6 +2086,67 @@ def serialize(self):
20592086
with self.nodes[0].assert_debug_log(['Unknown transaction optional data']):
20602087
self.nodes[0].p2p.send_and_ping(msg_bogus_tx(tx))
20612088

2089+
@subtest # type: ignore
2090+
def test_wtxid_relay(self):
2091+
# Use brand new nodes to avoid contamination from earlier tests
2092+
self.wtx_node = self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=True), services=NODE_NETWORK | NODE_WITNESS)
2093+
self.tx_node = self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=False), services=NODE_NETWORK | NODE_WITNESS)
2094+
2095+
# Check wtxidrelay feature negotiation message through connecting a new peer
2096+
def received_wtxidrelay():
2097+
return (len(self.wtx_node.last_wtxidrelay) > 0)
2098+
wait_until(received_wtxidrelay, timeout=60, lock=mininode_lock)
2099+
2100+
# Create a Segwit output from the latest UTXO
2101+
# and announce it to the network
2102+
witness_program = CScript([OP_TRUE])
2103+
witness_hash = sha256(witness_program)
2104+
script_pubkey = CScript([OP_0, witness_hash])
2105+
2106+
tx = CTransaction()
2107+
tx.vin.append(CTxIn(COutPoint(self.utxo[0].sha256, self.utxo[0].n), b""))
2108+
tx.vout.append(CTxOut(self.utxo[0].nValue - 1000, script_pubkey))
2109+
tx.rehash()
2110+
2111+
# Create a Segwit transaction
2112+
tx2 = CTransaction()
2113+
tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
2114+
tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_pubkey))
2115+
tx2.wit.vtxinwit.append(CTxInWitness())
2116+
tx2.wit.vtxinwit[0].scriptWitness.stack = [witness_program]
2117+
tx2.rehash()
2118+
2119+
# Announce Segwit transaction with wtxid
2120+
# and wait for getdata
2121+
self.wtx_node.announce_tx_and_wait_for_getdata(tx2, use_wtxid=True)
2122+
with mininode_lock:
2123+
lgd = self.wtx_node.lastgetdata[:]
2124+
assert_equal(lgd, [CInv(MSG_WTX, tx2.calc_sha256(True))])
2125+
2126+
# Announce Segwit transaction from non wtxidrelay peer
2127+
# and wait for getdata
2128+
self.tx_node.announce_tx_and_wait_for_getdata(tx2, use_wtxid=False)
2129+
with mininode_lock:
2130+
lgd = self.tx_node.lastgetdata[:]
2131+
assert_equal(lgd, [CInv(MSG_TX|MSG_WITNESS_FLAG, tx2.sha256)])
2132+
2133+
# Send tx2 through; it's an orphan so won't be accepted
2134+
with mininode_lock:
2135+
self.tx_node.last_message.pop("getdata", None)
2136+
test_transaction_acceptance(self.nodes[0], self.tx_node, tx2, with_witness=True, accepted=False)
2137+
2138+
# Expect a request for parent (tx) due to use of non-WTX peer
2139+
self.tx_node.wait_for_getdata([tx.sha256], 60)
2140+
with mininode_lock:
2141+
lgd = self.tx_node.lastgetdata[:]
2142+
assert_equal(lgd, [CInv(MSG_TX|MSG_WITNESS_FLAG, tx.sha256)])
2143+
2144+
# Send tx through
2145+
test_transaction_acceptance(self.nodes[0], self.tx_node, tx, with_witness=False, accepted=True)
2146+
2147+
# Check tx2 is there now
2148+
assert_equal(tx2.hash in self.nodes[0].getrawmempool(), True)
2149+
20622150

20632151
if __name__ == '__main__':
20642152
SegWitTest().main()

0 commit comments

Comments
 (0)