core-lightning/common/gossmap.h
Rusty Russell daba3e7deb common/gossmap: helper to map the gossip store.
I went overboard on optimization.  I am so sorry:
1. Squeezed channel min/max into 16 bits.
2. Uses mmap and leaves node_ids in the file.
3. Uses offsets instead of pointers where possible.
4. Uses custom free-list to allocate inside arrays.
5. Ignores our autogenerated marshalling code in favor of direct derefs.
6. Carefully aligns everything so we use minimal ram.

The result is that the current gossip_store:
 - load time (-O3 -flto laptop): 40msec
 - load time (-g laptop i.e. DEVELOPER=0): 60msec
 - load time (-O0 laptop i.e. DEVELOPER=1): 110msec
 - Total memory: 2.6MB:
   - 1.5MB for the array of channels
   - 512k for the channel htable to map scid -> channel.
   - 320k for the node htable to map nodeid -> node.
   - 192k for the array of channels inside each node
   - 94k for the array of nodes

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2020-08-28 10:56:50 +09:30

131 lines
4.3 KiB
C

#ifndef LIGHTNING_COMMON_GOSSMAP_H
#define LIGHTNING_COMMON_GOSSMAP_H
#include "config.h"
#include <bitcoin/short_channel_id.h>
#include <ccan/typesafe_cb/typesafe_cb.h>
#include <common/amount.h>
struct node_id;
/* 5 bit exponent, 11 bit mantissa approximations of min/max */
typedef u16 fp16_t;
struct gossmap_node {
/* Offset in memory map for node_announce, or 0. */
u32 nann_off;
u32 num_chans;
u32 *chan_idxs;
};
struct gossmap_chan {
u32 cann_off;
/* Technically redundant, but we have a hole anyway. */
u32 scid_off;
/* two nodes we connect (lesser idx first) */
struct half_chan {
/* Top bit indicates it's enabled */
u32 enabled: 1;
u32 nodeidx : 31;
fp16_t htlc_min, htlc_max;
/* millisatoshi. */
u64 base_fee : 24;
/* millionths */
u64 proportional_fee : 20;
/* Delay for HTLC in blocks. */
u64 delay : 20;
} half[2];
};
static inline u64 fp16_to_u64(fp16_t val)
{
return ((u64)val & ((1 << 11)-1)) << (val >> 11);
}
struct gossmap *gossmap_load(const tal_t *ctx, const char *filename);
/* Call this before using to ensure it's up-to-date. Returns true if something
* was updated. Note: this can scramble node and chan indexes! */
bool gossmap_refresh(struct gossmap *map);
/* Each channel has a unique (low) index. */
u32 gossmap_node_idx(const struct gossmap *map, const struct gossmap_node *node);
u32 gossmap_chan_idx(const struct gossmap *map, const struct gossmap_chan *chan);
/* Every node_idx/chan_idx will be < these.
* These values can change across calls to gossmap_check. */
u32 gossmap_max_node_idx(const struct gossmap *map);
u32 gossmap_max_chan_idx(const struct gossmap *map);
/* Find node with this node_id */
struct gossmap_node *gossmap_find_node(const struct gossmap *map,
const struct node_id *id);
/* Find chan with this short_channel_id */
struct gossmap_chan *gossmap_find_chan(const struct gossmap *map,
const struct short_channel_id *scid);
/* Get the short_channel_id of this chan */
struct short_channel_id gossmap_chan_scid(const struct gossmap *map,
const struct gossmap_chan *c);
/* Given a struct node, get the node_id */
void gossmap_node_get_id(const struct gossmap *map,
const struct gossmap_node *node,
struct node_id *id);
/* Do we have any values for this halfchannel ? */
static inline bool gossmap_chan_set(const struct gossmap_chan *chan, int dir)
{
return chan->half[dir].htlc_max != 0;
}
/* Get the announcement msg which created this chan */
u8 *gossmap_chan_get_announce(const tal_t *ctx,
const struct gossmap *map,
const struct gossmap_chan *c);
/* Get the announcement msg (if any) for this node. */
u8 *gossmap_node_get_announce(const tal_t *ctx,
const struct gossmap *map,
const struct gossmap_node *n);
/* Given a struct node, get the nth channel, and tell us if we're half[0/1].
* n must be less than node->num_chans */
struct gossmap_chan *gossmap_nth_chan(const struct gossmap *map,
const struct gossmap_node *node,
u32 n,
int *which_half);
/* Given a struct chan, get the nth node, where n is 0 or 1. */
struct gossmap_node *gossmap_nth_node(const struct gossmap *map,
const struct gossmap_chan *chan,
int n);
/* Can this channel send this amount? */
bool gossmap_chan_capacity(const struct gossmap_chan *chan,
int direction,
struct amount_msat amount);
/* Remove a channel from the map (warning! realloc can move gossmap_chan
* and gossmap_node ptrs!) */
void gossmap_remove_chan(struct gossmap *map, struct gossmap_chan *chan);
/* Remove node (by removing all its channels) */
void gossmap_remove_node(struct gossmap *map, struct gossmap_node *node);
/* Unsorted iterate through (do not add/remove channels or nodes!) */
size_t gossmap_num_nodes(const struct gossmap *map);
struct gossmap_node *gossmap_first_node(const struct gossmap *map);
struct gossmap_node *gossmap_next_node(const struct gossmap *map,
const struct gossmap_node *prev);
/* Unsorted iterate through (do not add/remove channels or nodes!) */
size_t gossmap_num_chans(const struct gossmap *map);
struct gossmap_chan *gossmap_first_chan(const struct gossmap *map);
struct gossmap_chan *gossmap_next_chan(const struct gossmap *map,
struct gossmap_chan *prev);
#endif /* LIGHTNING_COMMON_GOSSMAP_H */