55"""Test generation and spending of P2TR addresses."""
66
77import random
8+ import uuid
89
910from decimal import Decimal
1011from test_framework .address import output_key_to_p2tr
@@ -226,104 +227,162 @@ def make_addr(treefn, keys, i):
226227
227228 def do_test_addr (self , comment , pattern , privmap , treefn , keys ):
228229 self .log .info ("Testing %s address derivation" % comment )
230+
231+ # Create wallets
232+ wallet_uuid = uuid .uuid4 ().hex
233+ self .nodes [0 ].createwallet (wallet_name = f"privs_tr_enabled_{ wallet_uuid } " , descriptors = True , blank = True )
234+ self .nodes [0 ].createwallet (wallet_name = f"pubs_tr_enabled_{ wallet_uuid } " , descriptors = True , blank = True , disable_private_keys = True )
235+ self .nodes [0 ].createwallet (wallet_name = f"addr_gen_{ wallet_uuid } " , descriptors = True , disable_private_keys = True , blank = True )
236+ privs_tr_enabled = self .nodes [0 ].get_wallet_rpc (f"privs_tr_enabled_{ wallet_uuid } " )
237+ pubs_tr_enabled = self .nodes [0 ].get_wallet_rpc (f"pubs_tr_enabled_{ wallet_uuid } " )
238+ addr_gen = self .nodes [0 ].get_wallet_rpc (f"addr_gen_{ wallet_uuid } " )
239+
229240 desc = self .make_desc (pattern , privmap , keys , False )
230241 desc_pub = self .make_desc (pattern , privmap , keys , True )
231242 assert_equal (self .nodes [0 ].getdescriptorinfo (desc )['descriptor' ], desc_pub )
232- result = self . addr_gen .importdescriptors ([{"desc" : desc_pub , "active" : True , "timestamp" : "now" }])
243+ result = addr_gen .importdescriptors ([{"desc" : desc_pub , "active" : True , "timestamp" : "now" }])
233244 assert (result [0 ]['success' ])
245+ address_type = "bech32m" if "tr" in pattern else "bech32"
234246 for i in range (4 ):
235- addr_g = self . addr_gen .getnewaddress (address_type = 'bech32m' )
247+ addr_g = addr_gen .getnewaddress (address_type = address_type )
236248 if treefn is not None :
237249 addr_r = self .make_addr (treefn , keys , i )
238250 assert_equal (addr_g , addr_r )
239- desc_a = self . addr_gen .getaddressinfo (addr_g )['desc' ]
251+ desc_a = addr_gen .getaddressinfo (addr_g )['desc' ]
240252 if desc .startswith ("tr(" ):
241253 assert desc_a .startswith ("tr(" )
242254 rederive = self .nodes [1 ].deriveaddresses (desc_a )
243255 assert_equal (len (rederive ), 1 )
244256 assert_equal (rederive [0 ], addr_g )
245257
246258 # tr descriptors can be imported
247- result = self . privs_tr_enabled .importdescriptors ([{"desc" : desc , "timestamp" : "now" }])
259+ result = privs_tr_enabled .importdescriptors ([{"desc" : desc , "timestamp" : "now" }])
248260 assert (result [0 ]["success" ])
249- result = self . pubs_tr_enabled .importdescriptors ([{"desc" : desc_pub , "timestamp" : "now" }])
261+ result = pubs_tr_enabled .importdescriptors ([{"desc" : desc_pub , "timestamp" : "now" }])
250262 assert (result [0 ]["success" ])
251263
264+ # Cleanup
265+ privs_tr_enabled .unloadwallet ()
266+ pubs_tr_enabled .unloadwallet ()
267+ addr_gen .unloadwallet ()
268+
252269 def do_test_sendtoaddress (self , comment , pattern , privmap , treefn , keys_pay , keys_change ):
253270 self .log .info ("Testing %s through sendtoaddress" % comment )
271+
272+ # Create wallets
273+ wallet_uuid = uuid .uuid4 ().hex
274+ self .nodes [0 ].createwallet (wallet_name = f"rpc_online_{ wallet_uuid } " , descriptors = True , blank = True )
275+ rpc_online = self .nodes [0 ].get_wallet_rpc (f"rpc_online_{ wallet_uuid } " )
276+
254277 desc_pay = self .make_desc (pattern , privmap , keys_pay )
255278 desc_change = self .make_desc (pattern , privmap , keys_change )
256279 desc_pay_pub = self .make_desc (pattern , privmap , keys_pay , True )
257280 desc_change_pub = self .make_desc (pattern , privmap , keys_change , True )
258281 assert_equal (self .nodes [0 ].getdescriptorinfo (desc_pay )['descriptor' ], desc_pay_pub )
259282 assert_equal (self .nodes [0 ].getdescriptorinfo (desc_change )['descriptor' ], desc_change_pub )
260- result = self . rpc_online .importdescriptors ([{"desc" : desc_pay , "active" : True , "timestamp" : "now" }])
283+ result = rpc_online .importdescriptors ([{"desc" : desc_pay , "active" : True , "timestamp" : "now" }])
261284 assert (result [0 ]['success' ])
262- result = self . rpc_online .importdescriptors ([{"desc" : desc_change , "active" : True , "timestamp" : "now" , "internal" : True }])
285+ result = rpc_online .importdescriptors ([{"desc" : desc_change , "active" : True , "timestamp" : "now" , "internal" : True }])
263286 assert (result [0 ]['success' ])
287+ address_type = "bech32m" if "tr" in pattern else "bech32"
264288 for i in range (4 ):
265- addr_g = self . rpc_online .getnewaddress (address_type = 'bech32m' )
289+ addr_g = rpc_online .getnewaddress (address_type = address_type )
266290 if treefn is not None :
267291 addr_r = self .make_addr (treefn , keys_pay , i )
268292 assert_equal (addr_g , addr_r )
269293 boring_balance = int (self .boring .getbalance () * 100000000 )
270294 to_amnt = random .randrange (1000000 , boring_balance )
271295 self .boring .sendtoaddress (address = addr_g , amount = Decimal (to_amnt ) / 100000000 , subtractfeefromamount = True )
272296 self .generatetoaddress (self .nodes [0 ], 1 , self .boring .getnewaddress (), sync_fun = self .no_op )
273- test_balance = int (self . rpc_online .getbalance () * 100000000 )
297+ test_balance = int (rpc_online .getbalance () * 100000000 )
274298 ret_amnt = random .randrange (100000 , test_balance )
275299 # Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
276- res = self . rpc_online .sendtoaddress (address = self .boring .getnewaddress (), amount = Decimal (ret_amnt ) / 100000000 , subtractfeefromamount = True , fee_rate = 200 )
300+ res = rpc_online .sendtoaddress (address = self .boring .getnewaddress (), amount = Decimal (ret_amnt ) / 100000000 , subtractfeefromamount = True , fee_rate = 200 )
277301 self .generatetoaddress (self .nodes [0 ], 1 , self .boring .getnewaddress (), sync_fun = self .no_op )
278- assert (self .rpc_online .gettransaction (res )["confirmations" ] > 0 )
302+ assert (rpc_online .gettransaction (res )["confirmations" ] > 0 )
303+
304+ # Cleanup
305+ txid = rpc_online .sendall (recipients = [self .boring .getnewaddress ()])["txid" ]
306+ self .generatetoaddress (self .nodes [0 ], 1 , self .boring .getnewaddress (), sync_fun = self .no_op )
307+ assert (rpc_online .gettransaction (txid )["confirmations" ] > 0 )
308+ rpc_online .unloadwallet ()
279309
280310 def do_test_psbt (self , comment , pattern , privmap , treefn , keys_pay , keys_change ):
281311 self .log .info ("Testing %s through PSBT" % comment )
312+
313+ # Create wallets
314+ wallet_uuid = uuid .uuid4 ().hex
315+ self .nodes [0 ].createwallet (wallet_name = f"psbt_online_{ wallet_uuid } " , descriptors = True , disable_private_keys = True , blank = True )
316+ self .nodes [1 ].createwallet (wallet_name = f"psbt_offline_{ wallet_uuid } " , descriptors = True , blank = True )
317+ self .nodes [1 ].createwallet (f"key_only_wallet_{ wallet_uuid } " , descriptors = True , blank = True )
318+ psbt_online = self .nodes [0 ].get_wallet_rpc (f"psbt_online_{ wallet_uuid } " )
319+ psbt_offline = self .nodes [1 ].get_wallet_rpc (f"psbt_offline_{ wallet_uuid } " )
320+ key_only_wallet = self .nodes [1 ].get_wallet_rpc (f"key_only_wallet_{ wallet_uuid } " )
321+
282322 desc_pay = self .make_desc (pattern , privmap , keys_pay , False )
283323 desc_change = self .make_desc (pattern , privmap , keys_change , False )
284324 desc_pay_pub = self .make_desc (pattern , privmap , keys_pay , True )
285325 desc_change_pub = self .make_desc (pattern , privmap , keys_change , True )
286326 assert_equal (self .nodes [0 ].getdescriptorinfo (desc_pay )['descriptor' ], desc_pay_pub )
287327 assert_equal (self .nodes [0 ].getdescriptorinfo (desc_change )['descriptor' ], desc_change_pub )
288- result = self . psbt_online .importdescriptors ([{"desc" : desc_pay_pub , "active" : True , "timestamp" : "now" }])
328+ result = psbt_online .importdescriptors ([{"desc" : desc_pay_pub , "active" : True , "timestamp" : "now" }])
289329 assert (result [0 ]['success' ])
290- result = self . psbt_online .importdescriptors ([{"desc" : desc_change_pub , "active" : True , "timestamp" : "now" , "internal" : True }])
330+ result = psbt_online .importdescriptors ([{"desc" : desc_change_pub , "active" : True , "timestamp" : "now" , "internal" : True }])
291331 assert (result [0 ]['success' ])
292- result = self . psbt_offline .importdescriptors ([{"desc" : desc_pay , "active" : True , "timestamp" : "now" }])
332+ result = psbt_offline .importdescriptors ([{"desc" : desc_pay , "active" : True , "timestamp" : "now" }])
293333 assert (result [0 ]['success' ])
294- result = self . psbt_offline .importdescriptors ([{"desc" : desc_change , "active" : True , "timestamp" : "now" , "internal" : True }])
334+ result = psbt_offline .importdescriptors ([{"desc" : desc_change , "active" : True , "timestamp" : "now" , "internal" : True }])
295335 assert (result [0 ]['success' ])
336+ for key in keys_pay + keys_change :
337+ result = key_only_wallet .importdescriptors ([{"desc" : descsum_create (f"wpkh({ key ['xprv' ]} /*)" ), "timestamp" :"now" }])
338+ assert (result [0 ]["success" ])
339+ address_type = "bech32m" if "tr" in pattern else "bech32"
296340 for i in range (4 ):
297- addr_g = self . psbt_online .getnewaddress (address_type = 'bech32m' )
341+ addr_g = psbt_online .getnewaddress (address_type = address_type )
298342 if treefn is not None :
299343 addr_r = self .make_addr (treefn , keys_pay , i )
300344 assert_equal (addr_g , addr_r )
301345 boring_balance = int (self .boring .getbalance () * 100000000 )
302346 to_amnt = random .randrange (1000000 , boring_balance )
303347 self .boring .sendtoaddress (address = addr_g , amount = Decimal (to_amnt ) / 100000000 , subtractfeefromamount = True )
304348 self .generatetoaddress (self .nodes [0 ], 1 , self .boring .getnewaddress (), sync_fun = self .no_op )
305- test_balance = int (self . psbt_online .getbalance () * 100000000 )
349+ test_balance = int (psbt_online .getbalance () * 100000000 )
306350 ret_amnt = random .randrange (100000 , test_balance )
307351 # Increase fee_rate to compensate for the wallet's inability to estimate fees for script path spends.
308- psbt = self .psbt_online .walletcreatefundedpsbt ([], [{self .boring .getnewaddress (): Decimal (ret_amnt ) / 100000000 }], None , {"subtractFeeFromOutputs" :[0 ], "fee_rate" : 200 , "change_type" : "bech32m" })['psbt' ]
309- res = self .psbt_offline .walletprocesspsbt (psbt = psbt , finalize = False )
310-
311- decoded = self .psbt_offline .decodepsbt (res ["psbt" ])
312- if pattern .startswith ("tr(" ):
313- for psbtin in decoded ["inputs" ]:
314- assert "non_witness_utxo" not in psbtin
315- assert "witness_utxo" in psbtin
316- assert "taproot_internal_key" in psbtin
317- assert "taproot_bip32_derivs" in psbtin
318- assert "taproot_key_path_sig" in psbtin or "taproot_script_path_sigs" in psbtin
319- if "taproot_script_path_sigs" in psbtin :
320- assert "taproot_merkle_root" in psbtin
321- assert "taproot_scripts" in psbtin
322-
323- rawtx = self .nodes [0 ].finalizepsbt (res ['psbt' ])['hex' ]
352+ psbt = psbt_online .walletcreatefundedpsbt ([], [{self .boring .getnewaddress (): Decimal (ret_amnt ) / 100000000 }], None , {"subtractFeeFromOutputs" :[0 ], "fee_rate" : 200 , "change_type" : address_type })['psbt' ]
353+ res = psbt_offline .walletprocesspsbt (psbt = psbt , finalize = False )
354+ for wallet in [psbt_offline , key_only_wallet ]:
355+ res = wallet .walletprocesspsbt (psbt = psbt , finalize = False )
356+
357+ decoded = wallet .decodepsbt (res ["psbt" ])
358+ if pattern .startswith ("tr(" ):
359+ for psbtin in decoded ["inputs" ]:
360+ assert "non_witness_utxo" not in psbtin
361+ assert "witness_utxo" in psbtin
362+ assert "taproot_internal_key" in psbtin
363+ assert "taproot_bip32_derivs" in psbtin
364+ assert "taproot_key_path_sig" in psbtin or "taproot_script_path_sigs" in psbtin
365+ if "taproot_script_path_sigs" in psbtin :
366+ assert "taproot_merkle_root" in psbtin
367+ assert "taproot_scripts" in psbtin
368+
369+ rawtx = self .nodes [0 ].finalizepsbt (res ['psbt' ])['hex' ]
370+ res = self .nodes [0 ].testmempoolaccept ([rawtx ])
371+ assert res [0 ]["allowed" ]
372+
324373 txid = self .nodes [0 ].sendrawtransaction (rawtx )
325374 self .generatetoaddress (self .nodes [0 ], 1 , self .boring .getnewaddress (), sync_fun = self .no_op )
326- assert (self .psbt_online .gettransaction (txid )['confirmations' ] > 0 )
375+ assert (psbt_online .gettransaction (txid )['confirmations' ] > 0 )
376+
377+ # Cleanup
378+ psbt = psbt_online .sendall (recipients = [self .boring .getnewaddress ()], options = {"psbt" : True })["psbt" ]
379+ res = psbt_offline .walletprocesspsbt (psbt = psbt , finalize = False )
380+ rawtx = self .nodes [0 ].finalizepsbt (res ['psbt' ])['hex' ]
381+ txid = self .nodes [0 ].sendrawtransaction (rawtx )
382+ self .generatetoaddress (self .nodes [0 ], 1 , self .boring .getnewaddress (), sync_fun = self .no_op )
383+ assert (psbt_online .gettransaction (txid )['confirmations' ] > 0 )
384+ psbt_online .unloadwallet ()
385+ psbt_offline .unloadwallet ()
327386
328387 def do_test (self , comment , pattern , privmap , treefn ):
329388 nkeys = len (privmap )
@@ -333,21 +392,8 @@ def do_test(self, comment, pattern, privmap, treefn):
333392 self .do_test_psbt (comment , pattern , privmap , treefn , keys [2 * nkeys :3 * nkeys ], keys [3 * nkeys :4 * nkeys ])
334393
335394 def run_test (self ):
336- self .log .info ("Creating wallets..." )
337- self .nodes [0 ].createwallet (wallet_name = "privs_tr_enabled" , descriptors = True , blank = True )
338- self .privs_tr_enabled = self .nodes [0 ].get_wallet_rpc ("privs_tr_enabled" )
339- self .nodes [0 ].createwallet (wallet_name = "pubs_tr_enabled" , descriptors = True , blank = True , disable_private_keys = True )
340- self .pubs_tr_enabled = self .nodes [0 ].get_wallet_rpc ("pubs_tr_enabled" )
341395 self .nodes [0 ].createwallet (wallet_name = "boring" )
342- self .nodes [0 ].createwallet (wallet_name = "addr_gen" , descriptors = True , disable_private_keys = True , blank = True )
343- self .nodes [0 ].createwallet (wallet_name = "rpc_online" , descriptors = True , blank = True )
344- self .nodes [0 ].createwallet (wallet_name = "psbt_online" , descriptors = True , disable_private_keys = True , blank = True )
345- self .nodes [1 ].createwallet (wallet_name = "psbt_offline" , descriptors = True , blank = True )
346396 self .boring = self .nodes [0 ].get_wallet_rpc ("boring" )
347- self .addr_gen = self .nodes [0 ].get_wallet_rpc ("addr_gen" )
348- self .rpc_online = self .nodes [0 ].get_wallet_rpc ("rpc_online" )
349- self .psbt_online = self .nodes [0 ].get_wallet_rpc ("psbt_online" )
350- self .psbt_offline = self .nodes [1 ].get_wallet_rpc ("psbt_offline" )
351397
352398 self .log .info ("Mining blocks..." )
353399 gen_addr = self .boring .getnewaddress ()
@@ -457,18 +503,5 @@ def run_test(self):
457503 lambda k1 : key (k1 )
458504 )
459505
460- self .log .info ("Sending everything back..." )
461-
462- txid = self .rpc_online .sendall (recipients = [self .boring .getnewaddress ()])["txid" ]
463- self .generatetoaddress (self .nodes [0 ], 1 , self .boring .getnewaddress (), sync_fun = self .no_op )
464- assert (self .rpc_online .gettransaction (txid )["confirmations" ] > 0 )
465-
466- psbt = self .psbt_online .sendall (recipients = [self .boring .getnewaddress ()], options = {"psbt" : True })["psbt" ]
467- res = self .psbt_offline .walletprocesspsbt (psbt = psbt , finalize = False )
468- rawtx = self .nodes [0 ].finalizepsbt (res ['psbt' ])['hex' ]
469- txid = self .nodes [0 ].sendrawtransaction (rawtx )
470- self .generatetoaddress (self .nodes [0 ], 1 , self .boring .getnewaddress (), sync_fun = self .no_op )
471- assert (self .psbt_online .gettransaction (txid )['confirmations' ] > 0 )
472-
473506if __name__ == '__main__' :
474507 WalletTaprootTest ().main ()
0 commit comments