From 498401457843aceeea7b952209bafba1a66d8337 Mon Sep 17 00:00:00 2001 From: niftynei Date: Thu, 11 Aug 2022 16:29:58 -0500 Subject: [PATCH] signpsbt: add utxo info to inputs If you build a PSBT externally from CLN and attempt to sign for the output, we would crash. Now we don't crash. Changelog-Changed: JSON-RPC: `signpsbt` will now add redeemscript + witness-utxo to the PSBT for an input that we can sign for, before signing it. Fixes #5499 ? --- tests/test_wallet.py | 29 +++++++++++++++++++++++++++++ wallet/walletrpc.c | 27 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/tests/test_wallet.py b/tests/test_wallet.py index ac5fd0e7d..a093c390f 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -695,6 +695,35 @@ def test_utxopsbt(node_factory, bitcoind, chainparams): reservedok=True) +def test_sign_external_psbt(node_factory, bitcoind, chainparams): + """ + A PSBT w/ one of our inputs should be signable (we can fill + in the required UTXO data). + """ + l1 = node_factory.get_node(feerates=(7500, 7500, 7500, 7500)) + amount = 1000000 + total_outs = 4 + + # 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) + + # Build a PSBT using all our inputs, externally + inputs = [] + for inp in l1.rpc.listfunds()['outputs']: + inputs.append({'txid': inp['txid'], 'vout': inp['output']}) + addr = l1.rpc.newaddr()['bech32'] + psbt = bitcoind.rpc.createpsbt(inputs, [{addr: (amount * 3) / 10**8}]) + + l1.rpc.reserveinputs(psbt) + l1.rpc.signpsbt(psbt) + + def test_sign_and_send_psbt(node_factory, bitcoind, chainparams): """ Tests for the sign + send psbt RPCs diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 809bd8ef4..47f38e13d 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -648,6 +648,33 @@ static struct command_result *match_psbt_inputs_to_utxos(struct command *cmd, "Aborting PSBT signing. UTXO %s is not reserved", type_to_string(tmpctx, struct bitcoin_outpoint, &utxo->outpoint)); + + /* If the psbt doesn't have the UTXO info yet, add it. + * We only add the witness_utxo for this */ + if (!psbt->inputs[i].utxo && !psbt->inputs[i].witness_utxo) { + u8 *scriptPubKey; + + if (utxo->is_p2sh) { + struct pubkey key; + u8 *redeemscript; + int wally_err; + + bip32_pubkey(cmd->ld->wallet->bip32_base, &key, + utxo->keyindex); + redeemscript = bitcoin_redeem_p2sh_p2wpkh(tmpctx, &key); + scriptPubKey = scriptpubkey_p2sh(tmpctx, redeemscript); + + tal_wally_start(); + wally_err = wally_psbt_input_set_redeem_script(&psbt->inputs[i], + redeemscript, + tal_bytelen(redeemscript)); + assert(wally_err == WALLY_OK); + tal_wally_end(psbt); + } else + scriptPubKey = utxo->scriptPubkey; + + psbt_input_set_wit_utxo(psbt, i, scriptPubKey, utxo->amount); + } tal_arr_expand(utxos, utxo); }