From 739d3c7b472ec9c0748c01f4c6fdfb88566607ca Mon Sep 17 00:00:00 2001 From: niftynei Date: Mon, 9 Jan 2023 15:44:26 -0600 Subject: [PATCH] v2 open: if flagged, check that all our inputs are confirmed not amazing, since we'll probably call openchannel_update multiple times per open, but this is the simplest way to confirm that we're not sending unconfirmed outputs to peer. --- lightningd/channel.h | 1 + lightningd/dual_open_control.c | 84 +++++++++++++++++++ ...racted_peer_06_openchannelv2_updates.patch | 20 +++++ wire/peer_wire.csv | 4 +- 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 wire/extracted_peer_06_openchannelv2_updates.patch diff --git a/lightningd/channel.h b/lightningd/channel.h index ae7fb27ea..46118be8e 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -70,6 +70,7 @@ struct open_attempt { struct command *cmd; struct amount_sat funding; const u8 *our_upfront_shutdown_script; + bool req_confirmed_ins; /* First msg to send to dualopend (to make it create channel) */ const u8 *open_msg; diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index e7315dc8b..77324146c 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2562,6 +2562,72 @@ json_openchannel_signed(struct command *cmd, return command_still_pending(cmd); } +struct psbt_validator { + struct command *cmd; + struct channel *channel; + struct wally_psbt *psbt; + size_t next_index; +}; + +static void validate_input_unspent(struct bitcoind *bitcoind, + const struct bitcoin_tx_output *txout, + void *arg) +{ + struct psbt_validator *pv = arg; + u8 *msg; + + /* First time thru bitcoind will be NULL, otherwise is response */ + if (bitcoind && !txout) { + struct bitcoin_outpoint outpoint; + + assert(pv->next_index > 0); + wally_tx_input_get_outpoint(&pv->psbt->tx->inputs[pv->next_index - 1], + &outpoint); + /* Check cmd is still around? */ + was_pending(command_fail(pv->cmd, + FUNDING_PSBT_INVALID, + "Peer has requested only confirmed" + " inputs for this open." + " Input %s is not confirmed.", + type_to_string(tmpctx, + struct bitcoin_outpoint, + &outpoint))); + } + + for (size_t i = pv->next_index; i < pv->psbt->num_inputs; i++) { + struct bitcoin_outpoint outpoint; + u64 serial; + + if (!psbt_get_serial_id(&pv->psbt->inputs[i].unknowns, &serial)) { + was_pending(command_fail(pv->cmd, FUNDING_PSBT_INVALID, + "PSBT input at index %"PRIu64 + " missing serial id", i)); + return; + } + /* Ignore any input that's peer's */ + if (serial % 2 == TX_ACCEPTER) + continue; + + wally_tx_input_get_outpoint(&pv->psbt->tx->inputs[i], + &outpoint); + pv->next_index = i + 1; + + /* Confirm input is in a block */ + bitcoind_getutxout(pv->channel->owner->ld->topology->bitcoind, + &outpoint, + validate_input_unspent, + pv); + + /* Command is still pending */ + return; + } + + pv->channel->open_attempt->cmd = pv->cmd; + + msg = towire_dualopend_psbt_updated(NULL, pv->psbt); + subd_send_msg(pv->channel->owner, take(msg)); + /* Command is still pending */ +} static struct command_result *json_openchannel_update(struct command *cmd, const char *buffer, @@ -2614,6 +2680,24 @@ static struct command_result *json_openchannel_update(struct command *cmd, type_to_string(tmpctx, struct wally_psbt, psbt)); + if (channel->open_attempt->req_confirmed_ins) { + struct psbt_validator *pv; + struct command_result *ret; + + /* Save the info for the next round! */ + pv = tal(cmd, struct psbt_validator); + pv->cmd = cmd; + pv->channel = channel; + pv->next_index = 0; + pv->psbt = psbt; + + /* We might fail/terminate in validate's first call, + * which expects us to be at "command still pending" */ + ret = command_still_pending(cmd); + validate_input_unspent(NULL, NULL, pv); + return ret; + } + channel->open_attempt->cmd = cmd; msg = towire_dualopend_psbt_updated(NULL, psbt); diff --git a/wire/extracted_peer_06_openchannelv2_updates.patch b/wire/extracted_peer_06_openchannelv2_updates.patch new file mode 100644 index 000000000..96a193658 --- /dev/null +++ b/wire/extracted_peer_06_openchannelv2_updates.patch @@ -0,0 +1,20 @@ +--- wire/peer_wire.csv 2023-01-09 12:09:54.439255190 -0600 ++++ - 2023-01-09 12:15:37.608035051 -0600 +@@ -171,6 +173,7 @@ + tlvtype,opening_tlvs,request_funds,3 + tlvdata,opening_tlvs,request_funds,requested_sats,u64, + tlvdata,opening_tlvs,request_funds,blockheight,u32, ++tlvtype,opening_tlvs,require_confirmed_inputs,2 + msgtype,accept_channel2,65 + msgdata,accept_channel2,zerod_channel_id,channel_id, + msgdata,accept_channel2,funding_satoshis,u64, +@@ -190,7 +191,8 @@ + tlvdata,accept_tlvs,upfront_shutdown_script,shutdown_scriptpubkey,byte,... + tlvtype,accept_tlvs,channel_type,1 + tlvdata,accept_tlvs,channel_type,type,byte,... ++tlvtype,accept_tlvs,require_confirmed_inputs,2 +-tlvtype,accept_tlvs,will_fund,2 ++tlvtype,accept_tlvs,will_fund,3 + tlvdata,accept_tlvs,will_fund,signature,signature, + tlvdata,accept_tlvs,will_fund,lease_rates,lease_rates, + subtype,lease_rates diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv index 512818ab7..398a7b435 100644 --- a/wire/peer_wire.csv +++ b/wire/peer_wire.csv @@ -170,6 +170,7 @@ tlvdata,opening_tlvs,channel_type,type,byte,... tlvtype,opening_tlvs,request_funds,3 tlvdata,opening_tlvs,request_funds,requested_sats,u64, tlvdata,opening_tlvs,request_funds,blockheight,u32, +tlvtype,opening_tlvs,require_confirmed_inputs,2 msgtype,accept_channel2,65 msgdata,accept_channel2,zerod_channel_id,channel_id, msgdata,accept_channel2,funding_satoshis,u64, @@ -190,7 +191,8 @@ tlvtype,accept_tlvs,upfront_shutdown_script,0 tlvdata,accept_tlvs,upfront_shutdown_script,shutdown_scriptpubkey,byte,... tlvtype,accept_tlvs,channel_type,1 tlvdata,accept_tlvs,channel_type,type,byte,... -tlvtype,accept_tlvs,will_fund,2 +tlvtype,accept_tlvs,require_confirmed_inputs,2 +tlvtype,accept_tlvs,will_fund,3 tlvdata,accept_tlvs,will_fund,signature,signature, tlvdata,accept_tlvs,will_fund,lease_rates,lease_rates, subtype,lease_rates