lightningd/opening: receive details for remote config acceptance, not min/max.

The requirements for accepting the remote config are more complex than
a simple min/max value, as various parameters are related.  It turns
out that with a few assumptions, we can boil this down to:

1.  The valid feerate range.
2.  The minimum effective HTLC throughput we want
3.  The a maximum delay we'll accept for us to redeem.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-02-24 16:22:56 +10:30
parent a8b9177e9e
commit 6cf8a19881
2 changed files with 149 additions and 62 deletions

View File

@ -59,7 +59,11 @@ struct state {
/* Our shaseed for generating per-commitment-secrets. */
struct sha256 shaseed;
struct channel_config localconf, *remoteconf, minconf, maxconf;
struct channel_config localconf, *remoteconf;
/* Limits on what remote config we accept */
u32 max_to_self_delay;
u64 min_effective_htlc_capacity_msat;
struct channel *channel;
};
@ -120,55 +124,94 @@ static void derive_our_basepoints(const struct privkey *seed,
&per_commit_secret));
}
/* Yes, this multi-evaluates, and isn't do-while wrapped. */
#define test_config_inrange(conf, min, max, field, fmt) \
if ((conf)->field < (min)->field || (conf)->field > (max)->field) \
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_BAD_CONFIG, \
#field " %"fmt" too large (%"fmt"-%"fmt")", \
(conf)->field, (min)->field, (max)->field)
#define test_config_inrange_u64(conf, min, max, field) \
test_config_inrange(conf, min, max, field, PRIu64)
#define test_config_inrange_u32(conf, min, max, field) \
test_config_inrange(conf, min, max, field, "u")
#define test_config_inrange_u16(conf, min, max, field) \
test_config_inrange(conf, min, max, field, "u")
static void check_config_bounds(struct state *state,
const struct channel_config *remoteconf,
const struct channel_config *minc,
const struct channel_config *maxc)
const struct channel_config *remoteconf)
{
/* BOLT #2:
*
* It MUST fail the channel if `max-accepted-htlcs` is greater than
* 511.
*/
if (maxc->max_accepted_htlcs > 511)
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_BAD_PARAM,
"max->max_accepted_htlcs %u too large",
maxc->max_accepted_htlcs);
u64 capacity_msat;
u64 reserve_msat;
/* BOLT #2:
*
* The receiving node MUST fail the channel if `to-self-delay` is
* unreasonably large. The receiver MAY fail the channel if
* `funding-satoshis` is too small.... The receiving node MAY fail
* the channel if it considers `htlc-minimum-msat` too large,
* unreasonably large.
*/
if (remoteconf->to_self_delay > state->max_to_self_delay)
peer_failed(PEER_FD, &state->cs, NULL,
WIRE_OPENING_PEER_BAD_CONFIG,
"to_self_delay %u larger than %u",
remoteconf->to_self_delay, state->max_to_self_delay);
/* BOLT #2:
*
* The receiver MAY fail the channel if `funding-satoshis` is too
* small, and MUST fail the channel if `push-msat` is greater than
* `funding-amount` * 1000. The receiving node MAY fail the channel
* if it considers `htlc-minimum-msat` too large,
* `max-htlc-value-in-flight` too small, `channel-reserve-satoshis`
* too large, or `max-accepted-htlcs` too small.
*
* The receiver MUST fail the channel if it considers `feerate-per-kw`
* too small for timely processing, or unreasonably large.
*/
/* We simply compare every field, and let the master daemon sort out
the bounds. */
test_config_inrange_u64(remoteconf, minc, maxc, dust_limit_satoshis);
test_config_inrange_u64(remoteconf, minc, maxc, channel_reserve_satoshis);
test_config_inrange_u32(remoteconf, minc, maxc, minimum_depth);
test_config_inrange_u32(remoteconf, minc, maxc, htlc_minimum_msat);
test_config_inrange_u16(remoteconf, minc, maxc, to_self_delay);
test_config_inrange_u16(remoteconf, minc, maxc, max_accepted_htlcs);
/* We accumulate this into an effective bandwidth minimum. */
/* Overflow check before capacity calc. */
if (remoteconf->channel_reserve_satoshis > state->funding_satoshis)
peer_failed(PEER_FD, &state->cs, NULL,
WIRE_OPENING_PEER_BAD_CONFIG,
"Invalid channel_reserve_satoshis %"PRIu64
" for funding_satoshis %"PRIu64,
remoteconf->channel_reserve_satoshis,
state->funding_satoshis);
/* Consider highest reserve. */
reserve_msat = remoteconf->channel_reserve_satoshis * 1000;
if (state->localconf.channel_reserve_satoshis * 1000 > reserve_msat)
reserve_msat = state->localconf.channel_reserve_satoshis * 1000;
capacity_msat = state->funding_satoshis * 1000 - reserve_msat;
if (remoteconf->max_htlc_value_in_flight_msat < capacity_msat)
capacity_msat = remoteconf->max_htlc_value_in_flight_msat;
if (remoteconf->htlc_minimum_msat * (u64)1000 > capacity_msat)
peer_failed(PEER_FD, &state->cs, NULL,
WIRE_OPENING_PEER_BAD_CONFIG,
"Invalid htlc_minimum_msat %u"
" for funding_satoshis %"PRIu64
" capacity_msat %"PRIu64,
remoteconf->htlc_minimum_msat,
state->funding_satoshis,
capacity_msat);
if (capacity_msat < state->min_effective_htlc_capacity_msat)
peer_failed(PEER_FD, &state->cs, NULL,
WIRE_OPENING_PEER_BAD_CONFIG,
"Channel capacity with funding %"PRIu64" msat,"
" reserves %"PRIu64"/%"PRIu64" msat,"
" max_htlc_value_in_flight_msat %"PRIu64
" is %"PRIu64" msat, which is below %"PRIu64" msat",
state->funding_satoshis * 1000,
remoteconf->channel_reserve_satoshis * 1000,
state->localconf.channel_reserve_satoshis * 1000,
remoteconf->max_htlc_value_in_flight_msat,
capacity_msat,
state->min_effective_htlc_capacity_msat);
/* We don't worry about how many HTLCs they accept, as long as > 0! */
if (remoteconf->max_accepted_htlcs == 0)
peer_failed(PEER_FD, &state->cs, NULL,
WIRE_OPENING_PEER_BAD_CONFIG,
"max_accepted_htlcs %u invalid",
remoteconf->max_accepted_htlcs);
/* BOLT #2:
*
* It MUST fail the channel if `max-accepted-htlcs` is greater
* than 511.
*/
if (remoteconf->max_accepted_htlcs > 511)
peer_failed(PEER_FD, &state->cs, NULL,
WIRE_OPENING_PEER_BAD_CONFIG,
"max_accepted_htlcs %u too large",
remoteconf->max_accepted_htlcs);
}
static bool check_commit_sig(const struct state *state,
@ -207,7 +250,14 @@ sign_remote_commit(const struct state *state,
return sig;
}
static void open_channel(struct state *state, const struct points *ours)
/* We always set channel_reserve_satoshis to 1%, rounded up. */
static void set_reserve(u64 *reserve, u64 funding)
{
*reserve = (funding + 99) / 100;
}
static void open_channel(struct state *state, const struct points *ours,
u32 max_minimum_depth)
{
struct channel_id tmpid, tmpid2;
u8 *msg;
@ -215,6 +265,9 @@ static void open_channel(struct state *state, const struct points *ours)
struct points theirs;
secp256k1_ecdsa_signature sig;
set_reserve(&state->localconf.channel_reserve_satoshis,
state->funding_satoshis);
/* BOLT #2:
*
* A sending node MUST set the most significant bit in
@ -279,8 +332,8 @@ static void open_channel(struct state *state, const struct points *ours)
->max_htlc_value_in_flight_msat,
&state->remoteconf
->channel_reserve_satoshis,
&state->remoteconf->minimum_depth,
&state->remoteconf->htlc_minimum_msat,
&state->feerate_per_kw,
&state->remoteconf->to_self_delay,
&state->remoteconf->max_accepted_htlcs,
&theirs.funding_pubkey,
@ -301,8 +354,19 @@ static void open_channel(struct state *state, const struct points *ours)
type_to_string(msg, struct channel_id, &tmpid),
type_to_string(msg, struct channel_id, &tmpid2));
check_config_bounds(state, state->remoteconf,
&state->minconf, &state->maxconf);
/* BOLT #2:
*
* The receiver MAY reject the `minimum-depth` if it considers it
* unreasonably large.
*
* Other fields have the same requirements as their counterparts in
* `open_channel`.
*/
if (state->remoteconf->minimum_depth > max_minimum_depth)
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_BAD_PARAM,
"minimum_depth %u larger than %u",
state->remoteconf->minimum_depth, max_minimum_depth);
check_config_bounds(state, state->remoteconf);
/* Now, ask master create a transaction to pay those two addresses. */
msg = towire_opening_open_resp(state, &ours->funding_pubkey,
@ -419,7 +483,7 @@ static void open_channel(struct state *state, const struct points *ours)
/* This is handed the message the peer sent which caused gossip to stop:
* it should be an open_channel */
static void recv_channel(struct state *state, const struct points *ours,
const u8 *peer_msg)
u32 min_feerate, u32 max_feerate, const u8 *peer_msg)
{
struct channel_id tmpid, tmpid2;
struct points theirs;
@ -474,16 +538,32 @@ static void recv_channel(struct state *state, const struct points *ours,
" too large for funding_satoshis %"PRIu64,
state->push_msat, state->funding_satoshis);
check_config_bounds(state, state->remoteconf,
&state->minconf, &state->maxconf);
/* BOLT #3:
*
* The receiver MUST fail the channel if it considers `feerate-per-kw`
* too small for timely processing, or unreasonably large.
*/
if (state->feerate_per_kw < min_feerate)
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_BAD_FUNDING,
"feerate_per_kw %u below minimum %u",
state->feerate_per_kw, min_feerate);
if (state->feerate_per_kw > max_feerate)
peer_failed(PEER_FD, &state->cs, NULL, WIRE_OPENING_PEER_BAD_FUNDING,
"feerate_per_kw %u above maximum %u",
state->feerate_per_kw, max_feerate);
set_reserve(&state->localconf.channel_reserve_satoshis,
state->funding_satoshis);
check_config_bounds(state, state->remoteconf);
msg = towire_accept_channel(state, &tmpid,
state->localconf.dust_limit_satoshis,
state->localconf
.max_htlc_value_in_flight_msat,
state->localconf.channel_reserve_satoshis,
state->localconf.minimum_depth,
state->localconf.htlc_minimum_msat,
state->feerate_per_kw,
state->localconf.to_self_delay,
state->localconf.max_accepted_htlcs,
&ours->funding_pubkey,
@ -595,6 +675,8 @@ int main(int argc, char *argv[])
struct state *state = tal(NULL, struct state);
struct privkey seed;
struct points our_points;
u32 max_minimum_depth;
u32 min_feerate, max_feerate;
if (argc == 2 && streq(argv[1], "--version")) {
printf("%s\n", version());
@ -615,8 +697,8 @@ int main(int argc, char *argv[])
if (!fromwire_opening_init(msg, NULL,
&state->localconf,
&state->minconf,
&state->maxconf,
&state->max_to_self_delay,
&state->min_effective_htlc_capacity_msat,
&state->cs,
&seed))
status_failed(WIRE_OPENING_BAD_COMMAND, "%s", strerror(errno));
@ -630,10 +712,12 @@ int main(int argc, char *argv[])
if (fromwire_opening_open(msg, NULL,
&state->funding_satoshis,
&state->push_msat,
&state->feerate_per_kw))
open_channel(state, &our_points);
else if (fromwire_opening_accept(state, msg, NULL, &peer_msg))
recv_channel(state, &our_points, peer_msg);
&state->feerate_per_kw, &max_minimum_depth))
open_channel(state, &our_points, max_minimum_depth);
else if (fromwire_opening_accept(state, msg, NULL, &min_feerate,
&max_feerate, &peer_msg))
recv_channel(state, &our_points, min_feerate, max_feerate,
peer_msg);
/* Hand back the fd. */
fdpass_send(REQ_FD, PEER_FD);

View File

@ -1,20 +1,21 @@
#include <lightningd/cryptomsg.h>
#include <lightningd/channel_config.h>
opening_init,0
# What configuration we'll offer
# Base configuration we'll offer (channel reserve will vary with amount)
opening_init,0,our_config,36,struct channel_config
# Minimum/maximum configuration values we'll accept
opening_init,36,min_config,36,struct channel_config
opening_init,72,max_config,36,struct channel_config
opening_init,108,crypto_state,144,struct crypto_state
opening_init,36,max_to_self_delay,4
opening_init,40,min_effective_htlc_capacity_msat,8
opening_init,48,crypto_state,144,struct crypto_state
# Seed to generate all the keys from
opening_init,252,seed,32,struct privkey
opening_init,196,seed,32,struct privkey
# This means we offer the open.
opening_open,1
opening_open,0,funding_satoshis,8
opening_open,8,push_msat,8
opening_open,16,feerate_per_kw,4
opening_open,20,max_minimum_depth,4
# Response asks for txid of funding transaction.
opening_open_resp,101
@ -38,8 +39,10 @@ opening_open_funding_resp,343,their_per_commit_point,33
# This means they offer the open (contains their offer packet)
opening_accept,3
opening_accept,0,len,2
opening_accept,2,msg,len,u8
opening_accept,0,min_feerate,4
opening_accept,4,max_feerate,4
opening_accept,8,len,2
opening_accept,10,msg,len,u8
# This gives the txid of their funding tx: we're done.
opening_accept_resp,103

1 #include <lightningd/cryptomsg.h>
2 #include <lightningd/channel_config.h>
3 opening_init,0
4 # What configuration we'll offer # Base configuration we'll offer (channel reserve will vary with amount)
5 opening_init,0,our_config,36,struct channel_config
6 # Minimum/maximum configuration values we'll accept
7 opening_init,36,min_config,36,struct channel_config opening_init,36,max_to_self_delay,4
8 opening_init,72,max_config,36,struct channel_config opening_init,40,min_effective_htlc_capacity_msat,8
9 opening_init,108,crypto_state,144,struct crypto_state opening_init,48,crypto_state,144,struct crypto_state
10 # Seed to generate all the keys from
11 opening_init,252,seed,32,struct privkey opening_init,196,seed,32,struct privkey
12 # This means we offer the open.
13 opening_open,1
14 opening_open,0,funding_satoshis,8
15 opening_open,8,push_msat,8
16 opening_open,16,feerate_per_kw,4
17 # Response asks for txid of funding transaction. opening_open,20,max_minimum_depth,4
18 # Response asks for txid of funding transaction.
19 opening_open_resp,101
20 opening_open_resp,0,local_fundingkey,33
21 opening_open_resp,0,remote_fundingkey,33
39 # This gives the txid of their funding tx: we're done. opening_accept,8,len,2
40 opening_accept_resp,103 opening_accept,10,msg,len,u8
41 opening_accept_resp,0,funding_txid,32,struct sha256_double # This gives the txid of their funding tx: we're done.
42 opening_accept_resp,32,funding_txout,1,u8 opening_accept_resp,103
43 opening_accept_resp,33,their_config,36,struct channel_config opening_accept_resp,0,funding_txid,32,struct sha256_double
44 opening_accept_resp,32,funding_txout,1,u8
45 opening_accept_resp,33,their_config,36,struct channel_config
46 opening_accept_resp,69,first_commit_sig,64,secp256k1_ecdsa_signature
47 opening_accept_resp,133,crypto_state,144,struct crypto_state
48 opening_accept_resp,277,remote_fundingkey,33