--experimental-quick-close to enable quick-close negotiation

Based on a commit by @niftynei, but:
- Separated quickclose logic from main loop.
- I made it indep of anchor_outputs, use and option instead.
- Disable if they've specified how to negotiate.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2021-09-08 14:10:10 +09:30
parent 23a6c00496
commit 79d7e83f51
17 changed files with 337 additions and 20 deletions

View file

@ -141,10 +141,12 @@ static void send_offer(struct per_peer_state *pps,
enum side opener,
struct amount_sat our_dust_limit,
struct amount_sat fee_to_offer,
const struct bitcoin_outpoint *wrong_funding)
const struct bitcoin_outpoint *wrong_funding,
const struct tlv_closing_signed_tlvs_fee_range *tlv_fees)
{
struct bitcoin_tx *tx;
struct bitcoin_signature our_sig;
struct tlv_closing_signed_tlvs *close_tlvs;
u8 *msg;
/* BOLT #2:
@ -184,8 +186,19 @@ static void send_offer(struct per_peer_state *pps,
status_debug("sending fee offer %s",
type_to_string(tmpctx, struct amount_sat, &fee_to_offer));
/* Add the new close_tlvs with our fee range */
if (tlv_fees) {
close_tlvs = tlv_closing_signed_tlvs_new(msg);
close_tlvs->fee_range
= cast_const(struct tlv_closing_signed_tlvs_fee_range *,
tlv_fees);
} else
close_tlvs = NULL;
assert(our_sig.sighash_type == SIGHASH_ALL);
msg = towire_closing_signed(NULL, channel_id, fee_to_offer, &our_sig.s, NULL);
msg = towire_closing_signed(NULL, channel_id, fee_to_offer, &our_sig.s,
close_tlvs);
sync_crypto_write(pps, take(msg));
}
@ -222,7 +235,8 @@ receive_offer(struct per_peer_state *pps,
struct amount_sat our_dust_limit,
struct amount_sat min_fee_to_accept,
const struct bitcoin_outpoint *wrong_funding,
struct bitcoin_txid *closing_txid)
struct bitcoin_txid *closing_txid,
struct tlv_closing_signed_tlvs_fee_range **tlv_fees)
{
u8 *msg;
struct channel_id their_channel_id;
@ -330,6 +344,13 @@ receive_offer(struct per_peer_state *pps,
status_debug("Received fee offer %s",
type_to_string(tmpctx, struct amount_sat, &received_fee));
if (tlv_fees) {
if (close_tlvs)
*tlv_fees = tal_steal(tlv_fees, close_tlvs->fee_range);
else
*tlv_fees = NULL;
}
/* Master sorts out what is best offer, we just tell it any above min */
if (amount_sat_greater_eq(received_fee, min_fee_to_accept)) {
status_debug("...offer is reasonable");
@ -397,6 +418,32 @@ static void adjust_feerange(struct feerange *feerange,
"Overflow in updating fee range");
}
/* Do these two ranges overlap? If so, return that range. */
static bool get_overlap(const struct tlv_closing_signed_tlvs_fee_range *r1,
const struct tlv_closing_signed_tlvs_fee_range *r2,
struct tlv_closing_signed_tlvs_fee_range *overlap)
{
if (amount_sat_greater(r1->min_fee_satoshis, r2->min_fee_satoshis))
overlap->min_fee_satoshis = r1->min_fee_satoshis;
else
overlap->min_fee_satoshis = r2->min_fee_satoshis;
if (amount_sat_less(r1->max_fee_satoshis, r2->max_fee_satoshis))
overlap->max_fee_satoshis = r1->max_fee_satoshis;
else
overlap->max_fee_satoshis = r2->max_fee_satoshis;
return amount_sat_less_eq(overlap->min_fee_satoshis,
overlap->max_fee_satoshis);
}
/* Is this amount in this range? */
static bool amount_in_range(struct amount_sat amount,
const struct tlv_closing_signed_tlvs_fee_range *r)
{
return amount_sat_greater_eq(amount, r->min_fee_satoshis)
&& amount_sat_less_eq(amount, r->max_fee_satoshis);
}
/* Figure out what we should offer now. */
static struct amount_sat
adjust_offer(struct per_peer_state *pps, const struct channel_id *channel_id,
@ -572,6 +619,177 @@ static void calc_fee_bounds(size_t expected_weight,
type_to_string(tmpctx, struct amount_sat, &maxfee));
}
/* We've received one offer; if we're opener, that means we've already sent one
* too. */
static void do_quickclose(struct amount_sat offer[NUM_SIDES],
struct per_peer_state *pps,
const struct channel_id *channel_id,
const struct pubkey funding_pubkey[NUM_SIDES],
const u8 *funding_wscript,
u8 *scriptpubkey[NUM_SIDES],
const struct bitcoin_txid *funding_txid,
unsigned int funding_txout,
struct amount_sat funding,
const struct amount_sat out[NUM_SIDES],
enum side opener,
struct amount_sat our_dust_limit,
const struct bitcoin_outpoint *wrong_funding,
struct bitcoin_txid *closing_txid,
const struct tlv_closing_signed_tlvs_fee_range *our_feerange,
const struct tlv_closing_signed_tlvs_fee_range *their_feerange)
{
struct tlv_closing_signed_tlvs_fee_range overlap;
/* BOLT-closing-fee_range #2:
* - if the message contains a `fee_range`:
* - if there is no overlap between that and its own `fee_range`:
* - SHOULD fail the connection
*/
if (!get_overlap(our_feerange, their_feerange, &overlap)) {
peer_failed_warn(pps, channel_id,
"Unable to agree on a feerate."
" Our range %s-%s, other range %s-%s",
type_to_string(tmpctx,
struct amount_sat,
&our_feerange->min_fee_satoshis),
type_to_string(tmpctx,
struct amount_sat,
&our_feerange->max_fee_satoshis),
type_to_string(tmpctx,
struct amount_sat,
&their_feerange->min_fee_satoshis),
type_to_string(tmpctx,
struct amount_sat,
&their_feerange->max_fee_satoshis));
return;
}
status_info("performing quickclose in range %s-%s",
type_to_string(tmpctx, struct amount_sat,
&overlap.min_fee_satoshis),
type_to_string(tmpctx, struct amount_sat,
&overlap.max_fee_satoshis));
/* BOLT-closing-fee_range #2:
* - otherwise:
* - if it is the funder:
* - if `fee_satoshis` is not in the overlap between the sent
* and received `fee_range`:
* - SHOULD fail the connection
* - otherwise:
* - MUST reply with the same `fee_satoshis`.
*/
if (opener == LOCAL) {
if (!amount_in_range(offer[REMOTE], &overlap)) {
peer_failed_warn(pps, channel_id,
"Your fee %s was not in range:"
" Our range %s-%s, other range %s-%s",
type_to_string(tmpctx,
struct amount_sat, &offer[REMOTE]),
type_to_string(tmpctx,
struct amount_sat,
&our_feerange->min_fee_satoshis),
type_to_string(tmpctx,
struct amount_sat,
&our_feerange->max_fee_satoshis),
type_to_string(tmpctx,
struct amount_sat,
&their_feerange->min_fee_satoshis),
type_to_string(tmpctx,
struct amount_sat,
&their_feerange->max_fee_satoshis));
return;
}
/* Only reply if we didn't already completely agree. */
if (!amount_sat_eq(offer[LOCAL], offer[REMOTE])) {
offer[LOCAL] = offer[REMOTE];
send_offer(pps, chainparams,
channel_id, funding_pubkey, funding_wscript,
scriptpubkey, funding_txid, funding_txout,
funding, out, opener,
our_dust_limit,
offer[LOCAL],
wrong_funding,
our_feerange);
}
} else {
/* BOLT-closing-fee_range #2:
* - otherwise (it is not the funder):
* - if it has already sent a `closing_signed`:
* - if `fee_satoshis` is not the same as the value it sent:
* - SHOULD fail the connection.
* - otherwise:
* - MUST propose a `fee_satoshis` in the overlap between
* received and (about-to-be) sent `fee_range`.
*/
if (!amount_in_range(offer[LOCAL], &overlap)) {
/* Hmm, go to edges. */
if (amount_sat_greater(offer[LOCAL],
overlap.max_fee_satoshis)) {
offer[LOCAL] = overlap.max_fee_satoshis;
status_unusual("Lowered offer to max allowable"
" %s",
type_to_string(tmpctx,
struct amount_sat,
&offer[LOCAL]));
} else if (amount_sat_less(offer[LOCAL],
overlap.min_fee_satoshis)) {
offer[LOCAL] = overlap.min_fee_satoshis;
status_unusual("Increased offer to min allowable"
" %s",
type_to_string(tmpctx,
struct amount_sat,
&offer[LOCAL]));
}
}
send_offer(pps, chainparams,
channel_id, funding_pubkey, funding_wscript,
scriptpubkey, funding_txid, funding_txout,
funding, out, opener,
our_dust_limit,
offer[LOCAL],
wrong_funding,
our_feerange);
/* They will reply unless we completely agreed. */
if (!amount_sat_eq(offer[LOCAL], offer[REMOTE])) {
offer[REMOTE]
= receive_offer(pps, chainparams,
channel_id, funding_pubkey,
funding_wscript,
scriptpubkey, funding_txid,
funding_txout, funding,
out, opener,
our_dust_limit,
our_feerange->min_fee_satoshis,
wrong_funding,
closing_txid,
NULL);
/* BOLT-closing-fee_range #2:
* - otherwise (it is not the funder):
* - if it has already sent a `closing_signed`:
* - if `fee_satoshis` is not the same as the value
* it sent:
* - SHOULD fail the connection.
*/
if (!amount_sat_eq(offer[LOCAL], offer[REMOTE])) {
peer_failed_warn(pps, channel_id,
"Your fee %s was not equal to %s",
type_to_string(tmpctx,
struct amount_sat, &offer[REMOTE]),
type_to_string(tmpctx,
struct amount_sat, &offer[LOCAL]));
return;
}
}
}
peer_billboard(true, "We agreed on a closing fee of %"PRIu64" satoshi for tx:%s",
offer[LOCAL],
type_to_string(tmpctx, struct bitcoin_txid, closing_txid));
}
int main(int argc, char *argv[])
{
setup_locale();
@ -594,6 +812,8 @@ int main(int argc, char *argv[])
char fee_negotiation_step_str[32]; /* fee_negotiation_step + "sat" */
struct channel_id channel_id;
enum side whose_turn;
bool use_quickclose;
struct tlv_closing_signed_tlvs_fee_range *our_feerange, **their_feerange;
struct bitcoin_outpoint *wrong_funding;
subdaemon_setup(argc, argv);
@ -619,6 +839,7 @@ int main(int argc, char *argv[])
&scriptpubkey[REMOTE],
&fee_negotiation_step,
&fee_negotiation_step_unit,
&use_quickclose,
&dev_fast_gossip,
&wrong_funding))
master_badmsg(WIRE_CLOSINGD_INIT, msg);
@ -637,6 +858,29 @@ int main(int argc, char *argv[])
min_feerate, initial_feerate, commitment_fee,
&min_fee_to_accept, &offer[LOCAL]);
/* Write values into tlv for updated closing fee neg */
their_feerange = tal(ctx, struct tlv_closing_signed_tlvs_fee_range *);
*their_feerange = NULL;
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;
} else
our_feerange = NULL;
snprintf(fee_negotiation_step_str, sizeof(fee_negotiation_step_str),
"%" PRIu64 "%s", fee_negotiation_step,
fee_negotiation_step_unit ==
@ -683,7 +927,8 @@ int main(int argc, char *argv[])
funding, out, opener,
our_dust_limit,
offer[LOCAL],
wrong_funding);
wrong_funding,
our_feerange);
} else {
if (i == 0)
peer_billboard(false, "Waiting for their initial"
@ -705,7 +950,22 @@ int main(int argc, char *argv[])
our_dust_limit,
min_fee_to_accept,
wrong_funding,
&closing_txid);
&closing_txid,
their_feerange);
if (our_feerange && *their_feerange) {
do_quickclose(offer,
pps, &channel_id, funding_pubkey,
funding_wscript,
scriptpubkey,
&funding_txid, funding_txout,
funding, out, opener,
our_dust_limit,
wrong_funding,
&closing_txid,
our_feerange, *their_feerange);
goto exit_thru_the_giftshop;
}
}
}
@ -734,7 +994,8 @@ int main(int argc, char *argv[])
funding, out, opener,
our_dust_limit,
offer[LOCAL],
wrong_funding);
wrong_funding,
our_feerange);
} else {
peer_billboard(false, "Waiting for another"
" closing fee offer:"
@ -751,7 +1012,8 @@ int main(int argc, char *argv[])
our_dust_limit,
min_fee_to_accept,
wrong_funding,
&closing_txid);
&closing_txid,
their_feerange);
}
whose_turn = !whose_turn;
@ -761,9 +1023,12 @@ int main(int argc, char *argv[])
offer[LOCAL],
type_to_string(tmpctx, struct bitcoin_txid, &closing_txid));
exit_thru_the_giftshop:
#if DEVELOPER
/* We don't listen for master commands, so always check memleak here */
tal_free(wrong_funding);
tal_free(our_feerange);
tal_free(their_feerange);
closing_dev_memleak(ctx, scriptpubkey, funding_wscript);
#endif

View file

@ -26,6 +26,7 @@ msgdata,closingd_init,remote_scriptpubkey_len,u16,
msgdata,closingd_init,remote_scriptpubkey,u8,remote_scriptpubkey_len
msgdata,closingd_init,fee_negotiation_step,u64,
msgdata,closingd_init,fee_negotiation_step_unit,u8,
msgdata,closingd_init,use_quickclose,bool,
msgdata,closingd_init,dev_fast_gossip,bool,
msgdata,closingd_init,shutdown_wrong_funding,?bitcoin_outpoint,

1 #include <bitcoin/tx.h>
26 msgdata,closingd_init,remote_scriptpubkey,u8,remote_scriptpubkey_len
27 msgdata,closingd_init,fee_negotiation_step,u64,
28 msgdata,closingd_init,fee_negotiation_step_unit,u8,
29 msgdata,closingd_init,use_quickclose,bool,
30 msgdata,closingd_init,dev_fast_gossip,bool,
31 msgdata,closingd_init,shutdown_wrong_funding,?bitcoin_outpoint,
32 # We received an offer, save signature.

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 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, 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);
@ -76,6 +76,7 @@ u8 *towire_closingd_init(const tal_t *ctx, const struct chainparams *chainparams
towire_u8_array(&p, remote_scriptpubkey, remote_scriptpubkey_len);
towire_u64(&p, fee_negotiation_step);
towire_u8(&p, fee_negotiation_step_unit);
towire_bool(&p, use_quickclose);
towire_bool(&p, dev_fast_gossip);
if (!shutdown_wrong_funding)
towire_bool(&p, false);
@ -86,7 +87,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 *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, 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;
@ -121,6 +122,7 @@ bool fromwire_closingd_init(const tal_t *ctx, const void *p, const struct chainp
fromwire_u8_array(&cursor, &plen, *remote_scriptpubkey, remote_scriptpubkey_len);
*fee_negotiation_step = fromwire_u64(&cursor, &plen);
*fee_negotiation_step_unit = fromwire_u8(&cursor, &plen);
*use_quickclose = fromwire_bool(&cursor, &plen);
*dev_fast_gossip = fromwire_bool(&cursor, &plen);
if (!fromwire_bool(&cursor, &plen))
*shutdown_wrong_funding = NULL;
@ -195,4 +197,4 @@ bool fromwire_closingd_complete(const void *p)
return false;
return cursor != NULL;
}
// SHA256STAMP:961ca5ceef03f911684ba0e7863d69993e692b9b418108e6038a567cb7cc7b3e
// SHA256STAMP:b736e1d2c03a883962558ddcd5675d26cb09dcf3462c0cf82b3d49f1fd980c8a

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 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 *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, 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);
/* 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:961ca5ceef03f911684ba0e7863d69993e692b9b418108e6038a567cb7cc7b3e
// SHA256STAMP:b736e1d2c03a883962558ddcd5675d26cb09dcf3462c0cf82b3d49f1fd980c8a

View file

@ -90,6 +90,8 @@ On success, an object is returned, containing:
.IP \[bu]
\fBexperimental-offers\fR (boolean, optional): \fBexperimental-offers\fR field from config or cmdline, or default
.IP \[bu]
\fBexperimental-quick-close\fR (boolean, optional): \fBexperimental-quick-close\fR field from config or cmdline, or default
.IP \[bu]
\fBexperimental-shutdown-wrong-funding\fR (boolean, optional): \fBexperimental-shutdown-wrong-funding\fR field from config or cmdline, or default
.IP \[bu]
\fBrgb\fR (hex, optional): \fBrgb\fR field from config or cmdline, or default (always 6 characters)
@ -270,4 +272,4 @@ Vincenzo Palazzo \fI<vincenzo.palazzo@protonmail.com\fR> wrote the initial versi
Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
\" SHA256STAMP:b6e48314de5642ec61a3e2c989ac0197630c2a3c0e8e6d86020b597679049400
\" SHA256STAMP:fd8f2ae862627712b6baf51741670a6d60db8342f839580871617deed0c75317

View file

@ -55,6 +55,7 @@ On success, an object is returned, containing:
- **experimental-dual-fund** (boolean, optional): `experimental-dual-fund` field from config or cmdline, or default
- **experimental-onion-messages** (boolean, optional): `experimental-onion-messages` field from config or cmdline, or default
- **experimental-offers** (boolean, optional): `experimental-offers` field from config or cmdline, or default
- **experimental-quick-close** (boolean, optional): `experimental-quick-close` field from config or cmdline, or default
- **experimental-shutdown-wrong-funding** (boolean, optional): `experimental-shutdown-wrong-funding` field from config or cmdline, or default
- **rgb** (hex, optional): `rgb` field from config or cmdline, or default (always 6 characters)
- **alias** (string, optional): `alias` field from config or cmdline, or default
@ -205,4 +206,4 @@ RESOURCES
---------
Main web site: <https://github.com/ElementsProject/lightning>
[comment]: # ( SHA256STAMP:7bb40fc8fac201b32d9701b02596d0fa59eb14a3baf606439cbf96dc11548ed4)
[comment]: # ( SHA256STAMP:8b198154e70e1c0acb6c9ccdbe9e41e35ddab55738be9ea9076c5384da965cb8)

View file

@ -625,6 +625,16 @@ about whether to add funds or not to a proposed channel is handled
automatically by a plugin that implements the appropriate logic for
your needs\. The default behavior is to not contribute funds\.
\fBexperimental-quick-close\fR
Specifying this means we send our range of acceptable fees to the peer
on mutual close\. If they support it too, we'll simply use that for
closing (unless \fIfee_negotiation_step\fR is set, see \fBlightning-close\fR(7))\.
We always use this on channels which negotiation \fBoption_anchor_outputs\fR,
as the spec requires that\.
.SH BUGS
You should report bugs on our github issues page, and maybe submit a fix
@ -650,4 +660,4 @@ Main web site: \fIhttps://github.com/ElementsProject/lightning\fR
Note: the modules in the ccan/ directory have their own licenses, but
the rest of the code is covered by the BSD-style MIT license\.
\" SHA256STAMP:1c392f3fee66dc6c1fc2c34200204a9be1d79e53fd5fb1720ad169fc671f71c0
\" SHA256STAMP:0d2474276b325cb002191211fb1d0da2409ebc859ff3ccc6dd3e688b10d4550c

View file

@ -517,6 +517,14 @@ about whether to add funds or not to a proposed channel is handled
automatically by a plugin that implements the appropriate logic for
your needs. The default behavior is to not contribute funds.
**experimental-quick-close**
Specifying this means we send our range of acceptable fees to the peer
on mutual close. If they support it too, we'll simply use that for
closing (unless *fee_negotiation_step* is set, see lightning-close(7)).
We always use this on channels which negotiation `option_anchor_outputs`,
as the spec requires that.
BUGS
----

View file

@ -117,6 +117,10 @@
"type": "boolean",
"description": "`experimental-offers` field from config or cmdline, or default"
},
"experimental-quick-close": {
"type": "boolean",
"description": "`experimental-quick-close` field from config or cmdline, or default"
},
"experimental-shutdown-wrong-funding": {
"type": "boolean",
"description": "`experimental-shutdown-wrong-funding` field from config or cmdline, or default"

View file

@ -2,6 +2,7 @@
#include <bitcoin/script.h>
#include <closingd/closingd_wiregen.h>
#include <common/close_tx.h>
#include <common/closing_fee.h>
#include <common/fee_states.h>
#include <common/initial_commit_tx.h>
#include <common/per_peer_state.h>
@ -289,6 +290,12 @@ void peer_start_closingd(struct channel *channel,
channel->shutdown_scriptpubkey[REMOTE],
channel->closing_fee_negotiation_step,
channel->closing_fee_negotiation_step_unit,
(ld->use_quickclose
/* Don't quickclose if they specified how to negotiate! */
&& channel->closing_fee_negotiation_step == 50
&& channel->closing_fee_negotiation_step_unit == CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE)
/* Always use quickclose with anchors */
|| channel->option_anchor_outputs,
IFDEV(ld->dev_fast_gossip, false),
channel->shutdown_wrong_funding);

View file

@ -295,6 +295,11 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
* case this is a pointer to an enum feerate-indexed array of values */
ld->force_feerates = NULL;
/*~ We don't enable new network features until they've been approved
* and tested in the spec (i.e. some other implementation has also
* implemented and tested!). Until then we use a flag: */
ld->use_quickclose = false;
return ld;
}

View file

@ -283,6 +283,9 @@ struct lightningd {
/* Should we re-exec ourselves instead of just exiting? */
bool try_reexec;
/* --experimental-quick-close */
bool use_quickclose;
/* Array of (even) TLV types that we should allow. This is required
* since we otherwise would outright reject them. */
u64 *accept_extra_tlv_types;

View file

@ -1062,6 +1062,10 @@ static void register_opts(struct lightningd *ld)
"--subdaemon=hsmd:remote_signer "
"would use a hypothetical remote signing subdaemon.");
opt_register_noarg("--experimental-quick-close",
opt_set_bool, &ld->use_quickclose,
"EXPERIMENTAL: offer range to mutual close");
opt_register_logging(ld);
opt_register_version();

View file

@ -6,7 +6,7 @@ from pyln.testing.utils import SLOW_MACHINE
from utils import (
only_one, sync_blockheight, wait_for, TIMEOUT,
account_balance, first_channel_id, closing_fee, TEST_NETWORK,
scriptpubkey_addr, calc_lease_fee
scriptpubkey_addr, calc_lease_fee, EXPERIMENTAL_FEATURES
)
import os
@ -446,6 +446,7 @@ def closing_negotiation_step(node_factory, bitcoind, chainparams, opts):
assert opts['expected_close_fee'] == fee_mempool
@unittest.skipIf(EXPERIMENTAL_FEATURES, "anchors uses quick-close, not negotiation")
def test_closing_negotiation_step_30pct(node_factory, bitcoind, chainparams):
"""Test that the closing fee negotiation step works, 30%"""
opts = {}
@ -460,6 +461,7 @@ def test_closing_negotiation_step_30pct(node_factory, bitcoind, chainparams):
closing_negotiation_step(node_factory, bitcoind, chainparams, opts)
@unittest.skipIf(EXPERIMENTAL_FEATURES, "anchors uses quick-close, not negotiation")
def test_closing_negotiation_step_50pct(node_factory, bitcoind, chainparams):
"""Test that the closing fee negotiation step works, 50%, the default"""
opts = {}
@ -474,6 +476,7 @@ def test_closing_negotiation_step_50pct(node_factory, bitcoind, chainparams):
closing_negotiation_step(node_factory, bitcoind, chainparams, opts)
@unittest.skipIf(EXPERIMENTAL_FEATURES, "anchors uses quick-close, not negotiation")
def test_closing_negotiation_step_100pct(node_factory, bitcoind, chainparams):
"""Test that the closing fee negotiation step works, 100%"""
opts = {}
@ -493,6 +496,7 @@ def test_closing_negotiation_step_100pct(node_factory, bitcoind, chainparams):
closing_negotiation_step(node_factory, bitcoind, chainparams, opts)
@unittest.skipIf(EXPERIMENTAL_FEATURES, "anchors uses quick-close, not negotiation")
def test_closing_negotiation_step_1sat(node_factory, bitcoind, chainparams):
"""Test that the closing fee negotiation step works, 1sat"""
opts = {}
@ -507,6 +511,7 @@ def test_closing_negotiation_step_1sat(node_factory, bitcoind, chainparams):
closing_negotiation_step(node_factory, bitcoind, chainparams, opts)
@unittest.skipIf(EXPERIMENTAL_FEATURES, "anchors uses quick-close, not negotiation")
def test_closing_negotiation_step_700sat(node_factory, bitcoind, chainparams):
"""Test that the closing fee negotiation step works, 700sat"""
opts = {}

View file

@ -2074,4 +2074,4 @@ struct db_query db_postgres_queries[] = {
#endif /* LIGHTNINGD_WALLET_GEN_DB_POSTGRES */
// SHA256STAMP:219fccaaf2391eeabadd4cc15b4a3431c7ecab9d17755582e6962a34c74982c5
// SHA256STAMP:56ce3adfaa2de5ef901e32e7f698b9500859a0015d869470ea1be779847b32e3

View file

@ -2074,4 +2074,4 @@ struct db_query db_sqlite3_queries[] = {
#endif /* LIGHTNINGD_WALLET_GEN_DB_SQLITE3 */
// SHA256STAMP:219fccaaf2391eeabadd4cc15b4a3431c7ecab9d17755582e6962a34c74982c5
// SHA256STAMP:56ce3adfaa2de5ef901e32e7f698b9500859a0015d869470ea1be779847b32e3

View file

@ -1369,4 +1369,4 @@ msgstr ""
#: wallet/test/run-wallet.c:1753
msgid "INSERT INTO channels (id) VALUES (1);"
msgstr ""
# SHA256STAMP:d098fea63dcba84aefff5cf924cbc455caf9d2ec13cb28ad9ab929bb001a12e6
# SHA256STAMP:a433fb1866ae16a28b87177ef67fc99669c03a6cd47a0433e1460884367bbf34