@ -436,6 +436,131 @@ def test_txprepare(node_factory, bitcoind, chainparams):
assert decode [ ' vout ' ] [ changenum ] [ ' scriptPubKey ' ] [ ' type ' ] == ' witness_v0_keyhash '
def test_reserveinputs ( node_factory , bitcoind , chainparams ) :
"""
Reserve inputs is basically the same as txprepare , with the
slight exception that ' reserveinputs ' doesn ' t keep the
unsent transaction around
"""
amount = 1000000
total_outs = 12
l1 = node_factory . get_node ( feerates = ( 7500 , 7500 , 7500 , 7500 ) )
addr = chainparams [ ' example_addr ' ]
# Add a medley of funds to withdraw later, bech32 + p2sh-p2wpkh
for i in range ( total_outs / / 2 ) :
bitcoind . rpc . sendtoaddress ( l1 . rpc . newaddr ( ) [ ' bech32 ' ] ,
amount / 10 * * 8 )
bitcoind . rpc . sendtoaddress ( l1 . rpc . newaddr ( ' p2sh-segwit ' ) [ ' p2sh-segwit ' ] ,
amount / 10 * * 8 )
bitcoind . generate_block ( 1 )
wait_for ( lambda : len ( l1 . rpc . listfunds ( ) [ ' outputs ' ] ) == total_outs )
utxo_count = 8
sent = Decimal ( ' 0.01 ' ) * ( utxo_count - 1 )
reserved = l1 . rpc . reserveinputs ( outputs = [ { addr : Millisatoshi ( amount * ( utxo_count - 1 ) * 1000 ) } ] )
assert reserved [ ' feerate_per_kw ' ] == 7500
psbt = bitcoind . rpc . decodepsbt ( reserved [ ' psbt ' ] )
out_found = False
assert len ( psbt [ ' inputs ' ] ) == utxo_count
outputs = l1 . rpc . listfunds ( ) [ ' outputs ' ]
assert len ( [ x for x in outputs if not x [ ' reserved ' ] ] ) == total_outs - utxo_count
assert len ( [ x for x in outputs if x [ ' reserved ' ] ] ) == utxo_count
total_outs - = utxo_count
saved_input = psbt [ ' tx ' ] [ ' vin ' ] [ 0 ]
# We should have two outputs
for vout in psbt [ ' tx ' ] [ ' vout ' ] :
if vout [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] == addr :
assert vout [ ' value ' ] == sent
out_found = True
assert out_found
# Do it again, but for too many inputs
utxo_count = 12 - utxo_count + 1
sent = Decimal ( ' 0.01 ' ) * ( utxo_count - 1 )
with pytest . raises ( RpcError , match = r " Cannot afford transaction " ) :
reserved = l1 . rpc . reserveinputs ( outputs = [ { addr : Millisatoshi ( amount * ( utxo_count - 1 ) * 1000 ) } ] )
utxo_count - = 1
sent = Decimal ( ' 0.01 ' ) * ( utxo_count - 1 )
reserved = l1 . rpc . reserveinputs ( outputs = [ { addr : Millisatoshi ( amount * ( utxo_count - 1 ) * 1000 ) } ] , feerate = ' 10000perkw ' )
assert reserved [ ' feerate_per_kw ' ] == 10000
psbt = bitcoind . rpc . decodepsbt ( reserved [ ' psbt ' ] )
assert len ( psbt [ ' inputs ' ] ) == utxo_count
outputs = l1 . rpc . listfunds ( ) [ ' outputs ' ]
assert len ( [ x for x in outputs if not x [ ' reserved ' ] ] ) == total_outs - utxo_count == 0
assert len ( [ x for x in outputs if x [ ' reserved ' ] ] ) == 12
# No more available
with pytest . raises ( RpcError , match = r " Cannot afford transaction " ) :
reserved = l1 . rpc . reserveinputs ( outputs = [ { addr : Millisatoshi ( amount * 1 ) } ] , feerate = ' 253perkw ' )
# Unreserve three, from different psbts
unreserve_utxos = [
{
' txid ' : saved_input [ ' txid ' ] ,
' vout ' : saved_input [ ' vout ' ] ,
' sequence ' : saved_input [ ' sequence ' ]
} , {
' txid ' : psbt [ ' tx ' ] [ ' vin ' ] [ 0 ] [ ' txid ' ] ,
' vout ' : psbt [ ' tx ' ] [ ' vin ' ] [ 0 ] [ ' vout ' ] ,
' sequence ' : psbt [ ' tx ' ] [ ' vin ' ] [ 0 ] [ ' sequence ' ]
} , {
' txid ' : psbt [ ' tx ' ] [ ' vin ' ] [ 1 ] [ ' txid ' ] ,
' vout ' : psbt [ ' tx ' ] [ ' vin ' ] [ 1 ] [ ' vout ' ] ,
' sequence ' : psbt [ ' tx ' ] [ ' vin ' ] [ 1 ] [ ' sequence ' ]
} ]
unreserve_psbt = bitcoind . rpc . createpsbt ( unreserve_utxos , [ ] )
unreserved = l1 . rpc . unreserveinputs ( unreserve_psbt )
assert unreserved [ ' all_unreserved ' ]
outputs = l1 . rpc . listfunds ( ) [ ' outputs ' ]
assert len ( [ x for x in outputs if not x [ ' reserved ' ] ] ) == len ( unreserved [ ' outputs ' ] )
for i in range ( len ( unreserved [ ' outputs ' ] ) ) :
un = unreserved [ ' outputs ' ] [ i ]
u_utxo = unreserve_utxos [ i ]
assert un [ ' txid ' ] == u_utxo [ ' txid ' ] and un [ ' vout ' ] == u_utxo [ ' vout ' ] and un [ ' unreserved ' ]
# Try unreserving the same utxos again, plus one that's not included
# We expect this to be a no-op.
unreserve_utxos . append ( { ' txid ' : ' b ' * 64 , ' vout ' : 0 , ' sequence ' : 0 } )
unreserve_psbt = bitcoind . rpc . createpsbt ( unreserve_utxos , [ ] )
unreserved = l1 . rpc . unreserveinputs ( unreserve_psbt )
assert not unreserved [ ' all_unreserved ' ]
for un in unreserved [ ' outputs ' ] :
assert not un [ ' unreserved ' ]
assert len ( [ x for x in l1 . rpc . listfunds ( ) [ ' outputs ' ] if not x [ ' reserved ' ] ] ) == 3
# passing in an empty string should fail
with pytest . raises ( RpcError , match = r " should be a PSBT, not " ) :
l1 . rpc . unreserveinputs ( ' ' )
# reserve one of the utxos that we just unreserved
utxos = [ ]
utxos . append ( saved_input [ ' txid ' ] + " : " + str ( saved_input [ ' vout ' ] ) )
reserved = l1 . rpc . reserveinputs ( [ { addr : Millisatoshi ( amount * 0.5 * 1000 ) } ] , feerate = ' 253perkw ' , utxos = utxos )
assert len ( [ x for x in l1 . rpc . listfunds ( ) [ ' outputs ' ] if not x [ ' reserved ' ] ] ) == 2
psbt = bitcoind . rpc . decodepsbt ( reserved [ ' psbt ' ] )
assert len ( psbt [ ' inputs ' ] ) == 1
vin = psbt [ ' tx ' ] [ ' vin ' ] [ 0 ]
assert vin [ ' txid ' ] == saved_input [ ' txid ' ] and vin [ ' vout ' ] == saved_input [ ' vout ' ]
# reserve them all!
reserved = l1 . rpc . reserveinputs ( [ { addr : ' all ' } ] )
outputs = l1 . rpc . listfunds ( ) [ ' outputs ' ]
assert len ( [ x for x in outputs if not x [ ' reserved ' ] ] ) == 0
assert len ( [ x for x in outputs if x [ ' reserved ' ] ] ) == 12
# FIXME: restart the node, nothing will remain reserved
l1 . restart ( )
assert len ( l1 . rpc . listfunds ( ) [ ' outputs ' ] ) == 12
def test_txsend ( node_factory , bitcoind , chainparams ) :
amount = 1000000
l1 = node_factory . get_node ( random_hsm = True )