From 4ea9d9e9286fff4fd67884115d1304f2a4ba18a2 Mon Sep 17 00:00:00 2001 From: niftynei Date: Mon, 26 Oct 2020 12:48:42 -0500 Subject: [PATCH] df: Pass new feerate options through to plugin, set reasonable bounds We let the plugin decide what feerate to accept/whether or not to add funds to the open. To aid this decision, we also send the plugin what we (c-lightning) currently have as our max and min acceptable feerates. We also now use these as our default for max/min acceptable feerate range when sending an openchannel offer to a peer. In the future, it might be a good idea to make these more easily changeable, either via a config setting (?) or a command param. --- lightningd/dual_open_control.c | 81 ++++++++++++++++++++++++++++------ openingd/dualopend.c | 55 +++++++++++------------ openingd/dualopend_wire.csv | 5 ++- openingd/dualopend_wiregen.c | 20 ++++++--- openingd/dualopend_wiregen.h | 10 ++--- tests/plugins/df_accepter.py | 32 ++++++++++++-- 6 files changed, 145 insertions(+), 58 deletions(-) diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 9ea2f0c71..ce60058b2 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -77,8 +77,12 @@ struct openchannel2_payload { struct amount_sat dust_limit_satoshis; struct amount_msat max_htlc_value_in_flight_msat; struct amount_msat htlc_minimum_msat; - u32 feerate_per_kw_funding; - u32 feerate_per_kw; + u32 funding_feerate_max; + u32 funding_feerate_min; + u32 funding_feerate_best; + u32 feerate_our_max; + u32 feerate_our_min; + u32 commitment_feerate_per_kw; u16 to_self_delay; u16 max_accepted_htlcs; u8 channel_flags; @@ -87,6 +91,7 @@ struct openchannel2_payload { /* FIXME: include the podle? */ struct amount_sat accepter_funding; + u32 funding_feerate_per_kw; struct wally_psbt *psbt; const u8 *our_shutdown_scriptpubkey; }; @@ -105,9 +110,18 @@ openchannel2_hook_serialize(struct openchannel2_payload *payload, payload->max_htlc_value_in_flight_msat); json_add_amount_msat_only(stream, "htlc_minimum_msat", payload->htlc_minimum_msat); - json_add_num(stream, "feerate_per_kw_funding", - payload->feerate_per_kw_funding); - json_add_num(stream, "feerate_per_kw", payload->feerate_per_kw); + json_add_num(stream, "funding_feerate_max", + payload->funding_feerate_max); + json_add_num(stream, "funding_feerate_min", + payload->funding_feerate_min); + json_add_num(stream, "funding_feerate_best", + payload->funding_feerate_best); + json_add_num(stream, "feerate_our_max", + payload->feerate_our_max); + json_add_num(stream, "feerate_our_min", + payload->feerate_our_min); + json_add_num(stream, "commitment_feerate_per_kw", + payload->commitment_feerate_per_kw); json_add_num(stream, "to_self_delay", payload->to_self_delay); json_add_num(stream, "max_accepted_htlcs", payload->max_accepted_htlcs); json_add_num(stream, "channel_flags", payload->channel_flags); @@ -369,10 +383,31 @@ openchannel2_hook_deserialize(struct openchannel2_payload *payload, fatal("Plugin supplied PSBT that's missing required fields. %s", type_to_string(tmpctx, struct wally_psbt, payload->psbt)); - if (!hook_extract_amount(dualopend, buffer, toks, "accepter_funding_msat", + if (!hook_extract_amount(dualopend, buffer, toks, + "accepter_funding_msat", &payload->accepter_funding)) fatal("Plugin failed to supply accepter_funding_msat field"); + const jsmntok_t *t = json_get_member(buffer, toks, "funding_feerate"); + /* If they don't return a feerate, we use the best */ + if (!t) + payload->funding_feerate_per_kw = payload->funding_feerate_best; + else { + if (!json_to_number(buffer, t, + &payload->funding_feerate_per_kw)) + fatal("Unable to parse 'funding-feerate'"); + if (payload->funding_feerate_per_kw + < payload->funding_feerate_min + || payload->funding_feerate_per_kw + > payload->funding_feerate_max) + /* FIXME: return an error instead of failing? */ + fatal("Plugin supplied invalid funding feerate %d." + " Outside valid range %d - %d", + payload->funding_feerate_per_kw, + payload->funding_feerate_min, + payload->funding_feerate_max); + } + if (!payload->psbt && !amount_sat_eq(payload->accepter_funding, AMOUNT_SAT(0))) { /* Gotta give a PSBT if you set the accepter_funding amount */ @@ -386,6 +421,7 @@ static void openchannel2_hook_cb(struct openchannel2_payload *payload STEALS) { struct subd *dualopend = payload->dualopend; + u8 *msg; /* Free payload regardless of what happens next */ tal_steal(tmpctx, payload); @@ -396,13 +432,19 @@ openchannel2_hook_cb(struct openchannel2_payload *payload STEALS) tal_del_destructor2(dualopend, openchannel2_remove_dualopend, payload); + /* If there's no plugin, the funding_feerate_per_kw will be zero. + * In this case, we set the funding_feerate_per_kw to the default, + * the 'best' */ + if (payload->funding_feerate_per_kw == 0) + payload->funding_feerate_per_kw = payload->funding_feerate_best; + /* If there's no plugin, the psbt will be NULL. We should pass an empty * PSBT over, in this case */ - subd_send_msg(dualopend, - take(towire_dual_open_got_offer_reply(NULL, - payload->accepter_funding, - payload->psbt, - payload->our_shutdown_scriptpubkey))); + msg = towire_dual_open_got_offer_reply(NULL, payload->accepter_funding, + payload->funding_feerate_per_kw, + payload->psbt, + payload->our_shutdown_scriptpubkey); + subd_send_msg(dualopend, take(msg)); } /* dualopend dies? Remove dualopend ptr from payload */ @@ -956,8 +998,10 @@ static void accepter_got_offer(struct subd *dualopend, &payload->dust_limit_satoshis, &payload->max_htlc_value_in_flight_msat, &payload->htlc_minimum_msat, - &payload->feerate_per_kw_funding, - &payload->feerate_per_kw, + &payload->funding_feerate_max, + &payload->funding_feerate_min, + &payload->funding_feerate_best, + &payload->commitment_feerate_per_kw, &payload->to_self_delay, &payload->max_accepted_htlcs, &payload->channel_flags, @@ -969,6 +1013,17 @@ static void accepter_got_offer(struct subd *dualopend, return; } + /* As a convenience to the plugin, we provide our current known + * min + max feerates. Ideally, the plugin will fail to + * contribute funds if the peer's feerate range is outside of + * this acceptable range, but we delegate that decision to + * the plugin's logic */ + payload->feerate_our_min = feerate_min(dualopend->ld, NULL); + payload->feerate_our_max = feerate_max(dualopend->ld, NULL); + + /* Set the inital to feerate to zero, in case there is no plugin */ + payload->funding_feerate_per_kw = 0; + tal_add_destructor2(dualopend, openchannel2_remove_dualopend, payload); plugin_hook_call_openchannel2(dualopend->ld, payload); } diff --git a/openingd/dualopend.c b/openingd/dualopend.c index b69e50b1d..d4c5920ce 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1200,40 +1200,20 @@ static u8 *accepter_start(struct state *state, const u8 *oc2_msg) return NULL; } - /* BOLT #2: - * - * The receiving node MUST fail the channel if: - *... - * - it considers `feerate_per_kw` too small for timely processing or - * unreasonably large. - */ - if (state->feerate_per_kw_funding < state->min_feerate) { - negotiation_failed(state, false, - "feerate_per_kw_funding %u below minimum %u", - state->feerate_per_kw_funding, state->min_feerate); - return NULL; - } - - if (state->feerate_per_kw_funding > state->max_feerate) { - negotiation_failed(state, false, - "feerate_per_kw_funding %u above maximum %u", - state->feerate_per_kw_funding, state->max_feerate); - return NULL; - } - /* We can figure out the channel id now */ derive_channel_id_v2(&state->channel_id, &state->our_points.revocation, &state->their_points.revocation); /* FIXME: pass the podle back also */ - /* FIXME: pass back the feerate options */ msg = towire_dual_open_got_offer(NULL, state->opener_funding, state->remoteconf.dust_limit, state->remoteconf.max_htlc_value_in_flight, state->remoteconf.htlc_minimum, - state->feerate_per_kw_funding, + feerate_max, + feerate_min, + feerate_best, state->feerate_per_kw, state->remoteconf.to_self_delay, state->remoteconf.max_accepted_htlcs, @@ -1254,7 +1234,9 @@ static u8 *accepter_start(struct state *state, const u8 *oc2_msg) return NULL; } if (!fromwire_dual_open_got_offer_reply(state, msg, - &state->accepter_funding, &psbt, + &state->accepter_funding, + &state->feerate_per_kw_funding, + &psbt, &state->upfront_shutdown_script[LOCAL])) master_badmsg(WIRE_DUAL_OPEN_GOT_OFFER_REPLY, msg); @@ -1318,8 +1300,6 @@ static u8 *accepter_start(struct state *state, const u8 *oc2_msg) tal_count(state->upfront_shutdown_script[LOCAL]), 0); } - /* FIXME: actually look up a good feerate */ - state->feerate_per_kw_funding = feerate_best; msg = towire_accept_channel2(tmpctx, &state->channel_id, state->accepter_funding, state->feerate_per_kw_funding, @@ -1551,7 +1531,6 @@ static u8 *opener_start(struct state *state, u8 *msg) secp256k1_ecdsa_signature *htlc_sigs; u32 feerate_min, feerate_max, feerate_best; - /* FIXME: get these from opener !? */ if (!fromwire_dual_open_opener_init(state, msg, &psbt, &state->opener_funding, @@ -1565,8 +1544,26 @@ static u8 *opener_start(struct state *state, u8 *msg) state->tx_locktime = psbt->tx->locktime; open_tlv = tlv_opening_tlvs_new(tmpctx); - feerate_min = state->feerate_per_kw_funding - 1; - feerate_max = state->feerate_per_kw_funding + 1; + feerate_min = state->min_feerate; + feerate_max = state->max_feerate; + if (state->feerate_per_kw_funding > state->max_feerate) { + status_info("Selected funding feerate %d is greater than" + " current suggested max %d, adjusing max upwards" + " to match.", + state->feerate_per_kw_funding, + state->max_feerate); + + feerate_max = state->feerate_per_kw_funding; + } + if (state->feerate_per_kw_funding < state->min_feerate) { + status_info("Selected funding feerate %d is less than" + " current suggested min %d, adjusing min downwards" + " to match.", + state->feerate_per_kw_funding, + state->min_feerate); + + feerate_min = state->feerate_per_kw_funding; + } feerate_best = state->feerate_per_kw_funding; if (state->upfront_shutdown_script[LOCAL]) { diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 6a44307a2..85a8fd30c 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -36,7 +36,9 @@ msgdata,dual_open_got_offer,opener_funding,amount_sat, msgdata,dual_open_got_offer,dust_limit_satoshis,amount_sat, msgdata,dual_open_got_offer,max_htlc_value_in_flight_msat,amount_msat, msgdata,dual_open_got_offer,htlc_minimum_msat,amount_msat, -msgdata,dual_open_got_offer,feerate_per_kw_funding,u32, +msgdata,dual_open_got_offer,feerate_funding_max,u32, +msgdata,dual_open_got_offer,feerate_funding_min,u32, +msgdata,dual_open_got_offer,feerate_funding_best,u32, msgdata,dual_open_got_offer,feerate_per_kw,u32, msgdata,dual_open_got_offer,to_self_delay,u16, msgdata,dual_open_got_offer,max_accepted_htlcs,u16, @@ -48,6 +50,7 @@ msgdata,dual_open_got_offer,shutdown_scriptpubkey,u8,shutdown_len # master->dualopend: reply back with our first funding info/contribs msgtype,dual_open_got_offer_reply,7105 msgdata,dual_open_got_offer_reply,accepter_funding,amount_sat, +msgdata,dual_open_got_offer_reply,feerate_funding,u32, msgdata,dual_open_got_offer_reply,psbt,wally_psbt, msgdata,dual_open_got_offer_reply,shutdown_len,u16, msgdata,dual_open_got_offer_reply,our_shutdown_scriptpubkey,?u8,shutdown_len diff --git a/openingd/dualopend_wiregen.c b/openingd/dualopend_wiregen.c index 78d7a2fcb..96c00dc8b 100644 --- a/openingd/dualopend_wiregen.c +++ b/openingd/dualopend_wiregen.c @@ -130,7 +130,7 @@ bool fromwire_dual_open_init(const tal_t *ctx, const void *p, const struct chain /* WIRE: DUAL_OPEN_GOT_OFFER */ /* dualopend->master: they offered channel */ -u8 *towire_dual_open_got_offer(const tal_t *ctx, struct amount_sat opener_funding, struct amount_sat dust_limit_satoshis, struct amount_msat max_htlc_value_in_flight_msat, struct amount_msat htlc_minimum_msat, u32 feerate_per_kw_funding, u32 feerate_per_kw, u16 to_self_delay, u16 max_accepted_htlcs, u8 channel_flags, u32 locktime, const u8 *shutdown_scriptpubkey) +u8 *towire_dual_open_got_offer(const tal_t *ctx, struct amount_sat opener_funding, struct amount_sat dust_limit_satoshis, struct amount_msat max_htlc_value_in_flight_msat, struct amount_msat htlc_minimum_msat, u32 feerate_funding_max, u32 feerate_funding_min, u32 feerate_funding_best, u32 feerate_per_kw, u16 to_self_delay, u16 max_accepted_htlcs, u8 channel_flags, u32 locktime, const u8 *shutdown_scriptpubkey) { u16 shutdown_len = tal_count(shutdown_scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); @@ -140,7 +140,9 @@ u8 *towire_dual_open_got_offer(const tal_t *ctx, struct amount_sat opener_fundin towire_amount_sat(&p, dust_limit_satoshis); towire_amount_msat(&p, max_htlc_value_in_flight_msat); towire_amount_msat(&p, htlc_minimum_msat); - towire_u32(&p, feerate_per_kw_funding); + towire_u32(&p, feerate_funding_max); + towire_u32(&p, feerate_funding_min); + towire_u32(&p, feerate_funding_best); towire_u32(&p, feerate_per_kw); towire_u16(&p, to_self_delay); towire_u16(&p, max_accepted_htlcs); @@ -151,7 +153,7 @@ u8 *towire_dual_open_got_offer(const tal_t *ctx, struct amount_sat opener_fundin return memcheck(p, tal_count(p)); } -bool fromwire_dual_open_got_offer(const tal_t *ctx, const void *p, struct amount_sat *opener_funding, struct amount_sat *dust_limit_satoshis, struct amount_msat *max_htlc_value_in_flight_msat, struct amount_msat *htlc_minimum_msat, u32 *feerate_per_kw_funding, u32 *feerate_per_kw, u16 *to_self_delay, u16 *max_accepted_htlcs, u8 *channel_flags, u32 *locktime, u8 **shutdown_scriptpubkey) +bool fromwire_dual_open_got_offer(const tal_t *ctx, const void *p, struct amount_sat *opener_funding, struct amount_sat *dust_limit_satoshis, struct amount_msat *max_htlc_value_in_flight_msat, struct amount_msat *htlc_minimum_msat, u32 *feerate_funding_max, u32 *feerate_funding_min, u32 *feerate_funding_best, u32 *feerate_per_kw, u16 *to_self_delay, u16 *max_accepted_htlcs, u8 *channel_flags, u32 *locktime, u8 **shutdown_scriptpubkey) { u16 shutdown_len; @@ -164,7 +166,9 @@ bool fromwire_dual_open_got_offer(const tal_t *ctx, const void *p, struct amount *dust_limit_satoshis = fromwire_amount_sat(&cursor, &plen); *max_htlc_value_in_flight_msat = fromwire_amount_msat(&cursor, &plen); *htlc_minimum_msat = fromwire_amount_msat(&cursor, &plen); - *feerate_per_kw_funding = fromwire_u32(&cursor, &plen); + *feerate_funding_max = fromwire_u32(&cursor, &plen); + *feerate_funding_min = fromwire_u32(&cursor, &plen); + *feerate_funding_best = fromwire_u32(&cursor, &plen); *feerate_per_kw = fromwire_u32(&cursor, &plen); *to_self_delay = fromwire_u16(&cursor, &plen); *max_accepted_htlcs = fromwire_u16(&cursor, &plen); @@ -179,20 +183,21 @@ bool fromwire_dual_open_got_offer(const tal_t *ctx, const void *p, struct amount /* WIRE: DUAL_OPEN_GOT_OFFER_REPLY */ /* master->dualopend: reply back with our first funding info/contribs */ -u8 *towire_dual_open_got_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt, const u8 *our_shutdown_scriptpubkey) +u8 *towire_dual_open_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) { u16 shutdown_len = tal_count(our_shutdown_scriptpubkey); u8 *p = tal_arr(ctx, u8, 0); towire_u16(&p, WIRE_DUAL_OPEN_GOT_OFFER_REPLY); towire_amount_sat(&p, accepter_funding); + towire_u32(&p, feerate_funding); towire_wally_psbt(&p, psbt); towire_u16(&p, shutdown_len); towire_u8_array(&p, our_shutdown_scriptpubkey, shutdown_len); return memcheck(p, tal_count(p)); } -bool fromwire_dual_open_got_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt, u8 **our_shutdown_scriptpubkey) +bool fromwire_dual_open_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) { u16 shutdown_len; @@ -202,6 +207,7 @@ bool fromwire_dual_open_got_offer_reply(const tal_t *ctx, const void *p, struct if (fromwire_u16(&cursor, &plen) != WIRE_DUAL_OPEN_GOT_OFFER_REPLY) return false; *accepter_funding = fromwire_amount_sat(&cursor, &plen); + *feerate_funding = fromwire_u32(&cursor, &plen); *psbt = fromwire_wally_psbt(ctx, &cursor, &plen); shutdown_len = fromwire_u16(&cursor, &plen); // 2nd case our_shutdown_scriptpubkey @@ -479,4 +485,4 @@ bool fromwire_dual_open_dev_memleak_reply(const void *p, bool *leak) *leak = fromwire_bool(&cursor, &plen); return cursor != NULL; } -// SHA256STAMP:b1bf5b7fc522f2b0d940704f6f9e1699db093da76ca88d3ce7c925d40569ab14 +// SHA256STAMP:f08f0c25f359d5c8f843d78c94eca9b0543b39e62a34983f6572adf92ff02aaa diff --git a/openingd/dualopend_wiregen.h b/openingd/dualopend_wiregen.h index d0d39dc0c..9ee1fa2fe 100644 --- a/openingd/dualopend_wiregen.h +++ b/openingd/dualopend_wiregen.h @@ -59,13 +59,13 @@ bool fromwire_dual_open_init(const tal_t *ctx, const void *p, const struct chain /* WIRE: DUAL_OPEN_GOT_OFFER */ /* dualopend->master: they offered channel */ -u8 *towire_dual_open_got_offer(const tal_t *ctx, struct amount_sat opener_funding, struct amount_sat dust_limit_satoshis, struct amount_msat max_htlc_value_in_flight_msat, struct amount_msat htlc_minimum_msat, u32 feerate_per_kw_funding, u32 feerate_per_kw, u16 to_self_delay, u16 max_accepted_htlcs, u8 channel_flags, u32 locktime, const u8 *shutdown_scriptpubkey); -bool fromwire_dual_open_got_offer(const tal_t *ctx, const void *p, struct amount_sat *opener_funding, struct amount_sat *dust_limit_satoshis, struct amount_msat *max_htlc_value_in_flight_msat, struct amount_msat *htlc_minimum_msat, u32 *feerate_per_kw_funding, u32 *feerate_per_kw, u16 *to_self_delay, u16 *max_accepted_htlcs, u8 *channel_flags, u32 *locktime, u8 **shutdown_scriptpubkey); +u8 *towire_dual_open_got_offer(const tal_t *ctx, struct amount_sat opener_funding, struct amount_sat dust_limit_satoshis, struct amount_msat max_htlc_value_in_flight_msat, struct amount_msat htlc_minimum_msat, u32 feerate_funding_max, u32 feerate_funding_min, u32 feerate_funding_best, u32 feerate_per_kw, u16 to_self_delay, u16 max_accepted_htlcs, u8 channel_flags, u32 locktime, const u8 *shutdown_scriptpubkey); +bool fromwire_dual_open_got_offer(const tal_t *ctx, const void *p, struct amount_sat *opener_funding, struct amount_sat *dust_limit_satoshis, struct amount_msat *max_htlc_value_in_flight_msat, struct amount_msat *htlc_minimum_msat, u32 *feerate_funding_max, u32 *feerate_funding_min, u32 *feerate_funding_best, u32 *feerate_per_kw, u16 *to_self_delay, u16 *max_accepted_htlcs, u8 *channel_flags, u32 *locktime, u8 **shutdown_scriptpubkey); /* WIRE: DUAL_OPEN_GOT_OFFER_REPLY */ /* master->dualopend: reply back with our first funding info/contribs */ -u8 *towire_dual_open_got_offer_reply(const tal_t *ctx, struct amount_sat accepter_funding, const struct wally_psbt *psbt, const u8 *our_shutdown_scriptpubkey); -bool fromwire_dual_open_got_offer_reply(const tal_t *ctx, const void *p, struct amount_sat *accepter_funding, struct wally_psbt **psbt, u8 **our_shutdown_scriptpubkey); +u8 *towire_dual_open_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_dual_open_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: DUAL_OPEN_COMMIT_RCVD */ /* dualopend->master: ready to commit channel open to database and */ @@ -109,4 +109,4 @@ bool fromwire_dual_open_dev_memleak_reply(const void *p, bool *leak); #endif /* LIGHTNING_OPENINGD_DUALOPEND_WIREGEN_H */ -// SHA256STAMP:b1bf5b7fc522f2b0d940704f6f9e1699db093da76ca88d3ce7c925d40569ab14 +// SHA256STAMP:f08f0c25f359d5c8f843d78c94eca9b0543b39e62a34983f6572adf92ff02aaa diff --git a/tests/plugins/df_accepter.py b/tests/plugins/df_accepter.py index 703652254..9793ed972 100755 --- a/tests/plugins/df_accepter.py +++ b/tests/plugins/df_accepter.py @@ -44,13 +44,38 @@ def get_script(bech_addr): return bytes([wit_ver + 0x50 if wit_ver > 0 else wit_ver, len(wprog)] + wprog) +def find_feerate(best, their_min, their_max, our_min, our_max): + if best >= our_min and best <= our_max: + return best + + if their_max < our_min or their_min > our_max: + return False + + if best < our_min: + return our_min + + # best > our_max: + return our_max + + @plugin.hook('openchannel2') def on_openchannel(openchannel2, plugin, **kwargs): - # We mirror what the peer does, wrt to funding amount + # We mirror what the peer does, wrt to funding amount ... amount = openchannel2['their_funding'] - feerate = openchannel2['feerate_per_kw_funding'] locktime = openchannel2['locktime'] + # ...unless they send us totally unacceptable feerates. + feerate = find_feerate(openchannel2['funding_feerate_best'], + openchannel2['funding_feerate_min'], + openchannel2['funding_feerate_max'], + openchannel2['feerate_our_min'], + openchannel2['feerate_our_max']) + + # Their feerate range is out of bounds, we're not going to + # participate. + if not feerate: + return {'result': 'continue'} + funding = plugin.rpc.fundpsbt(amount, ''.join([str(feerate), 'perkw']), 0, reserve=True, locktime=locktime) psbt_obj = psbt_from_base64(funding['psbt']) @@ -65,7 +90,8 @@ def on_openchannel(openchannel2, plugin, **kwargs): psbt_add_output_at(psbt_obj, 0, 0, output) return {'result': 'continue', 'psbt': psbt_to_base64(psbt_obj, 0), - 'accepter_funding_msat': amount} + 'accepter_funding_msat': amount, + 'funding_feerate': feerate} @plugin.hook('openchannel2_changed')