From f8f6533dba0f439f3e5f0214258f0a83e0ac0340 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 8 Apr 2019 09:21:30 +0930 Subject: [PATCH] dev: --dev-gossip-time so gossipd doesn't prune old data. This is useful for canned data, such as the million channels project. Signed-off-by: Rusty Russell --- gossipd/gossip_wire.csv | 1 + gossipd/gossipd.c | 8 ++++--- gossipd/routing.c | 30 +++++++++++++++++++++----- gossipd/routing.h | 16 +++++++++++++- gossipd/test/run-bench-find_route.c | 2 +- gossipd/test/run-find_route-specific.c | 2 +- gossipd/test/run-find_route.c | 2 +- lightningd/gossip_control.c | 8 ++++++- lightningd/lightningd.c | 1 + lightningd/lightningd.h | 3 +++ lightningd/options.c | 4 ++++ 11 files changed, 64 insertions(+), 13 deletions(-) diff --git a/gossipd/gossip_wire.csv b/gossipd/gossip_wire.csv index 4d1b9e5d8..5b6a1ec0a 100644 --- a/gossipd/gossip_wire.csv +++ b/gossipd/gossip_wire.csv @@ -14,6 +14,7 @@ gossipctl_init,,alias,32*u8 gossipctl_init,,update_channel_interval,u32 gossipctl_init,,num_announcable,u16 gossipctl_init,,announcable,num_announcable*struct wireaddr +gossipctl_init,,dev_gossip_time,?u32 # Pass JSON-RPC getnodes call through gossip_getnodes_request,3005 diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 4a1de1b22..d6b2d61bd 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1859,6 +1859,7 @@ static struct io_plan *gossip_init(struct io_conn *conn, const u8 *msg) { u32 update_channel_interval; + u32 *dev_gossip_time; if (!fromwire_gossipctl_init(daemon, msg, /* 60,000 ms @@ -1871,7 +1872,8 @@ static struct io_plan *gossip_init(struct io_conn *conn, /* 1 week in seconds * (unless --dev-channel-update-interval) */ &update_channel_interval, - &daemon->announcable)) { + &daemon->announcable, + &dev_gossip_time)) { master_badmsg(WIRE_GOSSIPCTL_INIT, msg); } @@ -1879,8 +1881,8 @@ static struct io_plan *gossip_init(struct io_conn *conn, daemon->rstate = new_routing_state(daemon, chainparams_by_chainhash(&daemon->chain_hash), &daemon->id, - update_channel_interval * 2); - + update_channel_interval * 2, + dev_gossip_time); /* Load stored gossip messages */ gossip_store_load(daemon->rstate, daemon->rstate->store); diff --git a/gossipd/routing.c b/gossipd/routing.c index 0d8476d3b..06588814d 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -82,7 +82,8 @@ static struct node_map *empty_node_map(const tal_t *ctx) struct routing_state *new_routing_state(const tal_t *ctx, const struct chainparams *chainparams, const struct pubkey *local_id, - u32 prune_timeout) + u32 prune_timeout, + const u32 *dev_gossip_time) { struct routing_state *rstate = tal(ctx, struct routing_state); rstate->nodes = empty_node_map(rstate); @@ -99,6 +100,16 @@ struct routing_state *new_routing_state(const tal_t *ctx, rstate->pending_node_map = tal(ctx, struct pending_node_map); pending_node_map_init(rstate->pending_node_map); + +#if DEVELOPER + if (dev_gossip_time) { + rstate->gossip_time = tal(rstate, struct timeabs); + rstate->gossip_time->ts.tv_sec = *dev_gossip_time; + rstate->gossip_time->ts.tv_nsec = 0; + } else + rstate->gossip_time = NULL; +#endif + return rstate; } @@ -270,7 +281,7 @@ static void init_half_chan(struct routing_state *rstate, c->message_flags = 0; /* We haven't seen channel_update: make it halfway to prune time, * which should be older than any update we'd see. */ - c->last_timestamp = time_now().ts.tv_sec - rstate->prune_timeout/2; + c->last_timestamp = gossip_time_now(rstate).ts.tv_sec - rstate->prune_timeout/2; } static void bad_gossip_order(const u8 *msg, const char *source, @@ -1273,7 +1284,7 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES, * - if the `timestamp` is unreasonably far in the future: * - MAY discard the `channel_update`. */ - if (timestamp > time_now().ts.tv_sec + rstate->prune_timeout) { + if (timestamp > gossip_time_now(rstate).ts.tv_sec + rstate->prune_timeout) { status_debug("Received channel_update for %s with far time %u", type_to_string(tmpctx, struct short_channel_id, &short_channel_id), @@ -1282,7 +1293,7 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES, } /* Note: we can consider old timestamps a case of "instant prune" too */ - if (timestamp < time_now().ts.tv_sec - rstate->prune_timeout) { + if (timestamp < gossip_time_now(rstate).ts.tv_sec - rstate->prune_timeout) { status_debug("Received channel_update for %s with old time %u", type_to_string(tmpctx, struct short_channel_id, &short_channel_id), @@ -1721,7 +1732,7 @@ void routing_failure(struct routing_state *rstate, void route_prune(struct routing_state *rstate) { - u64 now = time_now().ts.tv_sec; + u64 now = gossip_time_now(rstate).ts.tv_sec; /* Anything below this highwater mark ought to be pruned */ const s64 highwater = now - rstate->prune_timeout; const tal_t *pruned = tal(NULL, char); @@ -1799,3 +1810,12 @@ bool handle_local_add_channel(struct routing_state *rstate, const u8 *msg) new_chan(rstate, &scid, &rstate->local_id, &remote_node_id, sat); return true; } + +struct timeabs gossip_time_now(const struct routing_state *rstate) +{ +#if DEVELOPER + if (rstate->gossip_time) + return *rstate->gossip_time; +#endif + return time_now(); +} diff --git a/gossipd/routing.h b/gossipd/routing.h index 6998e57af..ba6f30d44 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -214,6 +214,11 @@ struct routing_state { /* Cache for txout queries that failed. Allows us to skip failed * checks if we get another announcement for the same scid. */ UINTMAP(bool) txout_failures; + +#if DEVELOPER + /* Override local time for gossip messages */ + struct timeabs *gossip_time; +#endif }; static inline struct chan * @@ -234,7 +239,8 @@ struct route_hop { struct routing_state *new_routing_state(const tal_t *ctx, const struct chainparams *chainparams, const struct pubkey *local_id, - u32 prune_timeout); + u32 prune_timeout, + const u32 *dev_gossip_time); /** * Add a new bidirectional channel from id1 to id2 with the given @@ -345,4 +351,12 @@ bool handle_local_add_channel(struct routing_state *rstate, const u8 *msg); void memleak_remove_routing_tables(struct htable *memtable, const struct routing_state *rstate); #endif + +/** + * Get the local time. + * + * This gets overridden in dev mode so we can use canned (stale) gossip. + */ +struct timeabs gossip_time_now(const struct routing_state *rstate); + #endif /* LIGHTNING_GOSSIPD_ROUTING_H */ diff --git a/gossipd/test/run-bench-find_route.c b/gossipd/test/run-bench-find_route.c index ad702243d..80a7b3f95 100644 --- a/gossipd/test/run-bench-find_route.c +++ b/gossipd/test/run-bench-find_route.c @@ -225,7 +225,7 @@ int main(int argc, char *argv[]) setup_tmpctx(); me = nodeid(0); - rstate = new_routing_state(tmpctx, NULL, &me, 0); + rstate = new_routing_state(tmpctx, NULL, &me, 0, NULL); opt_register_noarg("--perfme", opt_set_bool, &perfme, "Run perfme-start and perfme-stop around benchmark"); diff --git a/gossipd/test/run-find_route-specific.c b/gossipd/test/run-find_route-specific.c index f3c73bf14..af9513b0b 100644 --- a/gossipd/test/run-find_route-specific.c +++ b/gossipd/test/run-find_route-specific.c @@ -184,7 +184,7 @@ int main(void) strlen("02cca6c5c966fcf61d121e3a70e03a1cd9eeeea024b26ea666ce974d43b242e636"), &d); - rstate = new_routing_state(tmpctx, NULL, &a, 0); + rstate = new_routing_state(tmpctx, NULL, &a, 0, NULL); /* [{'active': True, 'short_id': '6990:2:1/1', 'fee_per_kw': 10, 'delay': 5, 'message_flags': 0, 'channel_flags': 1, 'destination': '0230ad0e74ea03976b28fda587bb75bdd357a1938af4424156a18265167f5e40ae', 'source': '02ea622d5c8d6143f15ed3ce1d501dd0d3d09d3b1c83a44d0034949f8a9ab60f06', 'last_update': 1504064344}, */ diff --git a/gossipd/test/run-find_route.c b/gossipd/test/run-find_route.c index 34a5c6131..51f1a3b14 100644 --- a/gossipd/test/run-find_route.c +++ b/gossipd/test/run-find_route.c @@ -213,7 +213,7 @@ int main(void) memset(&tmp, 'a', sizeof(tmp)); pubkey_from_privkey(&tmp, &a); - rstate = new_routing_state(tmpctx, NULL, &a, 0); + rstate = new_routing_state(tmpctx, NULL, &a, 0, NULL); new_node(rstate, &a); diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 6b8ffdae1..7a1fa32d3 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -164,7 +164,13 @@ void gossip_init(struct lightningd *ld, int connectd_fd) get_offered_globalfeatures(tmpctx), ld->rgb, ld->alias, ld->config.channel_update_interval, - ld->announcable); + ld->announcable, +#if DEVELOPER + ld->dev_gossip_time ? &ld->dev_gossip_time: NULL +#else + NULL +#endif + ); subd_send_msg(ld->gossip, msg); } diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index b26441d99..fb4738a6c 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -116,6 +116,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->dev_disconnect_fd = -1; ld->dev_subdaemon_fail = false; ld->dev_allow_localhost = false; + ld->dev_gossip_time = 0; #endif /*~ These are CCAN lists: an embedded double-linked list. It's not diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 680e45dcd..3728d0761 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -196,6 +196,9 @@ struct lightningd { /* Allow and accept localhost node_announcement addresses */ bool dev_allow_localhost; + /* Timestamp to use for gossipd, iff non-zero */ + u32 dev_gossip_time; + /* Things we've marked as not leaking. */ const void **notleaks; #endif /* DEVELOPER */ diff --git a/lightningd/options.c b/lightningd/options.c index 146711b1a..0a3dea5c7 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -475,6 +475,10 @@ static void dev_register_opts(struct lightningd *ld) "--dev-channel-update-interval=", opt_set_u32, opt_show_u32, &ld->config.channel_update_interval, "Time in seconds between channel updates for our own channels."); + + opt_register_arg("--dev-gossip-time", opt_set_u32, opt_show_u32, + &ld->dev_gossip_time, + "UNIX time to override gossipd to use."); } #endif