Browse Source

gossipd: parse and respect optional `htlc_maximum_msat`

If another channel has set the optional `htlc_maximum_msat` field,
we should correctly parse that field and respect it when drawing up
routes for payments.
fee-tracking2
lisa neigut 6 years ago
committed by Rusty Russell
parent
commit
b9331e5ac8
  1. 2
      Makefile
  2. 10
      gossipd/gossip_constants.h
  3. 32
      gossipd/routing.c
  4. 3
      gossipd/routing.h
  5. 3
      gossipd/test/run-bench-find_route.c
  6. 33
      gossipd/test/run-find_route-specific.c
  7. 7
      gossipd/test/run-find_route.c
  8. 2
      lightningd/test/run-invoice-select-inchan.c
  9. 2
      wallet/test/run-wallet.c
  10. 1
      wire/gen_peer_wire_csv

2
Makefile

@ -9,7 +9,7 @@ CCANDIR := ccan
# Where we keep the BOLT RFCs
BOLTDIR := ../lightning-rfc/
BOLTVERSION := 0891374d47ddffa64c5a2e6ad151247e3d6b7a59
BOLTVERSION := b6ae60d24138a3601561fbc1c9d82d983595ae4f
-include config.vars

10
gossipd/gossip_constants.h

@ -23,6 +23,16 @@
#define ROUTING_FLAGS_DIRECTION (1 << 0)
#define ROUTING_FLAGS_DISABLED (1 << 1)
/* BOLT #7:
*
* The `message_flags` bitfield is used to indicate the presence of optional
* fields in the `channel_update` message:
* | Bit Position | Name | Field |
* | ------------- | ------------------------- | -------------------- |
* | 0 | `option_channel_htlc_max` | `htlc_maximum_msat` |
*/
#define ROUTING_OPT_HTLC_MAX_MSAT (1 << 0)
/* BOLT #7:
*
* - MUST NOT send `announcement_signatures` messages until `funding_locked`

32
gossipd/routing.c

@ -361,6 +361,15 @@ static u64 risk_fee(u64 amount, u32 delay, double riskfactor)
return 1 + amount * delay * riskfactor;
}
/* Check that we can fit through this channel's indicated
* maximum_ and minimum_msat requirements.
*/
static bool hc_can_carry(const struct half_chan *hc, u64 requiredcap)
{
return hc->htlc_maximum_msat >= requiredcap &&
hc->htlc_minimum_msat <= requiredcap;
}
/* We track totals, rather than costs. That's because the fee depends
* on the current amount passing through. */
static void bfg_one_edge(struct node *node,
@ -398,13 +407,9 @@ static void bfg_one_edge(struct node *node,
risk = node->bfg[h].risk +
risk_fee(requiredcap, c->delay, riskfactor);
if (requiredcap > chan->satoshis * 1000) {
/* Skip this edge if the channel has insufficient
* capacity to route the required amount */
continue;
} else if (requiredcap < c->htlc_minimum_msat) {
/* Skip a channels if it indicated that it won't route
* the requeuested amount. */
if (!hc_can_carry(c, requiredcap)) {
/* Skip a channel if it indicated that it won't route
* the requested amount. */
continue;
} else if (requiredcap >= MAX_MSATOSHI) {
SUPERVERBOSE("...extreme %"PRIu64
@ -1009,12 +1014,14 @@ static void set_connection_values(struct chan *chan,
u8 message_flags,
u8 channel_flags,
u64 timestamp,
u32 htlc_minimum_msat)
u64 htlc_minimum_msat,
u64 htlc_maximum_msat)
{
struct half_chan *c = &chan->half[idx];
c->delay = delay;
c->htlc_minimum_msat = htlc_minimum_msat;
c->htlc_maximum_msat = htlc_maximum_msat;
c->base_fee = base_fee;
c->proportional_fee = proportional_fee;
c->message_flags = message_flags;
@ -1051,15 +1058,17 @@ bool routing_add_channel_update(struct routing_state *rstate,
u64 htlc_minimum_msat;
u32 fee_base_msat;
u32 fee_proportional_millionths;
u64 htlc_maximum_msat;
struct bitcoin_blkid chain_hash;
struct chan *chan;
u8 direction;
if (!fromwire_channel_update(update, &signature, &chain_hash,
if (!fromwire_channel_update_option_channel_htlc_max(update, &signature, &chain_hash,
&short_channel_id, &timestamp,
&message_flags, &channel_flags,
&expiry, &htlc_minimum_msat, &fee_base_msat,
&fee_proportional_millionths))
&fee_proportional_millionths,
&htlc_maximum_msat))
return false;
chan = get_channel(rstate, &short_channel_id);
if (!chan)
@ -1069,7 +1078,8 @@ bool routing_add_channel_update(struct routing_state *rstate,
set_connection_values(chan, direction, fee_base_msat,
fee_proportional_millionths, expiry,
message_flags, channel_flags,
timestamp, htlc_minimum_msat);
timestamp, htlc_minimum_msat,
htlc_maximum_msat);
/* Replace any old one. */
tal_free(chan->half[direction].channel_update);

3
gossipd/routing.h

@ -29,6 +29,9 @@ struct half_chan {
/* Minimum number of msatoshi in an HTLC */
u32 htlc_minimum_msat;
/* Maximum number of msatoshis in an HTLC */
u64 htlc_maximum_msat;
/* Flags as specified by the `channel_update`s, among other
* things indicated direction wrt the `channel_id` */
u8 channel_flags;

3
gossipd/test/run-bench-find_route.c

@ -65,6 +65,9 @@ bool fromwire_channel_announcement(const tal_t *ctx UNNEEDED, const void *p UNNE
/* Generated stub for fromwire_channel_update */
bool fromwire_channel_update(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, u32 *timestamp UNNEEDED, u8 *message_flags UNNEEDED, u8 *channel_flags UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, u64 *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED)
{ fprintf(stderr, "fromwire_channel_update called!\n"); abort(); }
/* Generated stub for fromwire_channel_update_option_channel_htlc_max */
bool fromwire_channel_update_option_channel_htlc_max(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, u32 *timestamp UNNEEDED, u8 *message_flags UNNEEDED, u8 *channel_flags UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, u64 *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, u64 *htlc_maximum_msat UNNEEDED)
{ fprintf(stderr, "fromwire_channel_update_option_channel_htlc_max called!\n"); abort(); }
/* Generated stub for fromwire_gossip_local_add_channel */
bool fromwire_gossip_local_add_channel(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct pubkey *remote_node_id UNNEEDED, u64 *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_local_add_channel called!\n"); abort(); }

33
gossipd/test/run-find_route-specific.c

@ -29,6 +29,9 @@ bool fromwire_channel_announcement(const tal_t *ctx UNNEEDED, const void *p UNNE
/* Generated stub for fromwire_channel_update */
bool fromwire_channel_update(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, u32 *timestamp UNNEEDED, u8 *message_flags UNNEEDED, u8 *channel_flags UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, u64 *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED)
{ fprintf(stderr, "fromwire_channel_update called!\n"); abort(); }
/* Generated stub for fromwire_channel_update_option_channel_htlc_max */
bool fromwire_channel_update_option_channel_htlc_max(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, u32 *timestamp UNNEEDED, u8 *message_flags UNNEEDED, u8 *channel_flags UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, u64 *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, u64 *htlc_maximum_msat UNNEEDED)
{ fprintf(stderr, "fromwire_channel_update_option_channel_htlc_max called!\n"); abort(); }
/* Generated stub for fromwire_gossip_local_add_channel */
bool fromwire_gossip_local_add_channel(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct pubkey *remote_node_id UNNEEDED, u64 *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_local_add_channel called!\n"); abort(); }
@ -126,8 +129,9 @@ get_or_make_connection(struct routing_state *rstate,
/* Make sure it's seen as initialized (update non-NULL). */
chan->half[idx].channel_update = (void *)chan;
chan->half[idx].htlc_minimum_msat = 0;
chan->half[idx].htlc_maximum_msat = satoshis * 1000;
return &chan->half[pubkey_idx(from_id, to_id)];
return &chan->half[idx];
}
static bool channel_is_between(const struct chan *chan,
@ -151,7 +155,7 @@ int main(void)
static const struct bitcoin_blkid zerohash;
struct half_chan *nc;
struct routing_state *rstate;
struct pubkey a, b, c;
struct pubkey a, b, c, d;
u64 fee;
struct chan **route;
const double riskfactor = 1.0 / BLOCKS_PER_YEAR / 10000;
@ -169,6 +173,9 @@ int main(void)
pubkey_from_hexstr("02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06",
strlen("02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06"),
&c);
pubkey_from_hexstr("02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636",
strlen("02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636"),
&d);
rstate = new_routing_state(tmpctx, &zerohash, &a, 0);
@ -226,11 +233,31 @@ int main(void)
route = find_route(tmpctx, rstate, &a, &c, 999999, riskfactor, 0.0, NULL, &fee);
assert(!route);
/* This should fail to returns a route because it is smaller than these
/* This should fail to return a route because it is smaller than these
* htlc_minimum_msat on the last channel. */
route = find_route(tmpctx, rstate, &a, &c, 1, riskfactor, 0.0, NULL, &fee);
assert(!route);
/* {'active': True, 'short_id': '6990:2:1/0', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 1, 'htlc_maximum_msat': 500000, 'htlc_minimum_msat': 100, 'channel_flags': 0, 'destination': '02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636', 'source': '03c173897878996287a8100469f954dd820fcd8941daed91c327f168f3329be0bf', 'last_update': 1504064344}, */
nc = get_or_make_connection(rstate, &a, &d, "6991:2:1", 1000);
nc->base_fee = 0;
nc->proportional_fee = 0;
nc->delay = 5;
nc->channel_flags = 0;
nc->message_flags = 1;
nc->last_timestamp = 1504064344;
nc->htlc_minimum_msat = 100;
nc->htlc_maximum_msat = 500000; /* half capacity */
/* This should route correctly at the max_msat level */
route = find_route(tmpctx, rstate, &a, &d, 500000, riskfactor, 0.0, NULL, &fee);
assert(route);
/* This should fail to return a route because it's larger than the
* htlc_maximum_msat on the last channel. */
route = find_route(tmpctx, rstate, &a, &d, 500001, riskfactor, 0.0, NULL, &fee);
assert(!route);
tal_free(tmpctx);
secp256k1_context_destroy(secp256k1_ctx);
return 0;

7
gossipd/test/run-find_route.c

@ -27,6 +27,9 @@ bool fromwire_channel_announcement(const tal_t *ctx UNNEEDED, const void *p UNNE
/* Generated stub for fromwire_channel_update */
bool fromwire_channel_update(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, u32 *timestamp UNNEEDED, u8 *message_flags UNNEEDED, u8 *channel_flags UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, u64 *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED)
{ fprintf(stderr, "fromwire_channel_update called!\n"); abort(); }
/* Generated stub for fromwire_channel_update_option_channel_htlc_max */
bool fromwire_channel_update_option_channel_htlc_max(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, u32 *timestamp UNNEEDED, u8 *message_flags UNNEEDED, u8 *channel_flags UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, u64 *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, u64 *htlc_maximum_msat UNNEEDED)
{ fprintf(stderr, "fromwire_channel_update_option_channel_htlc_max called!\n"); abort(); }
/* Generated stub for fromwire_gossip_local_add_channel */
bool fromwire_gossip_local_add_channel(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct pubkey *remote_node_id UNNEEDED, u64 *satoshis UNNEEDED)
{ fprintf(stderr, "fromwire_gossip_local_add_channel called!\n"); abort(); }
@ -112,6 +115,7 @@ static void add_connection(struct routing_state *rstate,
struct short_channel_id scid;
struct half_chan *c;
struct chan *chan;
int satoshis = 100000;
/* Make a unique scid. */
memcpy(&scid, from, sizeof(scid) / 2);
@ -119,7 +123,7 @@ static void add_connection(struct routing_state *rstate,
chan = get_channel(rstate, &scid);
if (!chan)
chan = new_chan(rstate, &scid, from, to, 100000);
chan = new_chan(rstate, &scid, from, to, satoshis);
c = &chan->half[pubkey_idx(from, to)];
/* Make sure it's seen as initialized (update non-NULL). */
@ -129,6 +133,7 @@ static void add_connection(struct routing_state *rstate,
c->delay = delay;
c->channel_flags = get_channel_direction(from, to);
c->htlc_minimum_msat = 0;
c->htlc_maximum_msat = satoshis * 1000;
}
/* Returns chan connecting from and to: *idx set to refer

2
lightningd/test/run-invoice-select-inchan.c

@ -71,7 +71,7 @@ void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UN
void fatal(const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "fatal called!\n"); abort(); }
/* Generated stub for fromwire_connect_peer_connected */
bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **gfeatures UNNEEDED, u8 **lfeatures UNNEEDED)
bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **globalfeatures UNNEEDED, u8 **localfeatures UNNEEDED)
{ fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); }
/* Generated stub for fromwire_gossip_get_incoming_channels_reply */
bool fromwire_gossip_get_incoming_channels_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct route_info **route_info UNNEEDED)

2
wallet/test/run-wallet.c

@ -83,7 +83,7 @@ bool fromwire_channel_offer_htlc_reply(const tal_t *ctx UNNEEDED, const void *p
bool fromwire_channel_sending_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, u32 *feerate UNNEEDED, struct changed_htlc **changed UNNEEDED, secp256k1_ecdsa_signature *commit_sig UNNEEDED, secp256k1_ecdsa_signature **htlc_sigs UNNEEDED)
{ fprintf(stderr, "fromwire_channel_sending_commitsig called!\n"); abort(); }
/* Generated stub for fromwire_connect_peer_connected */
bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **gfeatures UNNEEDED, u8 **lfeatures UNNEEDED)
bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *crypto_state UNNEEDED, u8 **globalfeatures UNNEEDED, u8 **localfeatures UNNEEDED)
{ fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); }
/* Generated stub for fromwire_gossip_resolve_channel_reply */
bool fromwire_gossip_resolve_channel_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey **keys UNNEEDED)

1
wire/gen_peer_wire_csv

@ -149,6 +149,7 @@ channel_update,110,cltv_expiry_delta,2
channel_update,112,htlc_minimum_msat,8
channel_update,120,fee_base_msat,4
channel_update,124,fee_proportional_millionths,4
channel_update,128,htlc_maximum_msat,8,option_channel_htlc_max
query_short_channel_ids,261
query_short_channel_ids,0,chain_hash,32
query_short_channel_ids,32,len,2

Loading…
Cancel
Save