df-rbf: start of handling an incoming RBF attempt from peer

A peer init's an RBF, we start handling it
This commit is contained in:
niftynei 2021-01-12 13:09:11 -06:00 committed by Rusty Russell
parent 067f1f2eb7
commit a489f92ee8
5 changed files with 266 additions and 7 deletions

View File

@ -1931,6 +1931,9 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
case WIRE_DUALOPEND_GOT_OFFER:
accepter_got_offer(dualopend, uc, msg);
return 0;
case WIRE_DUALOPEND_GOT_RBF_OFFER:
// FIXME: do this
return 0;
case WIRE_DUALOPEND_PSBT_CHANGED:
if (uc->fc) {
if (!uc->fc->cmd) {
@ -1998,6 +2001,7 @@ static unsigned int dual_opend_msg(struct subd *dualopend,
case WIRE_DUALOPEND_REINIT:
case WIRE_DUALOPEND_OPENER_INIT:
case WIRE_DUALOPEND_GOT_OFFER_REPLY:
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY:
case WIRE_DUALOPEND_FAIL:
case WIRE_DUALOPEND_PSBT_UPDATED:
case WIRE_DUALOPEND_SEND_TX_SIGS:

View File

@ -332,10 +332,7 @@ static void negotiation_failed(struct state *state,
open_error(state, "You gave bad parameters: %s", errmsg);
}
/* FIXME: remove this once used */
void rbf_failed(struct state *state, const char *fmt, ...);
void rbf_failed(struct state *state,
const char *fmt, ...)
static void rbf_failed(struct state *state, const char *fmt, ...)
{
va_list ap;
const char *errmsg;
@ -2351,6 +2348,180 @@ static void opener_start(struct state *state, u8 *msg)
wire_sync_write(REQ_FD, take(msg));
}
static bool update_feerate(struct tx_state *tx_state,
u32 feerate_funding,
u32 last_feerate,
u8 fee_step)
{
u32 feerate = feerate_funding;
/*
* BOLT-487dd4b46aad9b59f7f3480b7bdf15862b52d2f9b #2:
* Each `fee_step` adds 1/4 (rounded down) to the initial
* transaction feerate, i.e. if the initial `feerate_per_kw_funding`
* was 512 satoshis per kiloweight, `fee_step` 1 is
* 512 + 512 / 4 or 640 sat/kw, `fee_step` 2
* is 640 + 640 / 4 or 800 sat/kw.
*/
for (; fee_step > 0; fee_step--)
feerate += feerate / 4;
/* It's possible they sent us a 'bad' feerate step,
* i.e. less than the last one. */
if (feerate <= last_feerate)
return false;
tx_state->feerate_per_kw_funding = feerate;
return true;
}
static void rbf_start(struct state *state, const u8 *rbf_msg)
{
struct channel_id cid;
struct tx_state *tx_state;
char *err_reason;
struct amount_sat total;
enum dualopend_wire msg_type;
u8 fee_step, *msg;
/* We need a new tx_state! */
tx_state = new_tx_state(state);
if (!fromwire_init_rbf(rbf_msg, &cid,
&tx_state->opener_funding,
&tx_state->tx_locktime,
&fee_step))
peer_failed_err(state->pps, &state->channel_id,
"Parsing init_rbf %s",
tal_hex(tmpctx, rbf_msg));
/* Is this the correct channel? */
check_channel_id(state, &cid, &state->channel_id);
peer_billboard(false, "channel rbf: init received from peer");
/* Have you sent us everything we need yet ? */
if (!state->tx_state->remote_funding_sigs_rcvd)
rbf_failed(state, "Last funding attempt not complete:"
" missing your funding tx_sigs");
/* FIXME: should we check for currently in progress? */
/* Copy over the channel config info -- everything except
* the reserve will be the same */
tx_state->localconf = state->tx_state->localconf;
tx_state->remoteconf = state->tx_state->remoteconf;
if (!update_feerate(tx_state,
state->feerate_per_kw_funding,
state->tx_state->feerate_per_kw_funding,
fee_step)) {
rbf_failed(state, "Fee step not greater than last."
" Fee step %d, last feerate %d",
fee_step,
state->tx_state->feerate_per_kw_funding);
return;
}
/* We ask master if this is ok */
msg = towire_dualopend_got_rbf_offer(NULL,
&state->channel_id,
tx_state->opener_funding,
tx_state->feerate_per_kw_funding,
tx_state->tx_locktime);
wire_sync_write(REQ_FD, take(msg));
msg = wire_sync_read(tmpctx, REQ_FD);
if ((msg_type = fromwire_peektype(msg)) == WIRE_DUALOPEND_FAIL) {
if (!fromwire_dualopend_fail(msg, msg, &err_reason))
master_badmsg(msg_type, msg);
rbf_failed(state, "%s", err_reason);
tal_free(tx_state);
return;
}
if (!fromwire_dualopend_got_rbf_offer_reply(state, msg,
&tx_state->accepter_funding,
&tx_state->psbt))
master_badmsg(WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY, msg);
if (!tx_state->psbt)
tx_state->psbt = create_psbt(tx_state, 0, 0,
tx_state->tx_locktime);
/* Check that total funding doesn't overflow */
if (!amount_sat_add(&total, tx_state->opener_funding,
tx_state->accepter_funding)) {
rbf_failed(state, "Amount overflow. Local sats %s. "
"Remote sats %s",
type_to_string(tmpctx, struct amount_sat,
&tx_state->accepter_funding),
type_to_string(tmpctx, struct amount_sat,
&tx_state->opener_funding));
tal_free(tx_state);
return;
}
/* Check that total funding doesn't exceed allowed channel capacity */
/* BOLT #2:
*
* The receiving node MUST fail the channel if:
*...
* - `funding_satoshis` is greater than or equal to 2^24 and the receiver does not support
* `option_support_large_channel`. */
/* We choose to require *negotiation*, not just support! */
if (!feature_negotiated(state->our_features, state->their_features,
OPT_LARGE_CHANNELS)
&& amount_sat_greater(total, chainparams->max_funding)) {
rbf_failed(state, "total funding_satoshis %s too large",
type_to_string(tmpctx, struct amount_sat, &total));
tal_free(tx_state);
return;
}
/* Add all of our inputs/outputs to the changeset */
init_changeset(tx_state, tx_state->psbt);
/* Now that we know the total of the channel, we can set the reserve */
set_reserve(tx_state, total);
if (!check_config_bounds(tmpctx, total,
state->feerate_per_kw_commitment,
state->max_to_self_delay,
state->min_effective_htlc_capacity,
&tx_state->remoteconf,
&tx_state->localconf,
false,
true, /* v2 means we use anchor outputs */
&err_reason)) {
rbf_failed(state, "%s", err_reason);
tal_free(tx_state);
return;
}
msg = towire_ack_rbf(tmpctx, &state->channel_id,
state->our_role == TX_INITIATOR ?
tx_state->opener_funding :
tx_state->accepter_funding);
sync_crypto_write(state->pps, msg);
peer_billboard(false, "channel rbf: ack sent, waiting for reply");
/* This is unused in this flow. We re-use
* the wire method between accepter + opener, so we set it
* to an invalid number, 1 (initiator sets; valid is even) */
tx_state->funding_serial = 1;
/* Now we figure out what the proposed new open transaction is */
if (!run_tx_interactive(state, tx_state,
&tx_state->psbt, TX_ACCEPTER))
return;
/* Find the funding transaction txid */
psbt_txid(NULL, tx_state->psbt, &tx_state->funding_txid, NULL);
// FIXME: same as accepter run now?
}
static u8 *handle_funding_locked(struct state *state, u8 *msg)
{
struct channel_id cid;
@ -2697,9 +2868,11 @@ static u8 *handle_master_in(struct state *state)
case WIRE_DUALOPEND_FAIL:
case WIRE_DUALOPEND_PSBT_UPDATED:
case WIRE_DUALOPEND_GOT_OFFER_REPLY:
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY:
/* Messages we send */
case WIRE_DUALOPEND_GOT_OFFER:
case WIRE_DUALOPEND_GOT_RBF_OFFER:
case WIRE_DUALOPEND_PSBT_CHANGED:
case WIRE_DUALOPEND_COMMIT_RCVD:
case WIRE_DUALOPEND_FUNDING_SIGS:
@ -2759,7 +2932,7 @@ static u8 *handle_peer_in(struct state *state)
handle_peer_shutdown(state, msg);
return NULL;
case WIRE_INIT_RBF:
// FIXME: rbf_start?
rbf_start(state, msg);
return NULL;
/* Otherwise we fall through */
case WIRE_INIT:

View File

@ -98,6 +98,18 @@ msgdata,dualopend_got_offer_reply,psbt,wally_psbt,
msgdata,dualopend_got_offer_reply,shutdown_len,u16,
msgdata,dualopend_got_offer_reply,our_shutdown_scriptpubkey,?u8,shutdown_len
# dualopend->master: they offered a RBF, should we continue?
msgtype,dualopend_got_rbf_offer,7500
msgdata,dualopend_got_rbf_offer,channel_id,channel_id,
msgdata,dualopend_got_rbf_offer,opener_funding,amount_sat,
msgdata,dualopend_got_rbf_offer,funding_feerate_per_kw,u32,
msgdata,dualopend_got_rbf_offer,locktime,u32,
# master->dualopend: reply back with our funding info/contribs
msgtype,dualopend_got_rbf_offer_reply,7505
msgdata,dualopend_got_rbf_offer_reply,accepter_funding,amount_sat,
msgdata,dualopend_got_rbf_offer_reply,psbt,wally_psbt,
# dualopend->master: ready to commit channel open to database and
# get some signatures for the funding_tx.
msgtype,dualopend_commit_rcvd,7007

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

View File

@ -24,6 +24,8 @@ const char *dualopend_wire_name(int e)
case WIRE_DUALOPEND_REINIT: return "WIRE_DUALOPEND_REINIT";
case WIRE_DUALOPEND_GOT_OFFER: return "WIRE_DUALOPEND_GOT_OFFER";
case WIRE_DUALOPEND_GOT_OFFER_REPLY: return "WIRE_DUALOPEND_GOT_OFFER_REPLY";
case WIRE_DUALOPEND_GOT_RBF_OFFER: return "WIRE_DUALOPEND_GOT_RBF_OFFER";
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY: return "WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY";
case WIRE_DUALOPEND_COMMIT_RCVD: return "WIRE_DUALOPEND_COMMIT_RCVD";
case WIRE_DUALOPEND_PSBT_CHANGED: return "WIRE_DUALOPEND_PSBT_CHANGED";
case WIRE_DUALOPEND_PSBT_UPDATED: return "WIRE_DUALOPEND_PSBT_UPDATED";
@ -56,6 +58,8 @@ bool dualopend_wire_is_defined(u16 type)
case WIRE_DUALOPEND_REINIT:;
case WIRE_DUALOPEND_GOT_OFFER:;
case WIRE_DUALOPEND_GOT_OFFER_REPLY:;
case WIRE_DUALOPEND_GOT_RBF_OFFER:;
case WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY:;
case WIRE_DUALOPEND_COMMIT_RCVD:;
case WIRE_DUALOPEND_PSBT_CHANGED:;
case WIRE_DUALOPEND_PSBT_UPDATED:;
@ -353,6 +357,58 @@ bool fromwire_dualopend_got_offer_reply(const tal_t *ctx, const void *p, struct
return cursor != NULL;
}
/* WIRE: DUALOPEND_GOT_RBF_OFFER */
/* dualopend->master: they offered a RBF */
u8 *towire_dualopend_got_rbf_offer(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat opener_funding, u32 funding_feerate_per_kw, u32 locktime)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_DUALOPEND_GOT_RBF_OFFER);
towire_channel_id(&p, channel_id);
towire_amount_sat(&p, opener_funding);
towire_u32(&p, funding_feerate_per_kw);
towire_u32(&p, locktime);
return memcheck(p, tal_count(p));
}
bool fromwire_dualopend_got_rbf_offer(const void *p, struct channel_id *channel_id, struct amount_sat *opener_funding, u32 *funding_feerate_per_kw, u32 *locktime)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_GOT_RBF_OFFER)
return false;
fromwire_channel_id(&cursor, &plen, channel_id);
*opener_funding = fromwire_amount_sat(&cursor, &plen);
*funding_feerate_per_kw = fromwire_u32(&cursor, &plen);
*locktime = fromwire_u32(&cursor, &plen);
return cursor != NULL;
}
/* WIRE: DUALOPEND_GOT_RBF_OFFER_REPLY */
/* master->dualopend: reply back with our funding info/contribs */
u8 *towire_dualopend_got_rbf_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt)
{
u8 *p = tal_arr(ctx, u8, 0);
towire_u16(&p, WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY);
towire_amount_sat(&p, accepter_funding);
towire_wally_psbt(&p, psbt);
return memcheck(p, tal_count(p));
}
bool fromwire_dualopend_got_rbf_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt)
{
const u8 *cursor = p;
size_t plen = tal_count(p);
if (fromwire_u16(&cursor, &plen) != WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY)
return false;
*accepter_funding = fromwire_amount_sat(&cursor, &plen);
*psbt = fromwire_wally_psbt(ctx, &cursor, &plen);
return cursor != NULL;
}
/* WIRE: DUALOPEND_COMMIT_RCVD */
/* dualopend->master: ready to commit channel open to database and */
/* get some signatures for the funding_tx. */
@ -862,4 +918,4 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak)
*leak = fromwire_bool(&cursor, &plen);
return cursor != NULL;
}
// SHA256STAMP:6e149f437eae7fde2f891bbb7f36903fa105179d9a97cd1b765d34641c0839ce
// SHA256STAMP:d9a02c4575a71748388be74b56f3fe333147557aa715e6735b9a1c35a72c7cd5

View File

@ -27,6 +27,10 @@ enum dualopend_wire {
WIRE_DUALOPEND_GOT_OFFER = 7005,
/* master->dualopend: reply back with our first funding info/contribs */
WIRE_DUALOPEND_GOT_OFFER_REPLY = 7105,
/* dualopend->master: they offered a RBF */
WIRE_DUALOPEND_GOT_RBF_OFFER = 7500,
/* master->dualopend: reply back with our funding info/contribs */
WIRE_DUALOPEND_GOT_RBF_OFFER_REPLY = 7505,
/* dualopend->master: ready to commit channel open to database and */
/* get some signatures for the funding_tx. */
WIRE_DUALOPEND_COMMIT_RCVD = 7007,
@ -98,6 +102,16 @@ bool fromwire_dualopend_got_offer(const tal_t *ctx, const void *p, struct channe
u8 *towire_dualopend_got_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, u32 feerate_funding, const struct wally_psbt *psbt, const u8 *our_shutdown_scriptpubkey);
bool fromwire_dualopend_got_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, u32 *feerate_funding, struct wally_psbt **psbt, u8 **our_shutdown_scriptpubkey);
/* WIRE: DUALOPEND_GOT_RBF_OFFER */
/* dualopend->master: they offered a RBF */
u8 *towire_dualopend_got_rbf_offer(const tal_t *ctx, const struct channel_id *channel_id, struct amount_sat opener_funding, u32 funding_feerate_per_kw, u32 locktime);
bool fromwire_dualopend_got_rbf_offer(const void *p, struct channel_id *channel_id, struct amount_sat *opener_funding, u32 *funding_feerate_per_kw, u32 *locktime);
/* WIRE: DUALOPEND_GOT_RBF_OFFER_REPLY */
/* master->dualopend: reply back with our funding info/contribs */
u8 *towire_dualopend_got_rbf_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt);
bool fromwire_dualopend_got_rbf_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt);
/* WIRE: DUALOPEND_COMMIT_RCVD */
/* dualopend->master: ready to commit channel open to database and */
/* get some signatures for the funding_tx. */
@ -195,4 +209,4 @@ bool fromwire_dualopend_dev_memleak_reply(const void *p, bool *leak);
#endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */
// SHA256STAMP:6e149f437eae7fde2f891bbb7f36903fa105179d9a97cd1b765d34641c0839ce
// SHA256STAMP:d9a02c4575a71748388be74b56f3fe333147557aa715e6735b9a1c35a72c7cd5