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 <rusty@rustcorp.com.au>
Changelog-EXPERIMENTAL: Anchor output mutual close allow a fee higher than the final commitment transaction (as per lightning-rfc #847)
This commit is contained in:
Rusty Russell
2021-09-08 14:10:29 +09:30
parent 79d7e83f51
commit 1752616386
5 changed files with 98 additions and 36 deletions

View File

@@ -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 @@ exit_thru_the_giftshop:
tal_free(wrong_funding);
tal_free(our_feerange);
tal_free(their_feerange);
tal_free(max_feerate);
closing_dev_memleak(ctx, scriptpubkey, funding_wscript);
#endif

View File

@@ -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
1 #include <bitcoin/tx.h>
19 msgdata,closingd_init,our_dust_limit,amount_sat,
20 msgdata,closingd_init,min_feerate_perksipa,u32,
21 msgdata,closingd_init,preferred_feerate_perksipa,u32,
22 msgdata,closingd_init,max_feerate_perksipa,?u32,
23 msgdata,closingd_init,fee_limit_satoshi,amount_sat,
24 msgdata,closingd_init,local_scriptpubkey_len,u16,
25 msgdata,closingd_init,local_scriptpubkey,u8,local_scriptpubkey_len

View File

@@ -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

View File

@@ -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

View File

@@ -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,