2525 MSG_BLOCK ,
2626 MSG_TX ,
2727 MSG_WITNESS_FLAG ,
28+ MSG_WTX ,
2829 NODE_NETWORK ,
2930 NODE_WITNESS ,
3031 msg_no_witness_block ,
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 ,
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
145149class 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
20632151if __name__ == '__main__' :
20642152 SegWitTest ().main ()
0 commit comments