mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 22:45:27 +01:00
pytest: restore test_sign_and_send_psbt.
It uses reservations heavily, and assumed we generated change, etc. It's now a simpler test, in many ways. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
31d7e013bd
commit
e85c895c5b
1 changed files with 44 additions and 41 deletions
|
@ -544,7 +544,6 @@ def test_fundpsbt(node_factory, bitcoind, chainparams):
|
|||
l1.rpc.fundpsbt(amount // 2, feerate)
|
||||
|
||||
|
||||
@pytest.mark.xfail(strict=True)
|
||||
def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
|
||||
"""
|
||||
Tests for the sign + send psbt RPCs
|
||||
|
@ -566,53 +565,58 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
|
|||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == total_outs)
|
||||
|
||||
# Make a PSBT out of our inputs
|
||||
reserved = l1.rpc.reserveinputs(outputs=[{addr: Millisatoshi(3 * amount * 1000)}])
|
||||
# Make a PSBT out of our inputs (FIXME: satoshi amount should include fees!)
|
||||
funding = l1.rpc.fundpsbt(satoshi=Millisatoshi(3 * amount * 1000),
|
||||
feerate=7500,
|
||||
reserve=True)
|
||||
assert len([x for x in l1.rpc.listfunds()['outputs'] if x['reserved']]) == 4
|
||||
psbt = bitcoind.rpc.decodepsbt(reserved['psbt'])
|
||||
psbt = bitcoind.rpc.decodepsbt(funding['psbt'])
|
||||
saved_input = psbt['tx']['vin'][0]
|
||||
|
||||
# Go ahead and unreserve the UTXOs, we'll use a smaller
|
||||
# set of them to create a second PSBT that we'll attempt to sign
|
||||
# and broadcast (to disastrous results)
|
||||
l1.rpc.unreserveinputs(reserved['psbt'])
|
||||
l1.rpc.unreserveinputs(funding['psbt'])
|
||||
|
||||
# Re-reserve one of the utxos we just unreserved
|
||||
utxos = []
|
||||
utxos.append(saved_input['txid'] + ":" + str(saved_input['vout']))
|
||||
second_reservation = l1.rpc.reserveinputs([{addr: Millisatoshi(amount * 0.5 * 1000)}], feerate='253perkw', utxos=utxos)
|
||||
psbt = bitcoind.rpc.createpsbt([{'txid': saved_input['txid'],
|
||||
'vout': saved_input['vout']}], [])
|
||||
l1.rpc.reserveinputs(psbt)
|
||||
|
||||
# We require the utxos be reserved before signing them
|
||||
with pytest.raises(RpcError, match=r"Aborting PSBT signing. UTXO .* is not reserved"):
|
||||
l1.rpc.signpsbt(reserved['psbt'])['signed_psbt']
|
||||
l1.rpc.signpsbt(funding['psbt'])['signed_psbt']
|
||||
|
||||
# Now we unreserve the singleton, so we can reserve it again
|
||||
l1.rpc.unreserveinputs(second_reservation['psbt'])
|
||||
l1.rpc.unreserveinputs(psbt)
|
||||
|
||||
# Now add an output.
|
||||
output_pbst = bitcoind.rpc.createpsbt([],
|
||||
[{addr: 3 * amount / 10**8}])
|
||||
fullpsbt = bitcoind.rpc.joinpsbts([funding['psbt'], output_pbst])
|
||||
|
||||
# We re-reserve the first set...
|
||||
utxos = []
|
||||
for vin in psbt['tx']['vin']:
|
||||
utxos.append(vin['txid'] + ':' + str(vin['vout']))
|
||||
reserved = l1.rpc.reserveinputs(outputs=[{addr: Millisatoshi(3 * amount * 1000)}], utxos=utxos)
|
||||
l1.rpc.reserveinputs(fullpsbt)
|
||||
|
||||
# Sign + send the PSBT we've created
|
||||
signed_psbt = l1.rpc.signpsbt(reserved['psbt'])['signed_psbt']
|
||||
signed_psbt = l1.rpc.signpsbt(fullpsbt)['signed_psbt']
|
||||
broadcast_tx = l1.rpc.sendpsbt(signed_psbt)
|
||||
|
||||
# Check that it was broadcast successfully
|
||||
l1.daemon.wait_for_log(r'sendrawtx exit 0 .* sendrawtransaction {}'.format(broadcast_tx['tx']))
|
||||
bitcoind.generate_block(1)
|
||||
|
||||
# We expect a change output to be added to the wallet
|
||||
expected_outs = total_outs - 4 + 1
|
||||
# We didn't add a change output.
|
||||
expected_outs = total_outs - 4
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == expected_outs)
|
||||
|
||||
# Let's try *sending* a PSBT that can't be finalized (it's unsigned)
|
||||
with pytest.raises(RpcError, match=r"PSBT not finalizeable"):
|
||||
l1.rpc.sendpsbt(second_reservation['psbt'])
|
||||
l1.rpc.sendpsbt(fullpsbt)
|
||||
|
||||
# Now we try signing a PSBT with an output that's already been spent
|
||||
with pytest.raises(RpcError, match=r"Aborting PSBT signing. UTXO {} is not reserved".format(utxos[0])):
|
||||
l1.rpc.signpsbt(second_reservation['psbt'])
|
||||
with pytest.raises(RpcError, match=r"Aborting PSBT signing. UTXO .* is not reserved"):
|
||||
l1.rpc.signpsbt(fullpsbt)
|
||||
|
||||
# Queue up another node, to make some PSBTs for us
|
||||
for i in range(total_outs // 2):
|
||||
|
@ -623,15 +627,22 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
|
|||
# Create a PSBT using L2
|
||||
bitcoind.generate_block(1)
|
||||
wait_for(lambda: len(l2.rpc.listfunds()['outputs']) == total_outs)
|
||||
l2_reserved = l2.rpc.reserveinputs(outputs=[{addr: Millisatoshi(3 * amount * 1000)}])
|
||||
l2_funding = l2.rpc.fundpsbt(satoshi=Millisatoshi(3 * amount * 1000),
|
||||
feerate=7500,
|
||||
reserve=True)
|
||||
|
||||
# Try to get L1 to sign it
|
||||
with pytest.raises(RpcError, match=r"No wallet inputs to sign"):
|
||||
l1.rpc.signpsbt(l2_reserved['psbt'])
|
||||
l1.rpc.signpsbt(l2_funding['psbt'])
|
||||
|
||||
# Add some of our own PSBT inputs to it
|
||||
l1_reserved = l1.rpc.reserveinputs(outputs=[{addr: Millisatoshi(3 * amount * 1000)}])
|
||||
joint_psbt = bitcoind.rpc.joinpsbts([l1_reserved['psbt'], l2_reserved['psbt']])
|
||||
l1_funding = l1.rpc.fundpsbt(satoshi=Millisatoshi(3 * amount * 1000),
|
||||
feerate=7500,
|
||||
reserve=True)
|
||||
|
||||
# Join and add an output
|
||||
joint_psbt = bitcoind.rpc.joinpsbts([l1_funding['psbt'], l2_funding['psbt'],
|
||||
output_pbst])
|
||||
|
||||
half_signed_psbt = l1.rpc.signpsbt(joint_psbt)['signed_psbt']
|
||||
totally_signed = l2.rpc.signpsbt(half_signed_psbt)['signed_psbt']
|
||||
|
@ -640,8 +651,11 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
|
|||
l1.daemon.wait_for_log(r'sendrawtx exit 0 .* sendrawtransaction {}'.format(broadcast_tx['tx']))
|
||||
|
||||
# Send a PSBT that's not ours
|
||||
l2_reserved = l2.rpc.reserveinputs(outputs=[{addr: Millisatoshi(3 * amount * 1000)}])
|
||||
l2_signed_psbt = l2.rpc.signpsbt(l2_reserved['psbt'])['signed_psbt']
|
||||
l2_funding = l2.rpc.fundpsbt(satoshi=Millisatoshi(3 * amount * 1000),
|
||||
feerate=7500,
|
||||
reserve=True)
|
||||
psbt = bitcoind.rpc.joinpsbts([l2_funding['psbt'], output_pbst])
|
||||
l2_signed_psbt = l2.rpc.signpsbt(psbt)['signed_psbt']
|
||||
l1.rpc.sendpsbt(l2_signed_psbt)
|
||||
|
||||
# Re-try sending the same tx?
|
||||
|
@ -658,7 +672,7 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
|
|||
l1.rpc.sendpsbt('')
|
||||
|
||||
# Try a modified (invalid) PSBT string
|
||||
modded_psbt = l2_reserved['psbt'][:-3] + 'A' + l2_reserved['psbt'][-3:]
|
||||
modded_psbt = psbt[:-3] + 'A' + psbt[-3:]
|
||||
with pytest.raises(RpcError, match=r"should be a PSBT, not"):
|
||||
l1.rpc.signpsbt(modded_psbt)
|
||||
|
||||
|
@ -679,27 +693,16 @@ def test_sign_and_send_psbt(node_factory, bitcoind, chainparams):
|
|||
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
|
||||
# Nicely splits out withdrawals and chain fees, because it's all our tx
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 988255000, 'tag': 'withdrawal'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 3000000000, 'tag': 'withdrawal'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 11745000, 'tag': 'chain_fees'},
|
||||
{'type': 'chain_mvt', 'credit': 988255000, 'debit': 0, 'tag': 'deposit'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 1000000000, 'tag': 'chain_fees'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'spend_track'},
|
||||
# Note that this is technically wrong since we paid 11745sat in fees
|
||||
# but since it includes inputs / outputs from a second node, we can't
|
||||
# do proper acccounting for it.
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 4000000000, 'tag': 'withdrawal'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 0, 'tag': 'chain_fees'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 3000000000, 'tag': 'withdrawal'},
|
||||
{'type': 'chain_mvt', 'credit': 0, 'debit': 1000000000, 'tag': 'chain_fees'},
|
||||
]
|
||||
|
||||
if chainparams['elements']:
|
||||
wallet_coin_mvts.append({'type': 'chain_mvt', 'credit': 984625000, 'debit': 0, 'tag': 'deposit'})
|
||||
else:
|
||||
wallet_coin_mvts.append({'type': 'chain_mvt', 'credit': 988285000, 'debit': 0, 'tag': 'deposit'})
|
||||
|
||||
check_coin_moves(l1, 'wallet', wallet_coin_mvts, chainparams)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue