dual-fund: add `require_confirmed_inputs` to RBF flows

We now require peers to reaffirm their preference for
`require_confirmed_inputs` when executing an RBF.

Requested-By: @t-bast
This commit is contained in:
niftynei 2023-12-13 16:59:50 -06:00 committed by Christian Decker
parent e72be90606
commit bc98cafe9e
8 changed files with 98 additions and 14 deletions

View File

@ -543,6 +543,13 @@ static void rbf_channel_hook_cb(struct rbf_channel_payload *payload STEALS)
return subd_send_msg(dualopend, take(msg));
}
/* Update the remote's require confirmed preferences */
if (payload->req_confirmed_ins_remote != channel->req_confirmed_ins[REMOTE]) {
channel->req_confirmed_ins[REMOTE] =
payload->req_confirmed_ins_remote;
wallet_channel_save(dualopend->ld->wallet, channel);
}
/* Update channel with new open attempt. */
channel->open_attempt = new_channel_open_attempt(channel);
msg = towire_dualopend_got_rbf_offer_reply(NULL,
@ -2002,7 +2009,8 @@ static void rbf_got_offer(struct subd *dualopend, const u8 *msg)
&payload->our_last_funding,
&payload->funding_feerate_per_kw,
&payload->locktime,
&payload->requested_lease_amt)) {
&payload->requested_lease_amt,
&payload->req_confirmed_ins_remote)) {
channel_internal_error(channel,
"Bad WIRE_DUALOPEND_GOT_RBF_OFFER: %s",
tal_hex(msg, msg));
@ -2027,8 +2035,6 @@ static void rbf_got_offer(struct subd *dualopend, const u8 *msg)
payload->peer_id = channel->peer->id;
payload->feerate_our_max = feerate_max(dualopend->ld, NULL);
payload->feerate_our_min = feerate_min(dualopend->ld, NULL);
payload->req_confirmed_ins_remote =
channel->req_confirmed_ins[REMOTE];
payload->psbt = NULL;
@ -3243,6 +3249,25 @@ done:
tal_free(pv);
}
static void handle_update_require_confirmed(struct subd *dualopend,
const u8 *msg)
{
bool require_confirmed;
struct channel *channel = dualopend->channel;
if (!fromwire_dualopend_update_require_confirmed(msg, &require_confirmed)) {
channel_internal_error(dualopend->channel,
"Bad DUALOPEND_UPDATE_REQUIRE_CONFIRMED: %s",
tal_hex(msg, msg));
return;
}
if (channel->req_confirmed_ins[REMOTE] != require_confirmed) {
channel->req_confirmed_ins[REMOTE] = require_confirmed;
wallet_channel_save(dualopend->ld->wallet, channel);
}
}
static void handle_validate_inputs(struct subd *dualopend,
const u8 *msg)
{
@ -3632,6 +3657,9 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
case WIRE_DUALOPEND_VALIDATE_INPUTS:
handle_validate_inputs(dualopend, msg);
return 0;
case WIRE_DUALOPEND_UPDATE_REQUIRE_CONFIRMED:
handle_update_require_confirmed(dualopend, msg);
return 0;
/* Messages we send */
case WIRE_DUALOPEND_INIT:
case WIRE_DUALOPEND_REINIT:

View File

@ -3564,6 +3564,14 @@ static void rbf_local_start(struct state *state, u8 *msg)
*init_rbf_tlvs->funding_output_contribution
= (s64)tx_state->opener_funding.satoshis; /* Raw: wire conversion */
/* We repeat whatever we used on initial open for requiring confirmed
* inputs */
if (state->require_confirmed_inputs[LOCAL])
init_rbf_tlvs->require_confirmed_inputs =
tal(init_rbf_tlvs, struct tlv_tx_init_rbf_tlvs_require_confirmed_inputs);
msg = towire_tx_init_rbf(tmpctx, &state->channel_id,
tx_state->tx_locktime,
tx_state->feerate_per_kw_funding,
@ -3601,6 +3609,14 @@ static void rbf_local_start(struct state *state, u8 *msg)
} else
tx_state->accepter_funding = state->tx_state->accepter_funding;
/* Set the require_confirmed_inputs to whatever they set here */
if (ack_rbf_tlvs)
state->require_confirmed_inputs[REMOTE] =
ack_rbf_tlvs->require_confirmed_inputs != NULL;
else
/* They have to re-affirm to keep it! */
state->require_confirmed_inputs[REMOTE] = false;
/* Check that total funding doesn't overflow */
if (!amount_sat_add(&total, tx_state->opener_funding,
tx_state->accepter_funding)) {
@ -3672,6 +3688,11 @@ static void rbf_local_start(struct state *state, u8 *msg)
tal_free(state->tx_state);
state->tx_state = tal_steal(state, tx_state);
/* Notify lightningd about require_confirmed state */
msg = towire_dualopend_update_require_confirmed(NULL,
state->require_confirmed_inputs[REMOTE]);
wire_sync_write(REQ_FD, take(msg));
/* We merge with RBF's we've initiated now */
rbf_wrap_up(state, tx_state, total);
tal_free(rbf_ctx);
@ -3735,6 +3756,14 @@ static void rbf_remote_start(struct state *state, const u8 *rbf_msg)
/* Otherwise we use the last known funding amount */
tx_state->opener_funding = state->tx_state->opener_funding;
/* Set the require_confirmed_inputs to whatever they set here */
if (init_rbf_tlvs)
state->require_confirmed_inputs[REMOTE] =
init_rbf_tlvs->require_confirmed_inputs != NULL;
else
/* They have to re-affirm to keep it! */
state->require_confirmed_inputs[REMOTE] = false;
/* Copy over the channel config info -- everything except
* the reserve will be the same */
tx_state->localconf = state->tx_state->localconf;
@ -3757,7 +3786,8 @@ static void rbf_remote_start(struct state *state, const u8 *rbf_msg)
state->tx_state->accepter_funding,
tx_state->feerate_per_kw_funding,
tx_state->tx_locktime,
state->requested_lease);
state->requested_lease,
state->require_confirmed_inputs[REMOTE]);
wire_sync_write(REQ_FD, take(msg));
msg = wire_sync_read(tmpctx, REQ_FD);
@ -3833,6 +3863,11 @@ static void rbf_remote_start(struct state *state, const u8 *rbf_msg)
*ack_rbf_tlvs->funding_output_contribution
= (s64)tx_state->accepter_funding.satoshis; /* Raw: wire conversion */
/* We keep whatever we initially set at open for RBFs */
if (state->require_confirmed_inputs[LOCAL])
ack_rbf_tlvs->require_confirmed_inputs =
tal(ack_rbf_tlvs, struct tlv_tx_ack_rbf_tlvs_require_confirmed_inputs);
msg = towire_tx_ack_rbf(tmpctx, &state->channel_id, ack_rbf_tlvs);
peer_write(state->pps, msg);
peer_billboard(false, "channel rbf: ack sent, waiting for reply");
@ -4177,6 +4212,7 @@ static u8 *handle_master_in(struct state *state)
case WIRE_DUALOPEND_DRY_RUN:
case WIRE_DUALOPEND_VALIDATE_LEASE:
case WIRE_DUALOPEND_VALIDATE_INPUTS:
case WIRE_DUALOPEND_UPDATE_REQUIRE_CONFIRMED:
break;
}
status_failed(STATUS_FAIL_MASTER_IO,

View File

@ -118,12 +118,17 @@ msgdata,dualopend_got_rbf_offer,our_last_funding,amount_sat,
msgdata,dualopend_got_rbf_offer,funding_feerate_per_kw,u32,
msgdata,dualopend_got_rbf_offer,locktime,u32,
msgdata,dualopend_got_rbf_offer,requested_lease,?amount_sat,
msgdata,dualopend_got_rbf_offer,require_confirmed_inputs,bool,
# master->dualopend: reply back with our funding info/contribs
msgtype,dualopend_got_rbf_offer_reply,7505
msgdata,dualopend_got_rbf_offer_reply,our_funding,amount_sat,
msgdata,dualopend_got_rbf_offer_reply,psbt,wally_psbt,
# dualopend->master: update to require_confirmed_inputs preference
msgtype,dualopend_update_require_confirmed,7511
msgdata,dualopend_update_require_confirmed,require_confirmed_inputs,bool,
# dualopend->master: is this a valid RBF candidate transaction?
msgtype,dualopend_rbf_validate,7506
msgdata,dualopend_rbf_validate,proposed_funding_psbt,wally_psbt,

Can't render this file because it has a wrong number of fields in line 16.

View File

@ -31,10 +31,14 @@ static bool equal(const struct tx_ack_rbf *x, const struct tx_ack_rbf *y)
return false;
assert(x->tlvs && y->tlvs);
return memeq(x->tlvs->funding_output_contribution,
tal_bytelen(x->tlvs->funding_output_contribution),
y->tlvs->funding_output_contribution,
tal_bytelen(y->tlvs->funding_output_contribution));
if (!memeq(x->tlvs->funding_output_contribution,
tal_bytelen(x->tlvs->funding_output_contribution),
y->tlvs->funding_output_contribution,
tal_bytelen(y->tlvs->funding_output_contribution)))
return false;
return !!x->tlvs->require_confirmed_inputs ==
!!y->tlvs->require_confirmed_inputs;
}
void run(const u8 *data, size_t size)

View File

@ -36,10 +36,14 @@ static bool equal(const struct tx_init_rbf *x, const struct tx_init_rbf *y)
return false;
assert(x->tlvs && y->tlvs);
return memeq(x->tlvs->funding_output_contribution,
if (!memeq(x->tlvs->funding_output_contribution,
tal_bytelen(x->tlvs->funding_output_contribution),
y->tlvs->funding_output_contribution,
tal_bytelen(y->tlvs->funding_output_contribution));
tal_bytelen(y->tlvs->funding_output_contribution)))
return false;
return !!x->tlvs->require_confirmed_inputs ==
!!y->tlvs->require_confirmed_inputs;
}
void run(const u8 *data, size_t size)

View File

@ -2286,9 +2286,10 @@ void wallet_channel_save(struct wallet *w, struct channel *chan)
" remote_feerate_ppm=?," // 48
" remote_cltv_expiry_delta=?," // 49
" remote_htlc_minimum_msat=?," // 50
" remote_htlc_maximum_msat=?,"
" last_stable_connection=?"
" WHERE id=?"));
" remote_htlc_maximum_msat=?," // 51
" last_stable_connection=?" // 52
" require_confirm_inputs_remote=?" // 53
" WHERE id=?")); // 54
db_bind_u64(stmt, chan->their_shachain.id);
if (chan->scid)
db_bind_short_channel_id(stmt, chan->scid);
@ -2385,6 +2386,8 @@ void wallet_channel_save(struct wallet *w, struct channel *chan)
db_bind_null(stmt);
}
db_bind_u64(stmt, chan->last_stable_connection);
db_bind_int(stmt, chan->req_confirmed_ins[REMOTE]);
db_bind_u64(stmt, chan->dbid);
db_exec_prepared_v2(take(stmt));

View File

@ -1,6 +1,6 @@
--- wire/peer_wire.csv.raw 2023-09-11 13:32:30.677617251 +0930
+++ wire/peer_wire.csv.openchannel2 2023-09-11 13:31:47.906308397 +0930
@@ -37,6 +37,51 @@
@@ -37,6 +37,53 @@
tlvdata,n2,tlv1,amount_msat,tu64,
tlvtype,n2,tlv2,11
tlvdata,n2,tlv2,cltv_expiry,tu32,
@ -40,11 +40,13 @@
+msgdata,tx_init_rbf,tlvs,tx_init_rbf_tlvs,
+tlvtype,tx_init_rbf_tlvs,funding_output_contribution,0
+tlvdata,tx_init_rbf_tlvs,funding_output_contribution,satoshis,s64,
+tlvtype,tx_init_rbf_tlvs,require_confirmed_inputs,2
+msgtype,tx_ack_rbf,73
+msgdata,tx_ack_rbf,channel_id,channel_id,
+msgdata,tx_ack_rbf,tlvs,tx_ack_rbf_tlvs,
+tlvtype,tx_ack_rbf_tlvs,funding_output_contribution,0
+tlvdata,tx_ack_rbf_tlvs,funding_output_contribution,satoshis,s64,
+tlvtype,tx_ack_rbf_tlvs,require_confirmed_inputs,2
+msgtype,tx_abort,74
+msgdata,tx_abort,channel_id,channel_id,
+msgdata,tx_abort,len,u16,

View File

@ -76,11 +76,13 @@ msgdata,tx_init_rbf,feerate,u32,
msgdata,tx_init_rbf,tlvs,tx_init_rbf_tlvs,
tlvtype,tx_init_rbf_tlvs,funding_output_contribution,0
tlvdata,tx_init_rbf_tlvs,funding_output_contribution,satoshis,s64,
tlvtype,tx_init_rbf_tlvs,require_confirmed_inputs,2
msgtype,tx_ack_rbf,73
msgdata,tx_ack_rbf,channel_id,channel_id,
msgdata,tx_ack_rbf,tlvs,tx_ack_rbf_tlvs,
tlvtype,tx_ack_rbf_tlvs,funding_output_contribution,0
tlvdata,tx_ack_rbf_tlvs,funding_output_contribution,satoshis,s64,
tlvtype,tx_ack_rbf_tlvs,require_confirmed_inputs,2
msgtype,tx_abort,74
msgdata,tx_abort,channel_id,channel_id,
msgdata,tx_abort,len,u16,

1 msgtype,init,16
76 msgdata,tx_init_rbf,tlvs,tx_init_rbf_tlvs,
77 tlvtype,tx_init_rbf_tlvs,funding_output_contribution,0
78 tlvdata,tx_init_rbf_tlvs,funding_output_contribution,satoshis,s64,
79 tlvtype,tx_init_rbf_tlvs,require_confirmed_inputs,2
80 msgtype,tx_ack_rbf,73
81 msgdata,tx_ack_rbf,channel_id,channel_id,
82 msgdata,tx_ack_rbf,tlvs,tx_ack_rbf_tlvs,
83 tlvtype,tx_ack_rbf_tlvs,funding_output_contribution,0
84 tlvdata,tx_ack_rbf_tlvs,funding_output_contribution,satoshis,s64,
85 tlvtype,tx_ack_rbf_tlvs,require_confirmed_inputs,2
86 msgtype,tx_abort,74
87 msgdata,tx_abort,channel_id,channel_id,
88 msgdata,tx_abort,len,u16,