Browse Source

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.
travis-experimental
niftynei 4 years ago
committed by neil saitug
parent
commit
4ea9d9e928
  1. 81
      lightningd/dual_open_control.c
  2. 55
      openingd/dualopend.c
  3. 5
      openingd/dualopend_wire.csv
  4. 20
      openingd/dualopend_wiregen.c
  5. 10
      openingd/dualopend_wiregen.h
  6. 32
      tests/plugins/df_accepter.py

81
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);
}

55
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]) {

5
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

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

20
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

10
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

32
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')

Loading…
Cancel
Save