25
25
MSG_BLOCK ,
26
26
MSG_TX ,
27
27
MSG_WITNESS_FLAG ,
28
+ MSG_WTX ,
28
29
NODE_NETWORK ,
29
30
NODE_WITNESS ,
30
31
msg_no_witness_block ,
34
35
msg_tx ,
35
36
msg_block ,
36
37
msg_no_witness_tx ,
38
+ msg_verack ,
39
+ msg_wtxidrelay ,
37
40
ser_uint256 ,
38
41
ser_vector ,
39
42
sha256 ,
81
84
softfork_active ,
82
85
hex_str_to_bytes ,
83
86
assert_raises_rpc_error ,
87
+ wait_until ,
84
88
)
85
89
86
90
# 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
143
147
144
148
145
149
class TestP2PConn (P2PInterface ):
146
- def __init__ (self ):
150
+ def __init__ (self , wtxidrelay = False ):
147
151
super ().__init__ ()
148
152
self .getdataset = set ()
153
+ self .last_wtxidrelay = []
154
+ self .lastgetdata = []
155
+ self .wtxidrelay = wtxidrelay
149
156
150
157
# Avoid sending out msg_getdata in the mininode thread as a reply to invs.
151
158
# They are not needed and would only lead to races because we send msg_getdata out in the test thread
152
159
def on_inv (self , message ):
153
160
pass
154
161
162
+ def on_version (self , message ):
163
+ if self .wtxidrelay :
164
+ self .send_message (msg_wtxidrelay ())
165
+ super ().on_version (message )
166
+
155
167
def on_getdata (self , message ):
168
+ self .lastgetdata = message .inv
156
169
for inv in message .inv :
157
170
self .getdataset .add (inv .hash )
158
171
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 ):
160
176
with mininode_lock :
161
177
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
+
163
184
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 )
165
189
else :
166
190
time .sleep (timeout )
167
191
assert not self .last_message .get ("getdata" )
@@ -277,6 +301,7 @@ def run_test(self):
277
301
self .test_upgrade_after_activation ()
278
302
self .test_witness_sigops ()
279
303
self .test_superfluous_witness ()
304
+ self .test_wtxid_relay ()
280
305
281
306
# Individual tests
282
307
@@ -1270,7 +1295,6 @@ def test_tx_relay_after_segwit_activation(self):
1270
1295
test_transaction_acceptance (self .nodes [0 ], self .test_node , tx , with_witness = True , accepted = False )
1271
1296
1272
1297
# Verify that removing the witness succeeds.
1273
- self .test_node .announce_tx_and_wait_for_getdata (tx )
1274
1298
test_transaction_acceptance (self .nodes [0 ], self .test_node , tx , with_witness = False , accepted = True )
1275
1299
1276
1300
# Now try to add extra witness data to a valid witness tx.
@@ -1297,8 +1321,6 @@ def test_tx_relay_after_segwit_activation(self):
1297
1321
# Node will not be blinded to the transaction
1298
1322
self .std_node .announce_tx_and_wait_for_getdata (tx3 )
1299
1323
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 )
1302
1324
1303
1325
# Remove witness stuffing, instead add extra witness push on stack
1304
1326
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):
2016
2038
2017
2039
# TODO: test p2sh sigop counting
2018
2040
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
2019
2046
def test_superfluous_witness (self ):
2020
2047
# Serialization of tx that puts witness flag to 3 always
2021
2048
def serialize_with_bogus_witness (tx ):
@@ -2059,6 +2086,67 @@ def serialize(self):
2059
2086
with self .nodes [0 ].assert_debug_log (['Unknown transaction optional data' ]):
2060
2087
self .nodes [0 ].p2p .send_and_ping (msg_bogus_tx (tx ))
2061
2088
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
+
2062
2150
2063
2151
if __name__ == '__main__' :
2064
2152
SegWitTest ().main ()
0 commit comments