Browse Source

BOLT7: broadcast `htlc_maximum_msat` in `channel_update s

Have c-lightning nodes send out the largest value for
`htlc_maximum_msat` that makes sense, ie the lesser of
the peer's max_inflight_htlc value or the total channel
capacity minus the total channel reserve.
fee-tracking2
lisa neigut 6 years ago
committed by Rusty Russell
parent
commit
0ae1d03513
  1. 27
      channeld/channeld.c
  2. 1
      gossipd/gossip_wire.csv
  3. 29
      gossipd/gossipd.c
  4. 15
      hsmd/hsmd.c
  5. 2
      tests/test_pay.py

27
channeld/channeld.c

@ -60,6 +60,7 @@
#define PEER_FD 3
#define GOSSIP_FD 4
#define HSM_FD 5
#define min(x, y) ((x) < (y) ? (x) : (y))
struct commit_sigs {
struct peer *peer;
@ -227,6 +228,25 @@ static const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES)
return msg;
}
/*
* The maximum msat that this node will accept for an htlc.
* It's flagged as an optional field in `channel_update`.
*
* We advertise the maximum value possible, defined as the smaller
* of the remote's maximum in-flight HTLC or the total channel
* capacity minus the cumulative reserve.
* FIXME: does this need fuzz?
*/
static const u64 advertised_htlc_max(const u64 funding_msat,
const struct channel_config *our_config,
const struct channel_config *remote_config)
{
u64 cumulative_reserve_msat = (our_config->channel_reserve_satoshis +
remote_config->channel_reserve_satoshis) * 1000;
return min(remote_config->max_htlc_value_in_flight_msat,
funding_msat - cumulative_reserve_msat);
}
/* Create and send channel_update to gossipd (and maybe peer) */
static void send_channel_update(struct peer *peer, int disable_flag)
{
@ -247,7 +267,11 @@ static void send_channel_update(struct peer *peer, int disable_flag)
peer->cltv_delta,
peer->conf[REMOTE].htlc_minimum_msat,
peer->fee_base,
peer->fee_per_satoshi);
peer->fee_per_satoshi,
advertised_htlc_max(
peer->channel->funding_msat,
&peer->conf[LOCAL],
&peer->conf[REMOTE]));
wire_sync_write(GOSSIP_FD, take(msg));
}
@ -2306,7 +2330,6 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
/* FIXME: Fuzz the boundaries a bit to avoid probing? */
case CHANNEL_ERR_MAX_HTLC_VALUE_EXCEEDED:
/* FIXME: We should advertise this? */
failcode = WIRE_TEMPORARY_CHANNEL_FAILURE;
failmsg = tal_fmt(inmsg, "Maximum value exceeded");
goto failed;

1
gossipd/gossip_wire.csv

@ -130,6 +130,7 @@ gossip_local_channel_update,,cltv_expiry_delta,u16
gossip_local_channel_update,,htlc_minimum_msat,u64
gossip_local_channel_update,,fee_base_msat,u32
gossip_local_channel_update,,fee_proportional_millionths,u32
gossip_local_channel_update,,htlc_maximum_msat,u64
gossip_local_channel_close,3027
gossip_local_channel_close,,short_channel_id,struct short_channel_id

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

29
gossipd/gossipd.c

@ -942,6 +942,7 @@ static void update_local_channel(struct daemon *daemon,
u64 htlc_minimum_msat,
u32 fee_base_msat,
u32 fee_proportional_millionths,
u64 htlc_maximum_msat,
const char *caller)
{
secp256k1_ecdsa_signature dummy_sig;
@ -949,10 +950,6 @@ static void update_local_channel(struct daemon *daemon,
u32 timestamp = time_now().ts.tv_sec;
u8 message_flags, channel_flags;
/* `message_flags` are optional.
* Currently, not set by c-lightning */
message_flags = 0;
/* So valgrind doesn't complain */
memset(&dummy_sig, 0, sizeof(dummy_sig));
@ -965,7 +962,10 @@ static void update_local_channel(struct daemon *daemon,
if (disable)
channel_flags |= ROUTING_FLAGS_DISABLED;
update = towire_channel_update(tmpctx, &dummy_sig,
// We set the htlc_maximum_msat value
message_flags = 0 | ROUTING_OPT_HTLC_MAX_MSAT;
update = towire_channel_update_option_channel_htlc_max(tmpctx, &dummy_sig,
&daemon->rstate->chain_hash,
&chan->scid,
timestamp,
@ -973,7 +973,8 @@ static void update_local_channel(struct daemon *daemon,
cltv_expiry_delta,
htlc_minimum_msat,
fee_base_msat,
fee_proportional_millionths);
fee_proportional_millionths,
htlc_maximum_msat);
if (!wire_sync_write(HSM_FD,
towire_hsm_cupdate_sig_req(tmpctx, update))) {
@ -1026,6 +1027,7 @@ static void maybe_update_local_channel(struct daemon *daemon,
hc->htlc_minimum_msat,
hc->base_fee,
hc->proportional_fee,
hc->htlc_maximum_msat,
__func__);
}
@ -1093,7 +1095,8 @@ out:
/* Return true if the information has changed. */
static bool halfchan_new_info(const struct half_chan *hc,
u16 cltv_delta, u64 htlc_minimum_msat,
u32 fee_base_msat, u32 fee_proportional_millionths)
u32 fee_base_msat, u32 fee_proportional_millionths,
u64 htlc_maximum_msat)
{
if (!is_halfchan_defined(hc))
return true;
@ -1101,7 +1104,8 @@ static bool halfchan_new_info(const struct half_chan *hc,
return hc->delay != cltv_delta
|| hc->htlc_minimum_msat != htlc_minimum_msat
|| hc->base_fee != fee_base_msat
|| hc->proportional_fee != fee_proportional_millionths;
|| hc->proportional_fee != fee_proportional_millionths
|| hc->htlc_maximum_msat != htlc_maximum_msat;
}
static void handle_local_channel_update(struct peer *peer, const u8 *msg)
@ -1111,6 +1115,7 @@ static void handle_local_channel_update(struct peer *peer, const u8 *msg)
bool disable;
u16 cltv_expiry_delta;
u64 htlc_minimum_msat;
u64 htlc_maximum_msat;
u32 fee_base_msat;
u32 fee_proportional_millionths;
int direction;
@ -1121,7 +1126,8 @@ static void handle_local_channel_update(struct peer *peer, const u8 *msg)
&cltv_expiry_delta,
&htlc_minimum_msat,
&fee_base_msat,
&fee_proportional_millionths)) {
&fee_proportional_millionths,
&htlc_maximum_msat)) {
status_broken("peer %s bad local_channel_update %s",
type_to_string(tmpctx, struct pubkey, &peer->id),
tal_hex(tmpctx, msg));
@ -1151,7 +1157,8 @@ static void handle_local_channel_update(struct peer *peer, const u8 *msg)
* Or, if it's an unannounced channel (only sending to peer). */
if (halfchan_new_info(&chan->half[direction],
cltv_expiry_delta, htlc_minimum_msat,
fee_base_msat, fee_proportional_millionths)
fee_base_msat, fee_proportional_millionths,
htlc_maximum_msat)
|| ((chan->half[direction].channel_flags & ROUTING_FLAGS_DISABLED)
&& !disable)
|| !is_chan_public(chan)) {
@ -1161,6 +1168,7 @@ static void handle_local_channel_update(struct peer *peer, const u8 *msg)
htlc_minimum_msat,
fee_base_msat,
fee_proportional_millionths,
htlc_maximum_msat,
__func__);
}
@ -1748,6 +1756,7 @@ static void gossip_send_keepalive_update(struct daemon *daemon,
hc->htlc_minimum_msat,
hc->base_fee,
hc->proportional_fee,
hc->htlc_maximum_msat,
__func__);
}

15
hsmd/hsmd.c

@ -653,6 +653,7 @@ static struct io_plan *handle_channel_update_sig(struct io_conn *conn,
struct short_channel_id scid;
u32 timestamp, fee_base_msat, fee_proportional_mill;
u64 htlc_minimum_msat;
u64 htlc_maximum_msat;
u8 message_flags, channel_flags;
u16 cltv_expiry_delta;
struct bitcoin_blkid chain_hash;
@ -661,10 +662,11 @@ static struct io_plan *handle_channel_update_sig(struct io_conn *conn,
if (!fromwire_hsm_cupdate_sig_req(tmpctx, msg_in, &cu))
return bad_req(conn, c, msg_in);
if (!fromwire_channel_update(cu, &sig, &chain_hash,
&scid, &timestamp, &message_flags, &channel_flags,
&cltv_expiry_delta, &htlc_minimum_msat,
&fee_base_msat, &fee_proportional_mill)) {
if (!fromwire_channel_update_option_channel_htlc_max(cu, &sig,
&chain_hash, &scid, &timestamp, &message_flags,
&channel_flags, &cltv_expiry_delta,
&htlc_minimum_msat, &fee_base_msat,
&fee_proportional_mill, &htlc_maximum_msat)) {
return bad_req_fmt(conn, c, msg_in, "Bad inner channel_update");
}
if (tal_count(cu) < offset)
@ -676,10 +678,11 @@ static struct io_plan *handle_channel_update_sig(struct io_conn *conn,
sign_hash(&node_pkey, &hash, &sig);
cu = towire_channel_update(tmpctx, &sig, &chain_hash,
cu = towire_channel_update_option_channel_htlc_max(tmpctx, &sig, &chain_hash,
&scid, timestamp, message_flags, channel_flags,
cltv_expiry_delta, htlc_minimum_msat,
fee_base_msat, fee_proportional_mill);
fee_base_msat, fee_proportional_mill,
htlc_maximum_msat);
return req_reply(conn, c, take(towire_hsm_cupdate_sig_reply(NULL, cu)));
}

2
tests/test_pay.py

@ -150,7 +150,7 @@ def test_pay_get_error_with_update(node_factory):
# channel_update, and it should patch it to include a type prefix. The
# prefix 0x0102 should be in the channel_update, but not in the
# onionreply (negation of 0x0102 in the RE)
l1.daemon.wait_for_log(r'Extracted channel_update 0102.*from onionreply 10070080(?!.*0102)')
l1.daemon.wait_for_log(r'Extracted channel_update 0102.*from onionreply 10070088[0-9a-fA-F]{88}')
# And now monitor for l1 to apply the channel_update we just extracted
l1.daemon.wait_for_log('Received channel_update for channel {}\(.\) now DISABLED was ACTIVE \(from error\)'.format(chanid2))

Loading…
Cancel
Save