From 5591c0b5d81fe91e99ad2eefd673af88a13bfb71 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 4 Jun 2019 03:45:25 +0930 Subject: [PATCH] gossipd: don't send gossip stream, let per-peer daemons read it themselves. Keeping the uintmap ordering all the broadcastable messages is expensive: 130MB for the million-channels project. But now we delete obsolete entries from the store, we can have the per-peer daemons simply read that sequentially and stream the gossip itself. This is the most primitive version, where all gossip is streamed; successive patches will bring back proper handling of timestamp filtering and initial_routing_sync. We add a gossip_state field to track what's happening with our gossip streaming: it's initialized in gossipd, and currently always set, but once we handle timestamps the per-peer daemon may do it when the first filter is sent. Signed-off-by: Rusty Russell --- channeld/channeld.c | 16 +- common/gossip_store.c | 130 +++++++++++--- common/gossip_store.h | 13 +- common/per_peer_state.c | 72 +++++++- common/per_peer_state.h | 25 ++- common/read_peer_msg.c | 52 +++--- connectd/connect_gossip_wire.csv | 2 + connectd/connect_wire.csv | 2 +- connectd/connectd.c | 34 ++-- gossipd/Makefile | 2 +- gossipd/gossip_peerd_wire.csv | 6 +- gossipd/gossip_store.c | 43 ++++- gossipd/gossip_wire.csv | 1 - gossipd/gossipd.c | 185 +++----------------- gossipd/test/run-bench-find_route.c | 3 - gossipd/test/run-find_route-specific.c | 3 - gossipd/test/run-find_route.c | 3 - gossipd/test/run-overlong.c | 3 - lightningd/gossip_control.c | 2 +- lightningd/peer_control.c | 12 +- lightningd/test/run-invoice-select-inchan.c | 6 +- openingd/openingd.c | 19 +- tests/test_gossip.py | 2 + wallet/test/run-wallet.c | 6 +- 24 files changed, 375 insertions(+), 267 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 76f21b592..87ced63ef 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -3018,6 +3019,14 @@ static void send_shutdown_complete(struct peer *peer) close(MASTER_FD); } +static void try_read_gossip_store(struct peer *peer) +{ + u8 *msg = gossip_store_next(tmpctx, peer->pps); + + if (msg) + sync_crypto_write(peer->pps, take(msg)); +} + int main(int argc, char *argv[]) { setup_locale(); @@ -3069,6 +3078,7 @@ int main(int argc, char *argv[]) struct timeval timeout, *tptr; struct timer *expired; const u8 *msg; + struct timerel trel; struct timemono now = time_mono(); /* Free any temporary allocations */ @@ -3095,6 +3105,9 @@ int main(int argc, char *argv[]) timeout = timespec_to_timeval( timemono_between(first, now).ts); tptr = &timeout; + } else if (time_to_next_gossip(peer->pps, &trel)) { + timeout = timerel_to_timeval(trel); + tptr = &timeout; } else tptr = NULL; @@ -3125,7 +3138,8 @@ int main(int argc, char *argv[]) if (!msg) peer_failed_connection_lost(); handle_gossip_msg(peer->pps, take(msg)); - } + } else /* Lowest priority: stream from store. */ + try_read_gossip_store(peer); } /* We only exit when shutdown is complete. */ diff --git a/common/gossip_store.c b/common/gossip_store.c index 2bc769e06..7bbe61595 100644 --- a/common/gossip_store.c +++ b/common/gossip_store.c @@ -1,43 +1,119 @@ +#include #include #include #include +#include #include #include #include #include #include +#include -u8 *gossip_store_read(const tal_t *ctx, int gossip_store_fd, u64 offset) +u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps) { - beint32_t hdr[2]; - u32 msglen, checksum; - u8 *msg; - - if (offset == 0) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "gossip_store: can't access offset %"PRIu64, - offset); - if (pread(gossip_store_fd, hdr, sizeof(hdr), offset) != sizeof(hdr)) { - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "gossip_store: can't read hdr offset %"PRIu64 - ": %s", - offset, strerror(errno)); - } + u8 *msg = NULL; + + /* Don't read until we're initialized. */ + if (!pps->gs) + return NULL; + + while (!msg) { + beint32_t hdr[2]; + u32 msglen, checksum; + int type; + + if (read(pps->gossip_store_fd, hdr, sizeof(hdr)) != sizeof(hdr)) { + per_peer_state_reset_gossip_timer(pps); + return NULL; + } - /* FIXME: We should skip over these deleted entries! */ - msglen = be32_to_cpu(hdr[0]) & ~GOSSIP_STORE_LEN_DELETED_BIT; - checksum = be32_to_cpu(hdr[1]); - msg = tal_arr(ctx, u8, msglen); - if (pread(gossip_store_fd, msg, msglen, offset + sizeof(hdr)) != msglen) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "gossip_store: can't read len %u offset %"PRIu64, - msglen, offset); + /* Skip any deleted entries. */ + if (be32_to_cpu(hdr[0]) & GOSSIP_STORE_LEN_DELETED_BIT) { + /* Skip over it. */ + lseek(pps->gossip_store_fd, + be32_to_cpu(hdr[0]) & ~GOSSIP_STORE_LEN_DELETED_BIT, + SEEK_CUR); + continue; + } - if (checksum != crc32c(0, msg, msglen)) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "gossip_store: bad checksum offset %"PRIu64": %s", - offset, tal_hex(tmpctx, msg)); + msglen = be32_to_cpu(hdr[0]); + checksum = be32_to_cpu(hdr[1]); + msg = tal_arr(ctx, u8, msglen); + if (read(pps->gossip_store_fd, msg, msglen) != msglen) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "gossip_store: can't read len %u" + " ~offset %"PRIi64, + msglen, + (s64)lseek(pps->gossip_store_fd, + 0, SEEK_CUR)); + + if (checksum != crc32c(0, msg, msglen)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "gossip_store: bad checksum offset %" + PRIi64": %s", + (s64)lseek(pps->gossip_store_fd, + 0, SEEK_CUR) - msglen, + tal_hex(tmpctx, msg)); + + /* Ignore gossipd internal messages. */ + type = fromwire_peektype(msg); + if (type != WIRE_CHANNEL_ANNOUNCEMENT + && type != WIRE_CHANNEL_UPDATE + && type != WIRE_NODE_ANNOUNCEMENT) + msg = tal_free(msg); + } return msg; } +/* newfd is at offset 1. We need to adjust it to similar offset as our + * current one. */ +void gossip_store_switch_fd(struct per_peer_state *pps, + int newfd, u64 offset_shorter) +{ + u64 cur = lseek(pps->gossip_store_fd, SEEK_CUR, 0); + + /* If we're already at end (common), we know where to go in new one. */ + if (cur == lseek(pps->gossip_store_fd, SEEK_END, 0)) { + status_debug("gossip_store at end, new fd moved to %"PRIu64, + cur - offset_shorter); + assert(cur > offset_shorter); + lseek(newfd, cur - offset_shorter, SEEK_SET); + } else if (cur > offset_shorter) { + /* We're part way through. Worst case, we should move back by + * offset_shorter (that's how much the *end* moved), but in + * practice we'll probably end up retransmitting some stuff */ + u64 target = cur - offset_shorter; + size_t num = 0; + + status_debug("gossip_store new fd moving back %"PRIu64 + " to %"PRIu64, + cur, target); + cur = 1; + while (cur < target) { + u32 msglen; + beint32_t hdr[2]; + + if (read(newfd, hdr, sizeof(hdr)) != sizeof(hdr)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "gossip_store: " + "can't read hdr offset %"PRIu64 + " in new store target %"PRIu64, + cur, target); + /* Skip over it. */ + msglen = (be32_to_cpu(hdr[0]) + & ~GOSSIP_STORE_LEN_DELETED_BIT); + cur = lseek(newfd, msglen, SEEK_CUR); + num++; + } + status_debug("gossip_store: skipped %zu records to %"PRIu64, + num, cur); + } else + status_debug("gossip_store new fd moving back %"PRIu64 + " to start (offset_shorter=%"PRIu64")", + cur, offset_shorter); + + close(pps->gossip_store_fd); + pps->gossip_store_fd = newfd; +} diff --git a/common/gossip_store.h b/common/gossip_store.h index 4e0e4bcd3..2b7ff2e5d 100644 --- a/common/gossip_store.h +++ b/common/gossip_store.h @@ -4,6 +4,8 @@ #include #include +struct per_peer_state; + /** * gossip_store -- On-disk storage related information */ @@ -17,8 +19,15 @@ /** * Direct store accessor: loads gossip msg from store. * - * Doesn't return; status_failed() on error. + * Returns NULL and resets time_to_next_gossip(pps) if there are no + * more gossip msgs. + */ +u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps); + +/** + * Switches the gossip store fd, and gets to the correct offset. */ -u8 *gossip_store_read(const tal_t *ctx, int gossip_store_fd, u64 offset); +void gossip_store_switch_fd(struct per_peer_state *pps, + int newfd, u64 offset_shorter); #endif /* LIGHTNING_COMMON_GOSSIP_STORE_H */ diff --git a/common/per_peer_state.c b/common/per_peer_state.c index 31d355785..161529a4e 100644 --- a/common/per_peer_state.c +++ b/common/per_peer_state.c @@ -2,6 +2,7 @@ #include #include #include +#include static void destroy_per_peer_state(struct per_peer_state *pps) { @@ -19,6 +20,7 @@ struct per_peer_state *new_per_peer_state(const tal_t *ctx, struct per_peer_state *pps = tal(ctx, struct per_peer_state); pps->cs = *cs; + pps->gs = NULL; pps->peer_fd = pps->gossip_fd = pps->gossip_store_fd = -1; tal_add_destructor(pps, destroy_per_peer_state); return pps; @@ -42,9 +44,28 @@ void per_peer_state_set_fds_arr(struct per_peer_state *pps, const int *fds) per_peer_state_set_fds(pps, fds[0], fds[1], fds[2]); } +void towire_gossip_state(u8 **pptr, const struct gossip_state *gs) +{ + towire_u64(pptr, gs->next_gossip.ts.tv_sec); + towire_u64(pptr, gs->next_gossip.ts.tv_nsec); +} + +void fromwire_gossip_state(const u8 **cursor, size_t *max, + struct gossip_state *gs) +{ + gs->next_gossip.ts.tv_sec = fromwire_u64(cursor, max); + gs->next_gossip.ts.tv_nsec = fromwire_u64(cursor, max); +} + void towire_per_peer_state(u8 **pptr, const struct per_peer_state *pps) { towire_crypto_state(pptr, &pps->cs); +#if DEVELOPER + towire_u32(pptr, pps->dev_gossip_broadcast_msec); +#endif + towire_bool(pptr, pps->gs != NULL); + if (pps->gs) + towire_gossip_state(pptr, pps->gs); } void per_peer_state_fdpass_send(int fd, const struct per_peer_state *pps) @@ -61,7 +82,56 @@ struct per_peer_state *fromwire_per_peer_state(const tal_t *ctx, const u8 **cursor, size_t *max) { struct crypto_state cs; + struct per_peer_state *pps; fromwire_crypto_state(cursor, max, &cs); - return new_per_peer_state(ctx, &cs); + pps = new_per_peer_state(ctx, &cs); +#if DEVELOPER + pps->dev_gossip_broadcast_msec = fromwire_u32(cursor, max); +#endif + if (fromwire_bool(cursor, max)) { + pps->gs = tal(pps, struct gossip_state); + fromwire_gossip_state(cursor, max, pps->gs); + } + return pps; +} + +/* FIXME: Put in ccan/time */ +/* Is a after b? */ +static inline bool timemono_after(struct timemono a, struct timemono b) +{ + return time_greater_(a.ts, b.ts); +} + +bool time_to_next_gossip(const struct per_peer_state *pps, + struct timerel *t) +{ + if (!pps->gs) + return false; + + struct timemono now = time_mono(); + if (timemono_after(now, pps->gs->next_gossip)) + *t = time_from_sec(0); + else + *t = timemono_between(pps->gs->next_gossip, now); + return true; +} + +/* BOLT #7: + * + * A node: + *... + * - SHOULD flush outgoing gossip messages once every 60 seconds, + * independently of the arrival times of the messages. + * - Note: this results in staggered announcements that are unique + * (not duplicated). + */ +void per_peer_state_reset_gossip_timer(struct per_peer_state *pps) +{ + struct timerel t = time_from_sec(60); + +#if DEVELOPER + t = time_from_msec(pps->dev_gossip_broadcast_msec); +#endif + pps->gs->next_gossip = timemono_add(time_mono(), t); } diff --git a/common/per_peer_state.h b/common/per_peer_state.h index ed6fa9cf1..93eb04da9 100644 --- a/common/per_peer_state.h +++ b/common/per_peer_state.h @@ -3,19 +3,31 @@ #include "config.h" #include +#include #include +struct gossip_state { + /* Time for next gossip burst. */ + struct timemono next_gossip; +}; + /* Things we hand between daemons to talk to peers. */ struct per_peer_state { /* Cryptographic state needed to exchange messages with the peer (as * featured in BOLT #8) */ struct crypto_state cs; + /* NULL if it's not initialized yet */ + struct gossip_state *gs; +#if DEVELOPER + /* Normally 60000, but adjustable for dev mode */ + u32 dev_gossip_broadcast_msec; +#endif /* DEVELOPER */ /* If not -1, closed on freeing */ int peer_fd, gossip_fd, gossip_store_fd; }; /* Allocate a new per-peer state and add destructor to close fds if set; - * sets fds to -1. */ + * sets fds to -1 and ->gs to NULL.. */ struct per_peer_state *new_per_peer_state(const tal_t *ctx, const struct crypto_state *cs); @@ -33,4 +45,15 @@ void per_peer_state_fdpass_send(int fd, const struct per_peer_state *pps); struct per_peer_state *fromwire_per_peer_state(const tal_t *ctx, const u8 **cursor, size_t *max); + +void towire_gossip_state(u8 **pptr, const struct gossip_state *gs); +void fromwire_gossip_state(const u8 **cursor, size_t *max, + struct gossip_state *gs); + +/* How long until we have to check gossip store, if any? */ +bool time_to_next_gossip(const struct per_peer_state *pps, + struct timerel *t); + +/* Reset pps->next_gossip now we've drained gossip_store */ +void per_peer_state_reset_gossip_timer(struct per_peer_state *pps); #endif /* LIGHTNING_COMMON_PER_PEER_STATE_H */ diff --git a/common/read_peer_msg.c b/common/read_peer_msg.c index aed6a9297..891c7d57f 100644 --- a/common/read_peer_msg.c +++ b/common/read_peer_msg.c @@ -22,13 +22,32 @@ u8 *peer_or_gossip_sync_read(const tal_t *ctx, fd_set readfds; u8 *msg; - FD_ZERO(&readfds); - FD_SET(pps->peer_fd, &readfds); - FD_SET(pps->gossip_fd, &readfds); - - select(pps->peer_fd > pps->gossip_fd - ? pps->peer_fd + 1 : pps->gossip_fd + 1, - &readfds, NULL, NULL, NULL); + for (;;) { + struct timeval tv, *tptr; + struct timerel trel; + + if (time_to_next_gossip(pps, &trel)) { + tv = timerel_to_timeval(trel); + tptr = &tv; + } else + tptr = NULL; + + FD_ZERO(&readfds); + FD_SET(pps->peer_fd, &readfds); + FD_SET(pps->gossip_fd, &readfds); + + if (select(pps->peer_fd > pps->gossip_fd + ? pps->peer_fd + 1 : pps->gossip_fd + 1, + &readfds, NULL, NULL, tptr) != 0) + break; + + /* We timed out; look in gossip_store. Failure resets timer. */ + msg = gossip_store_next(tmpctx, pps); + if (msg) { + *from_gossipd = true; + return msg; + } + } if (FD_ISSET(pps->peer_fd, &readfds)) { msg = sync_crypto_read(ctx, pps); @@ -84,23 +103,16 @@ bool is_wrong_channel(const u8 *msg, const struct channel_id *expected, return !channel_id_eq(expected, actual); } -static void new_gossip_store(struct per_peer_state *pps, int new_gossip_store_fd) -{ - close(pps->gossip_store_fd); - pps->gossip_store_fd = new_gossip_store_fd; -} - void handle_gossip_msg(struct per_peer_state *pps, const u8 *msg TAKES) { u8 *gossip; - u64 offset; + u64 offset_shorter; - if (fromwire_gossipd_new_store_fd(msg)) { - new_gossip_store(pps, fdpass_recv(pps->gossip_fd)); + if (fromwire_gossipd_new_store_fd(msg, &offset_shorter)) { + gossip_store_switch_fd(pps, fdpass_recv(pps->gossip_fd), + offset_shorter); goto out; - } else if (fromwire_gossipd_send_gossip_from_store(msg, &offset)) - gossip = gossip_store_read(tmpctx, pps->gossip_store_fd, offset); - else + } else /* It's a raw gossip msg: this copies or takes() */ gossip = tal_dup_arr(tmpctx, u8, msg, tal_bytelen(msg), 0); @@ -113,7 +125,7 @@ void handle_gossip_msg(struct per_peer_state *pps, const u8 *msg TAKES) peer_failed_connection_lost(); } else { status_broken("Gossipd gave us bad send_gossip message %s", - tal_hex(msg, msg)); + tal_hex(tmpctx, gossip)); peer_failed_connection_lost(); } diff --git a/connectd/connect_gossip_wire.csv b/connectd/connect_gossip_wire.csv index 1fadba1fe..ead76038e 100644 --- a/connectd/connect_gossip_wire.csv +++ b/connectd/connect_gossip_wire.csv @@ -1,3 +1,4 @@ +#include #include # Communication between gossipd and connectd. @@ -11,6 +12,7 @@ gossip_new_peer,,initial_routing_sync,bool # if success: + gossip fd and gossip_store fd gossip_new_peer_reply,4100 gossip_new_peer_reply,,success,bool +gossip_new_peer_reply,,gs,?struct gossip_state # Connectd asks gossipd for any known addresses for that node. gossip_get_addrs,4001 diff --git a/connectd/connect_wire.csv b/connectd/connect_wire.csv index b3d395dd4..26b0053c9 100644 --- a/connectd/connect_wire.csv +++ b/connectd/connect_wire.csv @@ -50,7 +50,7 @@ connectctl_connect_failed,,addrhint,?struct wireaddr_internal connect_peer_connected,2002 connect_peer_connected,,id,struct node_id connect_peer_connected,,addr,struct wireaddr_internal -connect_peer_connected,,cs,struct crypto_state +connect_peer_connected,,pps,struct per_peer_state connect_peer_connected,,gflen,u16 connect_peer_connected,,globalfeatures,gflen*u8 connect_peer_connected,,lflen,u16 diff --git a/connectd/connectd.c b/connectd/connectd.c index 459c9ac63..ed44dd692 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -278,16 +278,16 @@ static void connected_to_peer(struct daemon *daemon, * few of the features of the peer and its id (for reporting). * * Every peer also has read-only access to the gossip_store, which is handed - * out by gossipd too. + * out by gossipd too, and also a "gossip_state" indicating where we're up to. * * The 'localfeatures' is a field in the `init` message, indicating properties * when you're connected to it like we are: there are also 'globalfeatures' - * which specify requirements to route a payment through a node. */ + * which specify requirements to route a payment through a node. + */ static bool get_gossipfds(struct daemon *daemon, const struct node_id *id, const u8 *localfeatures, - int *gossip_fd, - int *gossip_store_fd) + struct per_peer_state *pps) { bool gossip_queries_feature, initial_routing_sync, success; u8 *msg; @@ -313,7 +313,7 @@ static bool get_gossipfds(struct daemon *daemon, strerror(errno)); msg = wire_sync_read(tmpctx, GOSSIPCTL_FD); - if (!fromwire_gossip_new_peer_reply(msg, &success)) + if (!fromwire_gossip_new_peer_reply(pps, msg, &success, &pps->gs)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Failed parsing msg gossipctl: %s", tal_hex(tmpctx, msg)); @@ -328,8 +328,8 @@ static bool get_gossipfds(struct daemon *daemon, /* Otherwise, the next thing in the socket will be the file descriptors * for the per-peer daemon. */ - *gossip_fd = fdpass_recv(GOSSIPCTL_FD); - *gossip_store_fd = fdpass_recv(GOSSIPCTL_FD); + pps->gossip_fd = fdpass_recv(GOSSIPCTL_FD); + pps->gossip_store_fd = fdpass_recv(GOSSIPCTL_FD); return true; } @@ -422,7 +422,7 @@ struct io_plan *peer_connected(struct io_conn *conn, const u8 *localfeatures TAKES) { u8 *msg; - int gossip_fd, gossip_store_fd; + struct per_peer_state *pps; if (node_set_get(&daemon->peers, id)) return peer_reconnected(conn, daemon, id, addr, cs, @@ -437,12 +437,19 @@ struct io_plan *peer_connected(struct io_conn *conn, if (taken(localfeatures)) tal_steal(tmpctx, localfeatures); + /* This contains the per-peer state info; gossipd fills in pps->gs */ + pps = new_per_peer_state(tmpctx, cs); +#if DEVELOPER + /* Overridden by lightningd, but initialize to keep valgrind happy */ + pps->dev_gossip_broadcast_msec = 0; +#endif + /* If gossipd can't give us a file descriptor, we give up connecting. */ - if (!get_gossipfds(daemon, id, localfeatures, &gossip_fd, &gossip_store_fd)) + if (!get_gossipfds(daemon, id, localfeatures, pps)) return io_close(conn); /* Create message to tell master peer has connected. */ - msg = towire_connect_peer_connected(NULL, id, addr, cs, + msg = towire_connect_peer_connected(NULL, id, addr, pps, globalfeatures, localfeatures); /*~ daemon_conn is a message queue for inter-daemon communication: we @@ -451,8 +458,11 @@ struct io_plan *peer_connected(struct io_conn *conn, daemon_conn_send(daemon->master, take(msg)); /* io_conn_fd() extracts the fd from ccan/io's io_conn */ daemon_conn_send_fd(daemon->master, io_conn_fd(conn)); - daemon_conn_send_fd(daemon->master, gossip_fd); - daemon_conn_send_fd(daemon->master, gossip_store_fd); + daemon_conn_send_fd(daemon->master, pps->gossip_fd); + daemon_conn_send_fd(daemon->master, pps->gossip_store_fd); + + /* Don't try to close these on freeing. */ + pps->gossip_store_fd = pps->gossip_fd = -1; /*~ Finally, we add it to the set of pubkeys: tal_dup will handle * take() args for us, by simply tal_steal()ing it. */ diff --git a/gossipd/Makefile b/gossipd/Makefile index a58978db4..8e63c090e 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -50,11 +50,11 @@ GOSSIPD_COMMON_OBJS := \ common/dev_disconnect.o \ common/features.o \ common/gen_status_wire.o \ - common/gossip_store.o \ common/key_derive.o \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ + common/per_peer_state.o \ common/ping.o \ common/pseudorand.o \ common/status.o \ diff --git a/gossipd/gossip_peerd_wire.csv b/gossipd/gossip_peerd_wire.csv index ca1cac4eb..30529e4df 100644 --- a/gossipd/gossip_peerd_wire.csv +++ b/gossipd/gossip_peerd_wire.csv @@ -9,10 +9,6 @@ gossipd_get_update_reply,3601 gossipd_get_update_reply,,len,u16 gossipd_get_update_reply,,update,len*u8 -# But usually gossipd just gives an offset into the gossip_store -gossipd_send_gossip_from_store,3506 -gossipd_send_gossip_from_store,,offset,u64 - # Both sides have seen the funding tx being locked, but we have not # yet reached the announcement depth. So we add the channel locally so # we (and peer) can update it already. @@ -33,3 +29,5 @@ gossipd_local_channel_update,,htlc_maximum_msat,struct amount_msat # Update your gossip_store fd: + gossip_store_fd gossipd_new_store_fd,3505 +# How much shorter the new store is, so you can offset streaming. +gossipd_new_store_fd,,offset_shorter,u64 diff --git a/gossipd/gossip_store.c b/gossipd/gossip_store.c index 6723ffe7f..07047c08f 100644 --- a/gossipd/gossip_store.c +++ b/gossipd/gossip_store.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -423,7 +424,7 @@ void gossip_store_delete(struct gossip_store *gs, assert(gs->writable); #if DEVELOPER - u8 *msg = gossip_store_read(tmpctx, gs->fd, bcast->index); + const u8 *msg = gossip_store_get(tmpctx, gs, bcast->index); assert(fromwire_peektype(msg) == type); #endif if (pread(gs->fd, &belen, sizeof(belen), bcast->index) != sizeof(belen)) @@ -455,7 +456,36 @@ const u8 *gossip_store_get(const tal_t *ctx, struct gossip_store *gs, u64 offset) { - return gossip_store_read(ctx, gs->fd, offset); + beint32_t hdr[2]; + u32 msglen, checksum; + u8 *msg; + + if (offset == 0) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "gossip_store: can't access offset %"PRIu64, + offset); + if (pread(gs->fd, hdr, sizeof(hdr), offset) != sizeof(hdr)) { + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "gossip_store: can't read hdr offset %"PRIu64 + "/%"PRIu64": %s", + offset, gs->len, strerror(errno)); + } + + /* FIXME: We should skip over these deleted entries! */ + msglen = be32_to_cpu(hdr[0]) & ~GOSSIP_STORE_LEN_DELETED_BIT; + checksum = be32_to_cpu(hdr[1]); + msg = tal_arr(ctx, u8, msglen); + if (pread(gs->fd, msg, msglen, offset + sizeof(hdr)) != msglen) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "gossip_store: can't read len %u offset %"PRIu64 + "/%"PRIu64, msglen, offset, gs->len); + + if (checksum != crc32c(0, msg, msglen)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "gossip_store: bad checksum offset %"PRIu64": %s", + offset, tal_hex(tmpctx, msg)); + + return msg; } const u8 *gossip_store_get_private_update(const tal_t *ctx, @@ -474,7 +504,14 @@ const u8 *gossip_store_get_private_update(const tal_t *ctx, int gossip_store_readonly_fd(struct gossip_store *gs) { - return open(GOSSIP_STORE_FILENAME, O_RDONLY); + int fd = open(GOSSIP_STORE_FILENAME, O_RDONLY); + + /* Skip over version header */ + if (fd != -1 && lseek(fd, 1, SEEK_SET) != 1) { + close_noerr(fd); + fd = -1; + } + return fd; } void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs) diff --git a/gossipd/gossip_wire.csv b/gossipd/gossip_wire.csv index 169dfdde3..575d3ae77 100644 --- a/gossipd/gossip_wire.csv +++ b/gossipd/gossip_wire.csv @@ -4,7 +4,6 @@ # Initialize the gossip daemon. gossipctl_init,3000 -gossipctl_init,,broadcast_interval_msec,u32 gossipctl_init,,chain_hash,struct bitcoin_blkid gossipctl_init,,id,struct node_id gossipctl_init,,gflen,u16 diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 5160edec7..05e204ed7 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -104,9 +104,6 @@ struct daemon { /* Timers: we batch gossip, and also refresh announcements */ struct timers timers; - /* How often we flush gossip (60 seconds unless DEVELOPER override) */ - u32 broadcast_interval_msec; - /* Global features to list in node_announcement. */ u8 *globalfeatures; @@ -132,12 +129,6 @@ struct peer { /* The two features gossip cares about (so far) */ bool gossip_queries_feature, initial_routing_sync_feature; - /* High water mark for the staggered broadcast */ - u32 broadcast_index; - - /* Timestamp range the peer asked us to filter gossip by */ - u32 gossip_timestamp_min, gossip_timestamp_max; - /* Are there outstanding queries on short_channel_ids? */ const struct short_channel_id *scid_queries; size_t scid_query_idx; @@ -146,9 +137,6 @@ struct peer { struct node_id *scid_query_nodes; size_t scid_query_nodes_idx; - /* If this is NULL, we're syncing gossip now. */ - struct oneshot *gossip_timer; - /* How many query responses are we expecting? */ size_t num_scid_queries_outstanding; @@ -228,27 +216,12 @@ static void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) daemon_conn_send(peer->dc, msg); } -/*~ We have a shortcut for messages from the store: we send the offset, and - * the other daemon reads and sends, saving us much work. */ +/*~ We have a helper for messages from the store. */ static void queue_peer_from_store(struct peer *peer, const struct broadcastable *bcast) { - const u8 *msg = towire_gossipd_send_gossip_from_store(NULL, - bcast->index); - - daemon_conn_send(peer->dc, take(msg)); -} - -/* This pokes daemon_conn, which calls dump_gossip: the NULL gossip_timer - * tells it that the gossip timer has expired and it should send any queued - * gossip messages. */ -static void wake_gossip_out(struct peer *peer) -{ - /* If we were waiting, we're not any more */ - peer->gossip_timer = tal_free(peer->gossip_timer); - - /* Notify the daemon_conn-write loop */ - daemon_conn_wake(peer->dc); + struct gossip_store *gs = peer->daemon->rstate->broadcasts->gs; + queue_peer_msg(peer, take(gossip_store_get(NULL, gs, bcast->index))); } /* BOLT #7: @@ -652,39 +625,7 @@ static const u8 *handle_query_short_channel_ids(struct peer *peer, const u8 *msg */ static u8 *handle_gossip_timestamp_filter(struct peer *peer, const u8 *msg) { - struct bitcoin_blkid chain_hash; - u32 first_timestamp, timestamp_range; - - if (!fromwire_gossip_timestamp_filter(msg, &chain_hash, - &first_timestamp, - ×tamp_range)) { - return towire_errorfmt(peer, NULL, - "Bad gossip_timestamp_filter %s", - tal_hex(tmpctx, msg)); - } - - if (!bitcoin_blkid_eq(&peer->daemon->chain_hash, &chain_hash)) { - status_trace("%s sent gossip_timestamp_filter chainhash %s", - type_to_string(tmpctx, struct node_id, &peer->id), - type_to_string(tmpctx, struct bitcoin_blkid, - &chain_hash)); - return NULL; - } - - /* We initialize the timestamps to "impossible" values so we can - * detect that this is the first filter: in this case, we gossip sync - * immediately. */ - if (peer->gossip_timestamp_min > peer->gossip_timestamp_max) - wake_gossip_out(peer); - - /* FIXME: We don't index by timestamp, so this forces a brute - * search! But keeping in correct order is v. hard. */ - peer->gossip_timestamp_min = first_timestamp; - peer->gossip_timestamp_max = first_timestamp + timestamp_range - 1; - /* In case they overflow. */ - if (peer->gossip_timestamp_max < peer->gossip_timestamp_min) - peer->gossip_timestamp_max = UINT32_MAX; - peer->broadcast_index = 0; + /* FIXME: Move handling this msg to peer! */ return NULL; } @@ -697,21 +638,17 @@ void update_peers_broadcast_index(struct list_head *peers, u32 offset) list_for_each_safe(peers, peer, next, list) { int gs_fd; - if (peer->broadcast_index < offset) - peer->broadcast_index = 0; - else - peer->broadcast_index -= offset; - /*~ Since store has been compacted, they need a new fd for the - * new store. The only one will still work, but after this - * any offsets will refer to the new store. */ + * new store. We also tell them how much this is shrunk, so + * they can (approximately) tell where to start in the new store. + */ gs_fd = gossip_store_readonly_fd(peer->daemon->rstate->broadcasts->gs); if (gs_fd < 0) { status_broken("Can't get read-only gossip store fd:" " killing peer"); tal_free(peer); } else { - u8 *msg = towire_gossipd_new_store_fd(NULL); + u8 *msg = towire_gossipd_new_store_fd(NULL, offset); daemon_conn_send(peer->dc, take(msg)); daemon_conn_send_fd(peer->dc, gs_fd); } @@ -1204,64 +1141,12 @@ static void maybe_create_next_scid_reply(struct peer *peer) } } -/*~ If we're supposed to be sending gossip, do so now. */ -static void maybe_queue_gossip(struct peer *peer) -{ - struct broadcastable *next; - - /* If the gossip timer is still running, don't send. */ - if (peer->gossip_timer) - return; - -#if DEVELOPER - /* The dev_suppress_gossip RPC is used for testing. */ - if (suppress_gossip) - return; -#endif - - /*~ We maintain an ordered map of gossip to broadcast, so each peer - * only needs to keep an index; this returns the next gossip message - * which is past the previous index and within the timestamp: it - * also updates `broadcast_index`. */ - next = next_broadcast(peer->daemon->rstate->broadcasts, - peer->gossip_timestamp_min, - peer->gossip_timestamp_max, - &peer->broadcast_index); - - if (next) { - queue_peer_from_store(peer, next); - return; - } - - /* BOLT #7: - * - * A node: - *... - * - SHOULD flush outgoing gossip messages once every 60 seconds, - * independently of the arrival times of the messages. - * - Note: this results in staggered announcements that are unique - * (not duplicated). - */ - - /* Gossip is drained; we set up timer now, which is strictly-speaking - * more than 60 seconds if sending gossip took a long time. But - * that's their fault for being slow! */ - peer->gossip_timer - = new_reltimer(&peer->daemon->timers, peer, - /* The time is adjustable for testing */ - time_from_msec(peer->daemon->broadcast_interval_msec), - wake_gossip_out, peer); -} - /*~ This is called when the outgoing queue is empty; gossip has lower priority * than just about anything else. */ static void dump_gossip(struct peer *peer) { /* Do we have scid query replies to send? */ maybe_create_next_scid_reply(peer); - - /* Queue any gossip we want to send */ - maybe_queue_gossip(peer); } /*~ This generates a `channel_update` message for one of our channels. We do @@ -1675,7 +1560,6 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, /* These are the ones we send, not them */ case WIRE_GOSSIPD_GET_UPDATE_REPLY: case WIRE_GOSSIPD_NEW_STORE_FD: - case WIRE_GOSSIPD_SEND_GOSSIP_FROM_STORE: break; } @@ -1710,6 +1594,7 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, struct peer *peer = tal(conn, struct peer); int fds[2]; int gossip_store_fd; + struct gossip_state *gs; if (!fromwire_gossip_new_peer(msg, &peer->id, &peer->gossip_queries_feature, @@ -1724,7 +1609,9 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, status_broken("Failed to get readonly store fd: %s", strerror(errno)); daemon_conn_send(daemon->connectd, - take(towire_gossip_new_peer_reply(NULL, false))); + take(towire_gossip_new_peer_reply(NULL, + false, + NULL))); goto done; } @@ -1734,7 +1621,9 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, strerror(errno)); close(gossip_store_fd); daemon_conn_send(daemon->connectd, - take(towire_gossip_new_peer_reply(NULL, false))); + take(towire_gossip_new_peer_reply(NULL, + false, + NULL))); goto done; } @@ -1750,43 +1639,11 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, peer->num_scid_queries_outstanding = 0; peer->query_channel_blocks = NULL; peer->num_pings_outstanding = 0; - peer->gossip_timer = NULL; /* We keep a list so we can find peer by id */ list_add_tail(&peer->daemon->peers, &peer->list); tal_add_destructor(peer, destroy_peer); - /* BOLT #7: - * - * - if the `gossip_queries` feature is negotiated: - * - MUST NOT relay any gossip messages unless explicitly requested. - */ - if (peer->gossip_queries_feature) { - peer->broadcast_index = UINT32_MAX; - /* Nothing in this "impossible" range */ - peer->gossip_timestamp_min = UINT32_MAX; - peer->gossip_timestamp_max = 0; - } else { - /* BOLT #7: - * - * - upon receiving an `init` message with the - * `initial_routing_sync` flag set to 1: - * - SHOULD send gossip messages for all known channels and - * nodes, as if they were just received. - * - if the `initial_routing_sync` flag is set to 0, OR if the - * initial sync was completed: - * - SHOULD resume normal operation, as specified in the - * following [Rebroadcasting](#rebroadcasting) section. - */ - peer->gossip_timestamp_min = 0; - peer->gossip_timestamp_max = UINT32_MAX; - if (peer->initial_routing_sync_feature) - peer->broadcast_index = 0; - else - peer->broadcast_index - = broadcast_final_index(peer->daemon->rstate->broadcasts) + 1; - } - /* This is the new connection: calls dump_gossip when nothing else to * send. */ peer->dc = daemon_conn_new(daemon, fds[0], @@ -1797,12 +1654,13 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, /* This sends the initial timestamp filter. */ setup_gossip_range(peer); - /* Start the gossip flowing. */ - wake_gossip_out(peer); + /* Start gossiping immediately */ + gs = tal(tmpctx, struct gossip_state); + gs->next_gossip = time_mono(); - /* Reply with success, and the new fd */ + /* Reply with success, and the new fd and gossip_state. */ daemon_conn_send(daemon->connectd, - take(towire_gossip_new_peer_reply(NULL, true))); + take(towire_gossip_new_peer_reply(NULL, true, gs))); daemon_conn_send_fd(daemon->connectd, fds[1]); daemon_conn_send_fd(daemon->connectd, gossip_store_fd); @@ -1967,9 +1825,6 @@ static struct io_plan *gossip_init(struct io_conn *conn, u32 *dev_gossip_time; if (!fromwire_gossipctl_init(daemon, msg, - /* 60,000 ms - * (unless --dev-broadcast-interval) */ - &daemon->broadcast_interval_msec, &daemon->chain_hash, &daemon->id, &daemon->globalfeatures, daemon->rgb, diff --git a/gossipd/test/run-bench-find_route.c b/gossipd/test/run-bench-find_route.c index ae2b3841c..c9c5a1400 100644 --- a/gossipd/test/run-bench-find_route.c +++ b/gossipd/test/run-bench-find_route.c @@ -57,9 +57,6 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_wireaddr */ bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) { fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } -/* Generated stub for gossip_store_read */ -u8 *gossip_store_read(const tal_t *ctx UNNEEDED, int gossip_store_fd UNNEEDED, u64 offset UNNEEDED) -{ fprintf(stderr, "gossip_store_read called!\n"); abort(); } /* Generated stub for onion_type_name */ const char *onion_type_name(int e UNNEEDED) { fprintf(stderr, "onion_type_name called!\n"); abort(); } diff --git a/gossipd/test/run-find_route-specific.c b/gossipd/test/run-find_route-specific.c index e5cd9c2a1..c06c5bcc9 100644 --- a/gossipd/test/run-find_route-specific.c +++ b/gossipd/test/run-find_route-specific.c @@ -46,9 +46,6 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_wireaddr */ bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) { fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } -/* Generated stub for gossip_store_read */ -u8 *gossip_store_read(const tal_t *ctx UNNEEDED, int gossip_store_fd UNNEEDED, u64 offset UNNEEDED) -{ fprintf(stderr, "gossip_store_read called!\n"); abort(); } /* Generated stub for onion_type_name */ const char *onion_type_name(int e UNNEEDED) { fprintf(stderr, "onion_type_name called!\n"); abort(); } diff --git a/gossipd/test/run-find_route.c b/gossipd/test/run-find_route.c index 20583a213..de4733151 100644 --- a/gossipd/test/run-find_route.c +++ b/gossipd/test/run-find_route.c @@ -44,9 +44,6 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_wireaddr */ bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) { fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } -/* Generated stub for gossip_store_read */ -u8 *gossip_store_read(const tal_t *ctx UNNEEDED, int gossip_store_fd UNNEEDED, u64 offset UNNEEDED) -{ fprintf(stderr, "gossip_store_read called!\n"); abort(); } /* Generated stub for onion_type_name */ const char *onion_type_name(int e UNNEEDED) { fprintf(stderr, "onion_type_name called!\n"); abort(); } diff --git a/gossipd/test/run-overlong.c b/gossipd/test/run-overlong.c index 0245dab34..faa980ae2 100644 --- a/gossipd/test/run-overlong.c +++ b/gossipd/test/run-overlong.c @@ -44,9 +44,6 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* Generated stub for fromwire_wireaddr */ bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) { fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } -/* Generated stub for gossip_store_read */ -u8 *gossip_store_read(const tal_t *ctx UNNEEDED, int gossip_store_fd UNNEEDED, u64 offset UNNEEDED) -{ fprintf(stderr, "gossip_store_read called!\n"); abort(); } /* Generated stub for onion_type_name */ const char *onion_type_name(int e UNNEEDED) { fprintf(stderr, "onion_type_name called!\n"); abort(); } diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 060aee855..06ac60910 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -161,7 +161,7 @@ void gossip_init(struct lightningd *ld, int connectd_fd) err(1, "Could not subdaemon gossip"); msg = towire_gossipctl_init( - tmpctx, ld->config.broadcast_interval_msec, + tmpctx, &get_chainparams(ld)->genesis_blockhash, &ld->id, get_offered_globalfeatures(tmpctx), ld->rgb, diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 00b3a0232..39f604277 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -801,18 +801,22 @@ void peer_connected(struct lightningd *ld, const u8 *msg, u8 *globalfeatures, *localfeatures; struct peer *peer; struct peer_connected_hook_payload *hook_payload; - struct crypto_state cs; hook_payload = tal(NULL, struct peer_connected_hook_payload); hook_payload->ld = ld; - if (!fromwire_connect_peer_connected(msg, msg, + if (!fromwire_connect_peer_connected(hook_payload, msg, &id, &hook_payload->addr, - &cs, + &hook_payload->pps, &globalfeatures, &localfeatures)) fatal("Connectd gave bad CONNECT_PEER_CONNECTED message %s", tal_hex(msg, msg)); - hook_payload->pps = new_per_peer_state(hook_payload, &cs); +#if DEVELOPER + /* Override broaedcast interval from our config */ + hook_payload->pps->dev_gossip_broadcast_msec + = ld->config.broadcast_interval_msec; +#endif + per_peer_state_set_fds(hook_payload->pps, peer_fd, gossip_fd, gossip_store_fd); diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index fac183984..a49a422b0 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -83,7 +83,7 @@ void fatal(const char *fmt UNNEEDED, ...) bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) { fprintf(stderr, "fromwire_channel_dev_memleak_reply 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 node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *cs UNNEEDED, u8 **globalfeatures UNNEEDED, u8 **localfeatures UNNEEDED) +bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct per_peer_state **pps 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) @@ -260,10 +260,6 @@ struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, struct log_book *new_log_book(size_t max_mem UNNEEDED, enum log_level printlevel UNNEEDED) { fprintf(stderr, "new_log_book called!\n"); abort(); } -/* Generated stub for new_per_peer_state */ -struct per_peer_state *new_per_peer_state(const tal_t *ctx UNNEEDED, - const struct crypto_state *cs UNNEEDED) -{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for new_reltimer_ */ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, const tal_t *ctx UNNEEDED, diff --git a/openingd/openingd.c b/openingd/openingd.c index 05b1a9898..615a1f992 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1438,6 +1439,14 @@ static u8 *handle_master_in(struct state *state) "Unknown msg %s", tal_hex(tmpctx, msg)); } +static void try_read_gossip_store(struct state *state) +{ + u8 *msg = gossip_store_next(tmpctx, state->pps); + + if (msg) + sync_crypto_write(state->pps, take(msg)); +} + int main(int argc, char *argv[]) { setup_locale(); @@ -1524,7 +1533,13 @@ int main(int argc, char *argv[]) * opening_funder_reply or opening_fundee. */ msg = NULL; while (!msg) { - poll(pollfd, ARRAY_SIZE(pollfd), -1); + int t; + struct timerel trel; + if (time_to_next_gossip(state->pps, &trel)) + t = time_to_msec(trel); + else + t = -1; + poll(pollfd, ARRAY_SIZE(pollfd), t); /* Subtle: handle_master_in can do its own poll loop, so * don't try to service more than one fd per loop. */ /* First priority: messages from lightningd. */ @@ -1536,6 +1551,8 @@ int main(int argc, char *argv[]) /* Last priority: chit-chat from gossipd. */ else if (pollfd[1].revents & POLLIN) handle_gossip_in(state); + else + try_read_gossip_store(state); /* Since we're the top-level event loop, we clean up */ clean_tmpctx(); diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 2a6f62466..03b780788 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -136,6 +136,8 @@ def test_announce_address(node_factory, bitcoind): l1.daemon.wait_for_log(r"\[OUT\] 0101.*004d010102030404d202000000000000000000000000000000002607039216a8b803f3acd758aa260704e00533f3e8f2aedaa8969b3d0fa03a96e857bbb28064dca5e147e934244b9ba50230032607'") +# FIXME: Implement timestamp filtering +@pytest.mark.xfail(strict=True) @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_gossip_timestamp_filter(node_factory, bitcoind): # Need full IO logging so we can see gossip (from gossipd and channeld) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 658281864..f6612b8eb 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -95,7 +95,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, struct bitcoin_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 node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct crypto_state *cs UNNEEDED, u8 **globalfeatures UNNEEDED, u8 **localfeatures UNNEEDED) +bool fromwire_connect_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct per_peer_state **pps UNNEEDED, u8 **globalfeatures UNNEEDED, u8 **localfeatures UNNEEDED) { fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); } /* Generated stub for fromwire_gossip_get_channel_peer_reply */ bool fromwire_gossip_get_channel_peer_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id **peer_id UNNEEDED) @@ -351,10 +351,6 @@ void log_add(struct log *log UNNEEDED, const char *fmt UNNEEDED, ...) void log_io(struct log *log UNNEEDED, enum log_level dir UNNEEDED, const char *comment UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) { fprintf(stderr, "log_io called!\n"); abort(); } -/* Generated stub for new_per_peer_state */ -struct per_peer_state *new_per_peer_state(const tal_t *ctx UNNEEDED, - const struct crypto_state *cs UNNEEDED) -{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for notify_connect */ void notify_connect(struct lightningd *ld UNNEEDED, struct node_id *nodeid UNNEEDED, struct wireaddr_internal *addr UNNEEDED)