From d8ba3ebde1262dab21778d5c761f4e79215657b2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 3 Sep 2021 19:59:12 +0930 Subject: [PATCH] closingd: allow higher closing fee if anchor_outputs. This follows https://github.com/lightningnetwork/lightning-rfc/pull/847. For anchor_outputs, we pass down a max_feerate to closingd, and set the fee ceiling to MAX. It uses that to estimate the desired closing fee. Signed-off-by: Rusty Russell Changelog-EXPERIMENTAL: Anchor output mutual close allow a fee higher than the final commitment transaction (as per lightning-rfc #847) --- closingd/closingd.c | 90 +++++++++++++++++++++++++----------- closingd/closingd_wire.csv | 1 + closingd/closingd_wiregen.c | 18 ++++++-- closingd/closingd_wiregen.h | 6 +-- lightningd/closing_control.c | 19 +++++++- 5 files changed, 98 insertions(+), 36 deletions(-) diff --git a/closingd/closingd.c b/closingd/closingd.c index 65c4a8664660..ca038fbff0ba 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -584,16 +584,59 @@ static size_t closing_tx_weight_estimate(u8 *scriptpubkey[NUM_SIDES], static void calc_fee_bounds(size_t expected_weight, u32 min_feerate, u32 desired_feerate, - struct amount_sat maxfee, + u32 *max_feerate, + struct amount_sat commitment_fee, + struct amount_sat funding, + enum side opener, struct amount_sat *minfee, - struct amount_sat *desiredfee) + struct amount_sat *desiredfee, + struct amount_sat *maxfee) { *minfee = amount_tx_fee(min_feerate, expected_weight); *desiredfee = amount_tx_fee(desired_feerate, expected_weight); + /* BOLT-closing-fee_range #2: + * - if it is not the funder: + * - SHOULD set `max_fee_satoshis` to at least the `max_fee_satoshis` + * received + *... + * Note that the non-funder is not paying the fee, so there is + * no reason for it to have a maximum feerate. + */ + if (opener == REMOTE) { + *maxfee = funding; + /* BOLT-closing-fee_range #2: + * - If the channel does not use `option_anchor_outputs`: + * - MUST set `fee_satoshis` less than or equal to the base fee of + * the final commitment transaction, as calculated in + * [BOLT #3](03-transactions.md#fee-calculation). + */ + } else if (max_feerate) { + *maxfee = amount_tx_fee(*max_feerate, expected_weight); + + status_debug("deriving max fee from rate %u -> %s (not %s)", + *max_feerate, + type_to_string(tmpctx, struct amount_sat, maxfee), + type_to_string(tmpctx, struct amount_sat, &commitment_fee)); + + /* option_anchor_outputs sets commitment_fee to max, so this + * doesn't do anything */ + if (amount_sat_greater(*maxfee, commitment_fee)) { + status_unusual("Maximum feerate %u would give fee %s:" + " we must limit it to the final commitment fee %s", + *max_feerate, + type_to_string(tmpctx, struct amount_sat, + maxfee), + type_to_string(tmpctx, struct amount_sat, + &commitment_fee)); + *maxfee = commitment_fee; + } + } else + *maxfee = commitment_fee; + /* Can't exceed maxfee. */ - if (amount_sat_greater(*minfee, maxfee)) - *minfee = maxfee; + if (amount_sat_greater(*minfee, *maxfee)) + *minfee = *maxfee; if (amount_sat_less(*desiredfee, *minfee)) { status_unusual("Our ideal fee is %s (%u sats/perkw)," @@ -603,20 +646,20 @@ static void calc_fee_bounds(size_t expected_weight, type_to_string(tmpctx, struct amount_sat, minfee)); *desiredfee = *minfee; } - if (amount_sat_greater(*desiredfee, maxfee)) { + if (amount_sat_greater(*desiredfee, *maxfee)) { status_unusual("Our ideal fee is %s (%u sats/perkw)," " but our maximum is %s: using that", type_to_string(tmpctx, struct amount_sat, desiredfee), desired_feerate, - type_to_string(tmpctx, struct amount_sat, &maxfee)); - *desiredfee = maxfee; + type_to_string(tmpctx, struct amount_sat, maxfee)); + *desiredfee = *maxfee; } status_debug("Expected closing weight = %zu, fee %s (min %s, max %s)", expected_weight, type_to_string(tmpctx, struct amount_sat, desiredfee), type_to_string(tmpctx, struct amount_sat, minfee), - type_to_string(tmpctx, struct amount_sat, &maxfee)); + type_to_string(tmpctx, struct amount_sat, maxfee)); } /* We've received one offer; if we're opener, that means we've already sent one @@ -802,8 +845,9 @@ int main(int argc, char *argv[]) u16 funding_txout; struct amount_sat funding, out[NUM_SIDES]; struct amount_sat our_dust_limit; - struct amount_sat min_fee_to_accept, commitment_fee, offer[NUM_SIDES]; - u32 min_feerate, initial_feerate; + struct amount_sat min_fee_to_accept, commitment_fee, offer[NUM_SIDES], + max_fee_to_accept; + u32 min_feerate, initial_feerate, *max_feerate; struct feerange feerange; enum side opener; u8 *scriptpubkey[NUM_SIDES], *funding_wscript; @@ -833,7 +877,7 @@ int main(int argc, char *argv[]) &out[LOCAL], &out[REMOTE], &our_dust_limit, - &min_feerate, &initial_feerate, + &min_feerate, &initial_feerate, &max_feerate, &commitment_fee, &scriptpubkey[LOCAL], &scriptpubkey[REMOTE], @@ -855,8 +899,9 @@ int main(int argc, char *argv[]) calc_fee_bounds(closing_tx_weight_estimate(scriptpubkey, funding_wscript, out, funding, our_dust_limit), - min_feerate, initial_feerate, commitment_fee, - &min_fee_to_accept, &offer[LOCAL]); + min_feerate, initial_feerate, max_feerate, + commitment_fee, funding, opener, + &min_fee_to_accept, &offer[LOCAL], &max_fee_to_accept); /* Write values into tlv for updated closing fee neg */ their_feerange = tal(ctx, struct tlv_closing_signed_tlvs_fee_range *); @@ -865,19 +910,7 @@ int main(int argc, char *argv[]) if (use_quickclose) { our_feerange = tal(ctx, struct tlv_closing_signed_tlvs_fee_range); our_feerange->min_fee_satoshis = min_fee_to_accept; - - /* BOLT-closing-fee_range #2: - * - if it is not the funder: - * - SHOULD set `max_fee_satoshis` to at least the - * `max_fee_satoshis` received - *... - * Note that the non-funder is not paying the fee, so there is - * no reason for it to have a maximum feerate. - */ - if (opener == REMOTE) - our_feerange->max_fee_satoshis = funding; - else - our_feerange->max_fee_satoshis = commitment_fee; + our_feerange->max_fee_satoshis = max_fee_to_accept; } else our_feerange = NULL; @@ -907,7 +940,7 @@ int main(int argc, char *argv[]) "Negotiating closing fee between %s and %s satoshi (ideal %s) " "using step %s", type_to_string(tmpctx, struct amount_sat, &min_fee_to_accept), - type_to_string(tmpctx, struct amount_sat, &commitment_fee), + type_to_string(tmpctx, struct amount_sat, &max_fee_to_accept), type_to_string(tmpctx, struct amount_sat, &offer[LOCAL]), fee_negotiation_step_str); @@ -970,7 +1003,7 @@ int main(int argc, char *argv[]) } /* Now we have first two points, we can init fee range. */ - init_feerange(&feerange, commitment_fee, offer); + init_feerange(&feerange, max_fee_to_accept, offer); /* Apply (and check) opener offer now. */ adjust_feerange(&feerange, offer[opener], opener); @@ -1029,6 +1062,7 @@ int main(int argc, char *argv[]) tal_free(wrong_funding); tal_free(our_feerange); tal_free(their_feerange); + tal_free(max_feerate); closing_dev_memleak(ctx, scriptpubkey, funding_wscript); #endif diff --git a/closingd/closingd_wire.csv b/closingd/closingd_wire.csv index 1cf2c11bcda6..b1e5ea8d47b2 100644 --- a/closingd/closingd_wire.csv +++ b/closingd/closingd_wire.csv @@ -19,6 +19,7 @@ msgdata,closingd_init,remote_sat,amount_sat, msgdata,closingd_init,our_dust_limit,amount_sat, msgdata,closingd_init,min_feerate_perksipa,u32, msgdata,closingd_init,preferred_feerate_perksipa,u32, +msgdata,closingd_init,max_feerate_perksipa,?u32, msgdata,closingd_init,fee_limit_satoshi,amount_sat, msgdata,closingd_init,local_scriptpubkey_len,u16, msgdata,closingd_init,local_scriptpubkey,u8,local_scriptpubkey_len diff --git a/closingd/closingd_wiregen.c b/closingd/closingd_wiregen.c index 134cceda1e55..c8c8b6c3ec9e 100644 --- a/closingd/closingd_wiregen.c +++ b/closingd/closingd_wiregen.c @@ -48,7 +48,7 @@ bool closingd_wire_is_defined(u16 type) /* WIRE: CLOSINGD_INIT */ /* Begin! (passes peer fd */ -u8 *towire_closingd_init(const tal_t *ctx, const struct chainparams *chainparams, const struct per_peer_state *pps, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, const struct pubkey *local_fundingkey, const struct pubkey *remote_fundingkey, enum side opener, struct amount_sat local_sat, struct amount_sat remote_sat, struct amount_sat our_dust_limit, u32 min_feerate_perksipa, u32 preferred_feerate_perksipa, struct amount_sat fee_limit_satoshi, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, u64 fee_negotiation_step, u8 fee_negotiation_step_unit, bool use_quickclose, bool dev_fast_gossip, const struct bitcoin_outpoint *shutdown_wrong_funding) +u8 *towire_closingd_init(const tal_t *ctx, const struct chainparams *chainparams, const struct per_peer_state *pps, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, const struct pubkey *local_fundingkey, const struct pubkey *remote_fundingkey, enum side opener, struct amount_sat local_sat, struct amount_sat remote_sat, struct amount_sat our_dust_limit, u32 min_feerate_perksipa, u32 preferred_feerate_perksipa, u32 *max_feerate_perksipa, struct amount_sat fee_limit_satoshi, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, u64 fee_negotiation_step, u8 fee_negotiation_step_unit, bool use_quickclose, bool dev_fast_gossip, const struct bitcoin_outpoint *shutdown_wrong_funding) { u16 local_scriptpubkey_len = tal_count(local_scriptpubkey); u16 remote_scriptpubkey_len = tal_count(remote_scriptpubkey); @@ -69,6 +69,12 @@ u8 *towire_closingd_init(const tal_t *ctx, const struct chainparams *chainparams towire_amount_sat(&p, our_dust_limit); towire_u32(&p, min_feerate_perksipa); towire_u32(&p, preferred_feerate_perksipa); + if (!max_feerate_perksipa) + towire_bool(&p, false); + else { + towire_bool(&p, true); + towire_u32(&p, *max_feerate_perksipa); + } towire_amount_sat(&p, fee_limit_satoshi); towire_u16(&p, local_scriptpubkey_len); towire_u8_array(&p, local_scriptpubkey, local_scriptpubkey_len); @@ -87,7 +93,7 @@ u8 *towire_closingd_init(const tal_t *ctx, const struct chainparams *chainparams return memcheck(p, tal_count(p)); } -bool fromwire_closingd_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct per_peer_state **pps, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, struct pubkey *local_fundingkey, struct pubkey *remote_fundingkey, enum side *opener, struct amount_sat *local_sat, struct amount_sat *remote_sat, struct amount_sat *our_dust_limit, u32 *min_feerate_perksipa, u32 *preferred_feerate_perksipa, struct amount_sat *fee_limit_satoshi, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, u64 *fee_negotiation_step, u8 *fee_negotiation_step_unit, bool *use_quickclose, bool *dev_fast_gossip, struct bitcoin_outpoint **shutdown_wrong_funding) +bool fromwire_closingd_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct per_peer_state **pps, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, struct pubkey *local_fundingkey, struct pubkey *remote_fundingkey, enum side *opener, struct amount_sat *local_sat, struct amount_sat *remote_sat, struct amount_sat *our_dust_limit, u32 *min_feerate_perksipa, u32 *preferred_feerate_perksipa, u32 **max_feerate_perksipa, struct amount_sat *fee_limit_satoshi, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, u64 *fee_negotiation_step, u8 *fee_negotiation_step_unit, bool *use_quickclose, bool *dev_fast_gossip, struct bitcoin_outpoint **shutdown_wrong_funding) { u16 local_scriptpubkey_len; u16 remote_scriptpubkey_len; @@ -111,6 +117,12 @@ bool fromwire_closingd_init(const tal_t *ctx, const void *p, const struct chainp *our_dust_limit = fromwire_amount_sat(&cursor, &plen); *min_feerate_perksipa = fromwire_u32(&cursor, &plen); *preferred_feerate_perksipa = fromwire_u32(&cursor, &plen); + if (!fromwire_bool(&cursor, &plen)) + *max_feerate_perksipa = NULL; + else { + *max_feerate_perksipa = tal(ctx, u32); + **max_feerate_perksipa = fromwire_u32(&cursor, &plen); + } *fee_limit_satoshi = fromwire_amount_sat(&cursor, &plen); local_scriptpubkey_len = fromwire_u16(&cursor, &plen); // 2nd case local_scriptpubkey @@ -197,4 +209,4 @@ bool fromwire_closingd_complete(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:b736e1d2c03a883962558ddcd5675d26cb09dcf3462c0cf82b3d49f1fd980c8a +// SHA256STAMP:be6dbb532dfd3c159212838acedd4bad3c8b4b16b5193b8c2a752697a15c8ab1 diff --git a/closingd/closingd_wiregen.h b/closingd/closingd_wiregen.h index 8af7b094fdba..5a02f8036a5e 100644 --- a/closingd/closingd_wiregen.h +++ b/closingd/closingd_wiregen.h @@ -37,8 +37,8 @@ bool closingd_wire_is_defined(u16 type); /* WIRE: CLOSINGD_INIT */ /* Begin! (passes peer fd */ -u8 *towire_closingd_init(const tal_t *ctx, const struct chainparams *chainparams, const struct per_peer_state *pps, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, const struct pubkey *local_fundingkey, const struct pubkey *remote_fundingkey, enum side opener, struct amount_sat local_sat, struct amount_sat remote_sat, struct amount_sat our_dust_limit, u32 min_feerate_perksipa, u32 preferred_feerate_perksipa, struct amount_sat fee_limit_satoshi, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, u64 fee_negotiation_step, u8 fee_negotiation_step_unit, bool use_quickclose, bool dev_fast_gossip, const struct bitcoin_outpoint *shutdown_wrong_funding); -bool fromwire_closingd_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct per_peer_state **pps, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, struct pubkey *local_fundingkey, struct pubkey *remote_fundingkey, enum side *opener, struct amount_sat *local_sat, struct amount_sat *remote_sat, struct amount_sat *our_dust_limit, u32 *min_feerate_perksipa, u32 *preferred_feerate_perksipa, struct amount_sat *fee_limit_satoshi, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, u64 *fee_negotiation_step, u8 *fee_negotiation_step_unit, bool *use_quickclose, bool *dev_fast_gossip, struct bitcoin_outpoint **shutdown_wrong_funding); +u8 *towire_closingd_init(const tal_t *ctx, const struct chainparams *chainparams, const struct per_peer_state *pps, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, const struct pubkey *local_fundingkey, const struct pubkey *remote_fundingkey, enum side opener, struct amount_sat local_sat, struct amount_sat remote_sat, struct amount_sat our_dust_limit, u32 min_feerate_perksipa, u32 preferred_feerate_perksipa, u32 *max_feerate_perksipa, struct amount_sat fee_limit_satoshi, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, u64 fee_negotiation_step, u8 fee_negotiation_step_unit, bool use_quickclose, bool dev_fast_gossip, const struct bitcoin_outpoint *shutdown_wrong_funding); +bool fromwire_closingd_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct per_peer_state **pps, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, struct pubkey *local_fundingkey, struct pubkey *remote_fundingkey, enum side *opener, struct amount_sat *local_sat, struct amount_sat *remote_sat, struct amount_sat *our_dust_limit, u32 *min_feerate_perksipa, u32 *preferred_feerate_perksipa, u32 **max_feerate_perksipa, struct amount_sat *fee_limit_satoshi, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, u64 *fee_negotiation_step, u8 *fee_negotiation_step_unit, bool *use_quickclose, bool *dev_fast_gossip, struct bitcoin_outpoint **shutdown_wrong_funding); /* WIRE: CLOSINGD_RECEIVED_SIGNATURE */ /* We received an offer */ @@ -56,4 +56,4 @@ bool fromwire_closingd_complete(const void *p); #endif /* LIGHTNING_CLOSINGD_CLOSINGD_WIREGEN_H */ -// SHA256STAMP:b736e1d2c03a883962558ddcd5675d26cb09dcf3462c0cf82b3d49f1fd980c8a +// SHA256STAMP:be6dbb532dfd3c159212838acedd4bad3c8b4b16b5193b8c2a752697a15c8ab1 diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index fbe869e4d3a0..1edced8fd37c 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -193,7 +193,7 @@ void peer_start_closingd(struct channel *channel, struct per_peer_state *pps) { u8 *initmsg; - u32 feerate; + u32 feerate, *max_feerate; struct amount_msat their_msat; struct amount_sat feelimit; int hsmfd; @@ -253,6 +253,19 @@ void peer_start_closingd(struct channel *channel, feerate = feerate_floor(); } + /* We use a feerate if anchor_outputs, otherwise max fee is set by + * the final unilateral. */ + if (channel->option_anchor_outputs) { + max_feerate = tal(tmpctx, u32); + /* Aim for reasonable max, but use final if we don't know. */ + *max_feerate = unilateral_feerate(ld->topology); + if (!*max_feerate) + *max_feerate = final_commit_feerate; + /* No other limit on fees */ + feelimit = channel->funding; + } else + max_feerate = NULL; + /* BOLT #3: * * Each node offering a signature: @@ -285,7 +298,9 @@ void peer_start_closingd(struct channel *channel, amount_msat_to_sat_round_down(channel->our_msat), amount_msat_to_sat_round_down(their_msat), channel->our_config.dust_limit, - feerate_min(ld, NULL), feerate, feelimit, + feerate_min(ld, NULL), feerate, + max_feerate, + feelimit, channel->shutdown_scriptpubkey[LOCAL], channel->shutdown_scriptpubkey[REMOTE], channel->closing_fee_negotiation_step,