@@ -606,11 +606,15 @@ def test_psbt_input_keys(psbt_input, keys):
606
606
607
607
assert_raises_rpc_error (- 25 , 'Inputs missing or spent' , self .nodes [0 ].walletprocesspsbt , 'cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA==' )
608
608
609
- # Test that we can fund psbts with external inputs specified
609
+ self .log .info ("Test that we can fund psbts with external inputs specified" )
610
+
610
611
eckey = ECKey ()
611
612
eckey .generate ()
612
613
privkey = bytes_to_wif (eckey .get_bytes ())
613
614
615
+ self .nodes [1 ].createwallet ("extfund" )
616
+ wallet = self .nodes [1 ].get_wallet_rpc ("extfund" )
617
+
614
618
# Make a weird but signable script. sh(pkh()) descriptor accomplishes this
615
619
desc = descsum_create ("sh(pkh({}))" .format (privkey ))
616
620
if self .options .descriptors :
@@ -622,26 +626,97 @@ def test_psbt_input_keys(psbt_input, keys):
622
626
addr_info = self .nodes [0 ].getaddressinfo (addr )
623
627
624
628
self .nodes [0 ].sendtoaddress (addr , 10 )
629
+ self .nodes [0 ].sendtoaddress (wallet .getnewaddress (), 10 )
625
630
self .generate (self .nodes [0 ], 6 )
626
631
ext_utxo = self .nodes [0 ].listunspent (addresses = [addr ])[0 ]
627
632
628
633
# An external input without solving data should result in an error
629
- assert_raises_rpc_error (- 4 , "Insufficient funds" , self . nodes [ 1 ]. walletcreatefundedpsbt , [ext_utxo ], {self .nodes [0 ].getnewaddress (): 10 + ext_utxo [ 'amount' ]}, 0 , { 'add_inputs' : True })
634
+ assert_raises_rpc_error (- 4 , "Insufficient funds" , wallet . walletcreatefundedpsbt , [ext_utxo ], {self .nodes [0 ].getnewaddress (): 15 })
630
635
631
636
# But funding should work when the solving data is provided
632
- psbt = self . nodes [ 1 ]. walletcreatefundedpsbt ([ext_utxo ], {self .nodes [0 ].getnewaddress (): 15 }, 0 , {' add_inputs' : True , "solving_data" : {"pubkeys" : [addr_info ['pubkey' ]], "scripts" : [addr_info ["embedded" ]["scriptPubKey" ]]}})
633
- signed = self . nodes [ 1 ] .walletprocesspsbt (psbt ['psbt' ])
637
+ psbt = wallet . walletcreatefundedpsbt ([ext_utxo ], {self .nodes [0 ].getnewaddress (): 15 }, 0 , {" add_inputs" : True , "solving_data" : {"pubkeys" : [addr_info ['pubkey' ]], "scripts" : [addr_info ["embedded" ]["scriptPubKey" ]]}})
638
+ signed = wallet .walletprocesspsbt (psbt ['psbt' ])
634
639
assert not signed ['complete' ]
635
640
signed = self .nodes [0 ].walletprocesspsbt (signed ['psbt' ])
636
641
assert signed ['complete' ]
637
642
self .nodes [0 ].finalizepsbt (signed ['psbt' ])
638
643
639
- psbt = self . nodes [ 1 ]. walletcreatefundedpsbt ([ext_utxo ], {self .nodes [0 ].getnewaddress (): 15 }, 0 , {' add_inputs' : True , "solving_data" :{"descriptors" : [desc ]}})
640
- signed = self . nodes [ 1 ] .walletprocesspsbt (psbt ['psbt' ])
644
+ psbt = wallet . walletcreatefundedpsbt ([ext_utxo ], {self .nodes [0 ].getnewaddress (): 15 }, 0 , {" add_inputs" : True , "solving_data" :{"descriptors" : [desc ]}})
645
+ signed = wallet .walletprocesspsbt (psbt ['psbt' ])
641
646
assert not signed ['complete' ]
642
647
signed = self .nodes [0 ].walletprocesspsbt (signed ['psbt' ])
643
648
assert signed ['complete' ]
644
- self .nodes [0 ].finalizepsbt (signed ['psbt' ])
649
+ final = self .nodes [0 ].finalizepsbt (signed ['psbt' ], False )
650
+
651
+ dec = self .nodes [0 ].decodepsbt (signed ["psbt" ])
652
+ for i , txin in enumerate (dec ["tx" ]["vin" ]):
653
+ if txin ["txid" ] == ext_utxo ["txid" ] and txin ["vout" ] == ext_utxo ["vout" ]:
654
+ input_idx = i
655
+ break
656
+ psbt_in = dec ["inputs" ][input_idx ]
657
+ # Calculate the input weight
658
+ # (prevout + sequence + length of scriptSig + 2 bytes buffer) * 4 + len of scriptwitness
659
+ len_scriptsig = len (psbt_in ["final_scriptSig" ]["hex" ]) // 2 if "final_scriptSig" in psbt_in else 0
660
+ len_scriptwitness = len (psbt_in ["final_scriptwitness" ]["hex" ]) // 2 if "final_scriptwitness" in psbt_in else 0
661
+ input_weight = ((41 + len_scriptsig + 2 ) * 4 ) + len_scriptwitness
662
+ low_input_weight = input_weight // 2
663
+ high_input_weight = input_weight * 2
664
+
665
+ # Input weight error conditions
666
+ assert_raises_rpc_error (
667
+ - 8 ,
668
+ "Input weights should be specified in inputs rather than in options." ,
669
+ wallet .walletcreatefundedpsbt ,
670
+ inputs = [ext_utxo ],
671
+ outputs = {self .nodes [0 ].getnewaddress (): 15 },
672
+ options = {"input_weights" : [{"txid" : ext_utxo ["txid" ], "vout" : ext_utxo ["vout" ], "weight" : 1000 }]}
673
+ )
674
+
675
+ # Funding should also work if the input weight is provided
676
+ psbt = wallet .walletcreatefundedpsbt (
677
+ inputs = [{"txid" : ext_utxo ["txid" ], "vout" : ext_utxo ["vout" ], "weight" : input_weight }],
678
+ outputs = {self .nodes [0 ].getnewaddress (): 15 },
679
+ options = {"add_inputs" : True }
680
+ )
681
+ signed = wallet .walletprocesspsbt (psbt ["psbt" ])
682
+ signed = self .nodes [0 ].walletprocesspsbt (signed ["psbt" ])
683
+ final = self .nodes [0 ].finalizepsbt (signed ["psbt" ])
684
+ assert self .nodes [0 ].testmempoolaccept ([final ["hex" ]])[0 ]["allowed" ]
685
+ # Reducing the weight should have a lower fee
686
+ psbt2 = wallet .walletcreatefundedpsbt (
687
+ inputs = [{"txid" : ext_utxo ["txid" ], "vout" : ext_utxo ["vout" ], "weight" : low_input_weight }],
688
+ outputs = {self .nodes [0 ].getnewaddress (): 15 },
689
+ options = {"add_inputs" : True }
690
+ )
691
+ assert_greater_than (psbt ["fee" ], psbt2 ["fee" ])
692
+ # Increasing the weight should have a higher fee
693
+ psbt2 = wallet .walletcreatefundedpsbt (
694
+ inputs = [{"txid" : ext_utxo ["txid" ], "vout" : ext_utxo ["vout" ], "weight" : high_input_weight }],
695
+ outputs = {self .nodes [0 ].getnewaddress (): 15 },
696
+ options = {"add_inputs" : True }
697
+ )
698
+ assert_greater_than (psbt2 ["fee" ], psbt ["fee" ])
699
+ # The provided weight should override the calculated weight when solving data is provided
700
+ psbt3 = wallet .walletcreatefundedpsbt (
701
+ inputs = [{"txid" : ext_utxo ["txid" ], "vout" : ext_utxo ["vout" ], "weight" : high_input_weight }],
702
+ outputs = {self .nodes [0 ].getnewaddress (): 15 },
703
+ options = {'add_inputs' : True , "solving_data" :{"descriptors" : [desc ]}}
704
+ )
705
+ assert_equal (psbt2 ["fee" ], psbt3 ["fee" ])
706
+
707
+ # Import the external utxo descriptor so that we can sign for it from the test wallet
708
+ if self .options .descriptors :
709
+ res = wallet .importdescriptors ([{"desc" : desc , "timestamp" : "now" }])
710
+ else :
711
+ res = wallet .importmulti ([{"desc" : desc , "timestamp" : "now" }])
712
+ assert res [0 ]["success" ]
713
+ # The provided weight should override the calculated weight for a wallet input
714
+ psbt3 = wallet .walletcreatefundedpsbt (
715
+ inputs = [{"txid" : ext_utxo ["txid" ], "vout" : ext_utxo ["vout" ], "weight" : high_input_weight }],
716
+ outputs = {self .nodes [0 ].getnewaddress (): 15 },
717
+ options = {"add_inputs" : True }
718
+ )
719
+ assert_equal (psbt2 ["fee" ], psbt3 ["fee" ])
645
720
646
721
if __name__ == '__main__' :
647
722
PSBTTest ().main ()
0 commit comments