@@ -441,7 +441,6 @@ def test_txprepare(node_factory, bitcoind, chainparams):
441441 assert decode ['vout' ][changenum ]['scriptPubKey' ]['type' ] == 'witness_v0_keyhash'
442442
443443
444- @unittest .skipIf (TEST_NETWORK == 'liquid-regtest' , '' )
445444def test_reserveinputs (node_factory , bitcoind , chainparams ):
446445 amount = 1000000
447446 total_outs = 12
@@ -495,12 +494,14 @@ def test_reserveinputs(node_factory, bitcoind, chainparams):
495494 assert not any ('reserved_to_block' in o for o in l1 .rpc .listfunds ()['outputs' ])
496495
497496
498- @unittest .skipIf (TEST_NETWORK == 'liquid-regtest' , '' )
499497def test_fundpsbt (node_factory , bitcoind , chainparams ):
500498 amount = 1000000
501499 total_outs = 4
502500 l1 = node_factory .get_node ()
503501
502+ # CLN returns PSBTv0 and PSETv2, for now
503+ is_psbt_v2 = chainparams ['elements' ]
504+
504505 outputs = []
505506 # Add a medley of funds to withdraw later
506507 for i in range (total_outs ):
@@ -515,22 +516,35 @@ def test_fundpsbt(node_factory, bitcoind, chainparams):
515516
516517 # Should get one input, plus some excess
517518 funding = l1 .rpc .fundpsbt (amount // 2 , feerate , 0 , reserve = 0 )
519+
518520 psbt = bitcoind .rpc .decodepsbt (funding ['psbt' ])
519521 # We can fuzz this up to 99 blocks back.
520- assert psbt ['tx' ]['locktime' ] > bitcoind .rpc .getblockcount () - 100
521- assert psbt ['tx' ]['locktime' ] <= bitcoind .rpc .getblockcount ()
522- assert len (psbt ['tx' ]['vin' ]) == 1
523522 assert funding ['excess_msat' ] > Millisatoshi (0 )
524523 assert funding ['excess_msat' ] < Millisatoshi (amount // 2 * 1000 )
525524 assert funding ['feerate_per_kw' ] == 7500
526525 assert 'estimated_final_weight' in funding
527526 assert 'reservations' not in funding
528527
528+ if is_psbt_v2 :
529+ assert psbt ['fallback_locktime' ] > bitcoind .rpc .getblockcount () - 100
530+ assert psbt ['fallback_locktime' ] <= bitcoind .rpc .getblockcount ()
531+ assert psbt ['input_count' ] == 1
532+ else :
533+ assert psbt ['tx' ]['locktime' ] > bitcoind .rpc .getblockcount () - 100
534+ assert psbt ['tx' ]['locktime' ] <= bitcoind .rpc .getblockcount ()
535+ assert len (psbt ['tx' ]['vin' ]) == 1
536+
529537 # This should add 99 to the weight, but otherwise be identical (might choose different inputs though!) except for locktime.
530538 funding2 = l1 .rpc .fundpsbt (amount // 2 , feerate , 99 , reserve = 0 , locktime = bitcoind .rpc .getblockcount () + 1 )
531539 psbt2 = bitcoind .rpc .decodepsbt (funding2 ['psbt' ])
532- assert psbt2 ['tx' ]['locktime' ] == bitcoind .rpc .getblockcount () + 1
533- assert len (psbt2 ['tx' ]['vin' ]) == 1
540+
541+ if is_psbt_v2 :
542+ assert psbt2 ['fallback_locktime' ] == bitcoind .rpc .getblockcount () + 1
543+ assert psbt2 ['input_count' ] == 1
544+ else :
545+ assert psbt2 ['tx' ]['locktime' ] == bitcoind .rpc .getblockcount () + 1
546+ assert len (psbt2 ['tx' ]['vin' ]) == 1
547+
534548 assert funding2 ['excess_msat' ] < funding ['excess_msat' ]
535549 assert funding2 ['feerate_per_kw' ] == 7500
536550 # Naively you'd expect this to be +99, but it might have selected a non-p2sh output...
@@ -548,7 +562,12 @@ def test_fundpsbt(node_factory, bitcoind, chainparams):
548562 assert funding3 ['excess_msat' ] == Millisatoshi (0 )
549563 # Should have the excess msat as the output value (minus fee for change)
550564 psbt = bitcoind .rpc .decodepsbt (funding3 ['psbt' ])
551- change = Millisatoshi ("{}btc" .format (psbt ['tx' ]['vout' ][funding3 ['change_outnum' ]]['value' ]))
565+
566+ if is_psbt_v2 :
567+ change = Millisatoshi ("{}btc" .format (psbt ["outputs" ][funding3 ['change_outnum' ]]["amount" ]))
568+ else :
569+ change = Millisatoshi ("{}btc" .format (psbt ['tx' ]['vout' ][funding3 ['change_outnum' ]]['value' ]))
570+
552571 # The weight should be greater (now includes change output)
553572 change_weight = funding3 ['estimated_final_weight' ] - funding ['estimated_final_weight' ]
554573 assert change_weight > 0
@@ -558,7 +577,10 @@ def test_fundpsbt(node_factory, bitcoind, chainparams):
558577
559578 # Should get two inputs.
560579 psbt = bitcoind .rpc .decodepsbt (l1 .rpc .fundpsbt (amount , feerate , 0 , reserve = 0 )['psbt' ])
561- assert len (psbt ['tx' ]['vin' ]) == 2
580+ if is_psbt_v2 :
581+ assert psbt ['input_count' ] == 2
582+ else :
583+ assert len (psbt ['tx' ]['vin' ]) == 2
562584
563585 # Should not use reserved outputs.
564586 psbt = bitcoind .rpc .createpsbt ([{'txid' : out [0 ], 'vout' : out [1 ]} for out in outputs ], [])
@@ -579,11 +601,13 @@ def test_fundpsbt(node_factory, bitcoind, chainparams):
579601 l1 .rpc .fundpsbt (amount // 2 , feerate , 0 )
580602
581603
582- @unittest .skipIf (TEST_NETWORK == 'liquid-regtest' , '' )
583604def test_utxopsbt (node_factory , bitcoind , chainparams ):
584605 amount = 1000000
585606 l1 = node_factory .get_node ()
586607
608+ # CLN returns PSBTv0 and PSETv2, for now
609+ is_psbt_v2 = chainparams ['elements' ]
610+
587611 outputs = []
588612 # Add a funds to withdraw later
589613 for _ in range (2 ):
@@ -603,27 +627,40 @@ def test_utxopsbt(node_factory, bitcoind, chainparams):
603627 reserve = 0 )
604628 psbt = bitcoind .rpc .decodepsbt (funding ['psbt' ])
605629 # We can fuzz this up to 99 blocks back.
606- assert psbt ['tx' ]['locktime' ] > bitcoind .rpc .getblockcount () - 100
607- assert psbt ['tx' ]['locktime' ] <= bitcoind .rpc .getblockcount ()
608- assert len (psbt ['tx' ]['vin' ]) == 1
609630 assert funding ['excess_msat' ] > Millisatoshi (0 )
610631 assert funding ['excess_msat' ] < Millisatoshi (amount // 2 * 1000 )
611632 assert funding ['feerate_per_kw' ] == 7500
612633 assert 'estimated_final_weight' in funding
613634 assert 'reservations' not in funding
614635
636+ if is_psbt_v2 :
637+ assert psbt ['fallback_locktime' ] > bitcoind .rpc .getblockcount () - 100
638+ assert psbt ['fallback_locktime' ] <= bitcoind .rpc .getblockcount ()
639+ assert psbt ['input_count' ] == 1
640+ else :
641+ assert psbt ['tx' ]['locktime' ] > bitcoind .rpc .getblockcount () - 100
642+ assert psbt ['tx' ]['locktime' ] <= bitcoind .rpc .getblockcount ()
643+ assert len (psbt ['tx' ]['vin' ]) == 1
644+
615645 # This should add 99 to the weight, but otherwise be identical except for locktime.
616646 start_weight = 99
617647 funding2 = l1 .rpc .utxopsbt (amount // 2 , feerate , start_weight ,
618648 ['{}:{}' .format (outputs [0 ][0 ], outputs [0 ][1 ])],
619649 reserve = 0 , locktime = bitcoind .rpc .getblockcount () + 1 )
620650 psbt2 = bitcoind .rpc .decodepsbt (funding2 ['psbt' ])
621- assert psbt2 ['tx' ]['locktime' ] == bitcoind .rpc .getblockcount () + 1
622- assert psbt2 ['tx' ]['vin' ] == psbt ['tx' ]['vin' ]
651+
652+ if is_psbt_v2 :
653+ assert psbt2 ['fallback_locktime' ] == bitcoind .rpc .getblockcount () + 1
654+ assert psbt2 ['inputs' ] == psbt ['inputs' ]
655+ else :
656+ assert psbt2 ['tx' ]['locktime' ] == bitcoind .rpc .getblockcount () + 1
657+ assert psbt2 ['tx' ]['vin' ] == psbt ['tx' ]['vin' ]
658+
623659 if chainparams ['elements' ]:
660+ assert is_psbt_v2
624661 # elements includes the fee as an output
625662 addl_fee = Millisatoshi ((fee_val * start_weight + 999 ) // 1000 * 1000 )
626- assert psbt2 ['tx ' ]['vout' ][ 0 ]['value ' ] == psbt ['tx ' ]['vout' ][ 0 ]['value ' ] + addl_fee .to_btc ()
663+ assert psbt2 ['outputs ' ][0 ]['amount ' ] == psbt ['outputs ' ][0 ]['amount ' ] + addl_fee .to_btc ()
627664 else :
628665 assert psbt2 ['tx' ]['vout' ] == psbt ['tx' ]['vout' ]
629666 assert funding2 ['excess_msat' ] < funding ['excess_msat' ]
@@ -649,7 +686,11 @@ def test_utxopsbt(node_factory, bitcoind, chainparams):
649686 assert funding3 ['excess_msat' ] == Millisatoshi (0 )
650687 # Should have the excess msat as the output value (minus fee for change)
651688 psbt = bitcoind .rpc .decodepsbt (funding3 ['psbt' ])
652- change = Millisatoshi ("{}btc" .format (psbt ['tx' ]['vout' ][funding3 ['change_outnum' ]]['value' ]))
689+ if is_psbt_v2 :
690+ change = Millisatoshi ("{}btc" .format (psbt ['outputs' ][funding3 ['change_outnum' ]]['amount' ]))
691+ else :
692+ change = Millisatoshi ("{}btc" .format (psbt ['tx' ]['vout' ][funding3 ['change_outnum' ]]['value' ]))
693+
653694 # The weight should be greater (now includes change output)
654695 change_weight = funding3 ['estimated_final_weight' ] - funding ['estimated_final_weight' ]
655696 assert change_weight > 0
@@ -670,7 +711,10 @@ def test_utxopsbt(node_factory, bitcoind, chainparams):
670711 ['{}:{}' .format (outputs [0 ][0 ], outputs [0 ][1 ]),
671712 '{}:{}' .format (outputs [1 ][0 ], outputs [1 ][1 ])])
672713 psbt = bitcoind .rpc .decodepsbt (funding ['psbt' ])
673- assert len (psbt ['tx' ]['vin' ]) == 2
714+ if is_psbt_v2 :
715+ assert psbt ['input_count' ] == 2
716+ else :
717+ assert len (psbt ['tx' ]['vin' ]) == 2
674718 assert len (funding ['reservations' ]) == 2
675719 assert funding ['reservations' ][0 ]['txid' ] == outputs [0 ][0 ]
676720 assert funding ['reservations' ][0 ]['vout' ] == outputs [0 ][1 ]
@@ -694,7 +738,6 @@ def test_utxopsbt(node_factory, bitcoind, chainparams):
694738 reservedok = True )
695739
696740
697- @unittest .skipIf (TEST_NETWORK == 'liquid-regtest' , '' )
698741def test_sign_external_psbt (node_factory , bitcoind , chainparams ):
699742 """
700743 A PSBT w/ one of our inputs should be signable (we can fill
@@ -723,11 +766,64 @@ def test_sign_external_psbt(node_factory, bitcoind, chainparams):
723766 l1 .rpc .signpsbt (psbt )
724767
725768
726- @unittest .skipIf (TEST_NETWORK == 'liquid-regtest' , '' )
769+ def test_psbt_version (node_factory , bitcoind , chainparams ):
770+
771+ sats_amount = 10 ** 8
772+
773+ # CLN returns PSBTv0 and PSETv2, for now
774+ is_elements = chainparams ['elements' ]
775+
776+ l1 = node_factory .get_node ()
777+ bitcoind .rpc .sendtoaddress (l1 .rpc .newaddr ()['bech32' ],
778+ sats_amount / 100000000 )
779+
780+ bitcoind .generate_block (1 )
781+ wait_for (lambda : len (l1 .rpc .listfunds ()['outputs' ]) == 1 )
782+
783+ funding = l1 .rpc .fundpsbt (satoshi = int (sats_amount / 2 ),
784+ feerate = 7500 ,
785+ startweight = 42 )['psbt' ]
786+
787+ # Short elements test
788+ if is_elements :
789+ # Only v2 is allowed, and is a no-op
790+ for i in [0 , 1 , 3 , 4 , 5 ]:
791+ with pytest .raises (RpcError , match = r"Could not set PSBT version" ):
792+ l1 .rpc .setpsbtversion (funding , i )
793+ assert funding == l1 .rpc .setpsbtversion (funding , 2 )['psbt' ]
794+ # And elementsd can understand it
795+ bitcoind .rpc .decodepsbt (funding )
796+ return
797+
798+ # Non-elements test
799+ v2_funding = l1 .rpc .setpsbtversion (funding , 2 )['psbt' ]
800+
801+ # Bitcoind cannot understand PSBTv2 yet
802+ with pytest .raises (JSONRPCError , match = r"TX decode failed Unsupported version number" ):
803+ bitcoind .rpc .decodepsbt (v2_funding )
804+
805+ # But it round-trips fine enough
806+ v0_funding = l1 .rpc .setpsbtversion (v2_funding , 0 )['psbt' ]
807+
808+ # CLN returns v0 for now
809+ assert funding == v0_funding
810+
811+ # And we reject non-0/2 args
812+ for i in [1 , 3 , 4 , 5 ]:
813+ with pytest .raises (RpcError , match = r"Could not set PSBT version" ):
814+ l1 .rpc .setpsbtversion (v2_funding , i )
815+
816+ @unittest .skipIf (TEST_NETWORK == 'liquid-regtest' , 'Core/Elements need joinpsbt support for v2' )
727817def test_sign_and_send_psbt (node_factory , bitcoind , chainparams ):
728818 """
729819 Tests for the sign + send psbt RPCs
730820 """
821+ # CLN returns PSBTv0 and PSETv2, for now
822+ is_psbt_v2 = chainparams ['elements' ]
823+
824+ # Once support for v2 joinpsbt is added, below test should work verbatim
825+ assert not is_psbt_v2
826+
731827 amount = 1000000
732828 total_outs = 12
733829 coin_mvt_plugin = os .path .join (os .getcwd (), 'tests/plugins/coin_movements.py' )
@@ -750,16 +846,24 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
750846 startweight = 42 )
751847 assert len ([x for x in l1 .rpc .listfunds ()['outputs' ] if x ['reserved' ]]) == 4
752848 psbt = bitcoind .rpc .decodepsbt (funding ['psbt' ])
753- saved_input = psbt ['tx' ]['vin' ][0 ]
849+ if is_psbt_v2 :
850+ saved_input = psbt ['inputs' ][0 ]
851+ else :
852+ saved_input = psbt ['tx' ]['vin' ][0 ]
754853
755854 # Go ahead and unreserve the UTXOs, we'll use a smaller
756855 # set of them to create a second PSBT that we'll attempt to sign
757856 # and broadcast (to disastrous results)
758857 l1 .rpc .unreserveinputs (funding ['psbt' ])
759858
760859 # Re-reserve one of the utxos we just unreserved
761- psbt = bitcoind .rpc .createpsbt ([{'txid' : saved_input ['txid' ],
762- 'vout' : saved_input ['vout' ]}], [])
860+ if is_psbt_v2 :
861+ psbt = bitcoind .rpc .createpsbt ([{'txid' : saved_input ['previous_txid' ],
862+ 'vout' : saved_input ['previous_vout' ]}], [])
863+ else :
864+ psbt = bitcoind .rpc .createpsbt ([{'txid' : saved_input ['txid' ],
865+ 'vout' : saved_input ['vout' ]}], [])
866+
763867 l1 .rpc .reserveinputs (psbt )
764868
765869 # We require the utxos be reserved before signing them
@@ -823,8 +927,12 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
823927 l1_funding = l1 .rpc .fundpsbt (satoshi = out_total ,
824928 feerate = 7500 ,
825929 startweight = 42 )
826- l1_num_inputs = len (bitcoind .rpc .decodepsbt (l1_funding ['psbt' ])['tx' ]['vin' ])
827- l2_num_inputs = len (bitcoind .rpc .decodepsbt (l2_funding ['psbt' ])['tx' ]['vin' ])
930+ if is_psbt_v2 :
931+ l1_num_inputs = bitcoind .rpc .decodepsbt (l1_funding ['psbt' ])["input_count" ]
932+ l2_num_inputs = bitcoind .rpc .decodepsbt (l2_funding ['psbt' ])["input_count" ]
933+ else :
934+ l1_num_inputs = len (bitcoind .rpc .decodepsbt (l1_funding ['psbt' ])['tx' ]['vin' ])
935+ l2_num_inputs = len (bitcoind .rpc .decodepsbt (l2_funding ['psbt' ])['tx' ]['vin' ])
828936
829937 # Join and add an output (reorders!)
830938 out_2_ms = Millisatoshi (l1_funding ['excess_msat' ])
0 commit comments