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 <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2019-06-04 03:45:25 +09:30
parent a40f45af55
commit 5591c0b5d8
24 changed files with 374 additions and 266 deletions

View File

@@ -29,6 +29,7 @@
#include <common/crypto_sync.h> #include <common/crypto_sync.h>
#include <common/dev_disconnect.h> #include <common/dev_disconnect.h>
#include <common/features.h> #include <common/features.h>
#include <common/gossip_store.h>
#include <common/htlc_tx.h> #include <common/htlc_tx.h>
#include <common/key_derive.h> #include <common/key_derive.h>
#include <common/memleak.h> #include <common/memleak.h>
@@ -3018,6 +3019,14 @@ static void send_shutdown_complete(struct peer *peer)
close(MASTER_FD); 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[]) int main(int argc, char *argv[])
{ {
setup_locale(); setup_locale();
@@ -3069,6 +3078,7 @@ int main(int argc, char *argv[])
struct timeval timeout, *tptr; struct timeval timeout, *tptr;
struct timer *expired; struct timer *expired;
const u8 *msg; const u8 *msg;
struct timerel trel;
struct timemono now = time_mono(); struct timemono now = time_mono();
/* Free any temporary allocations */ /* Free any temporary allocations */
@@ -3095,6 +3105,9 @@ int main(int argc, char *argv[])
timeout = timespec_to_timeval( timeout = timespec_to_timeval(
timemono_between(first, now).ts); timemono_between(first, now).ts);
tptr = &timeout; tptr = &timeout;
} else if (time_to_next_gossip(peer->pps, &trel)) {
timeout = timerel_to_timeval(trel);
tptr = &timeout;
} else } else
tptr = NULL; tptr = NULL;
@@ -3125,7 +3138,8 @@ int main(int argc, char *argv[])
if (!msg) if (!msg)
peer_failed_connection_lost(); peer_failed_connection_lost();
handle_gossip_msg(peer->pps, take(msg)); 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. */ /* We only exit when shutdown is complete. */

View File

@@ -1,43 +1,119 @@
#include <assert.h>
#include <ccan/crc/crc.h> #include <ccan/crc/crc.h>
#include <ccan/endian/endian.h> #include <ccan/endian/endian.h>
#include <common/gossip_store.h> #include <common/gossip_store.h>
#include <common/per_peer_state.h>
#include <common/status.h> #include <common/status.h>
#include <common/utils.h> #include <common/utils.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <unistd.h> #include <unistd.h>
#include <wire/gen_peer_wire.h>
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]; u8 *msg = NULL;
u32 msglen, checksum;
u8 *msg;
if (offset == 0) /* Don't read until we're initialized. */
status_failed(STATUS_FAIL_INTERNAL_ERROR, if (!pps->gs)
"gossip_store: can't access offset %"PRIu64, return NULL;
offset);
if (pread(gossip_store_fd, hdr, sizeof(hdr), offset) != sizeof(hdr)) { while (!msg) {
status_failed(STATUS_FAIL_INTERNAL_ERROR, beint32_t hdr[2];
"gossip_store: can't read hdr offset %"PRIu64 u32 msglen, checksum;
": %s", int type;
offset, strerror(errno));
if (read(pps->gossip_store_fd, hdr, sizeof(hdr)) != sizeof(hdr)) {
per_peer_state_reset_gossip_timer(pps);
return NULL;
}
/* 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;
}
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);
} }
/* 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);
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; 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;
}

View File

@@ -4,6 +4,8 @@
#include <ccan/short_types/short_types.h> #include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h> #include <ccan/tal/tal.h>
struct per_peer_state;
/** /**
* gossip_store -- On-disk storage related information * gossip_store -- On-disk storage related information
*/ */
@@ -17,8 +19,15 @@
/** /**
* Direct store accessor: loads gossip msg from store. * 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_read(const tal_t *ctx, int gossip_store_fd, u64 offset); u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps);
/**
* Switches the gossip store fd, and gets to the correct offset.
*/
void gossip_store_switch_fd(struct per_peer_state *pps,
int newfd, u64 offset_shorter);
#endif /* LIGHTNING_COMMON_GOSSIP_STORE_H */ #endif /* LIGHTNING_COMMON_GOSSIP_STORE_H */

View File

@@ -2,6 +2,7 @@
#include <ccan/fdpass/fdpass.h> #include <ccan/fdpass/fdpass.h>
#include <common/per_peer_state.h> #include <common/per_peer_state.h>
#include <unistd.h> #include <unistd.h>
#include <wire/wire.h>
static void destroy_per_peer_state(struct per_peer_state *pps) 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); struct per_peer_state *pps = tal(ctx, struct per_peer_state);
pps->cs = *cs; pps->cs = *cs;
pps->gs = NULL;
pps->peer_fd = pps->gossip_fd = pps->gossip_store_fd = -1; pps->peer_fd = pps->gossip_fd = pps->gossip_store_fd = -1;
tal_add_destructor(pps, destroy_per_peer_state); tal_add_destructor(pps, destroy_per_peer_state);
return pps; 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]); 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) void towire_per_peer_state(u8 **pptr, const struct per_peer_state *pps)
{ {
towire_crypto_state(pptr, &pps->cs); 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) 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) const u8 **cursor, size_t *max)
{ {
struct crypto_state cs; struct crypto_state cs;
struct per_peer_state *pps;
fromwire_crypto_state(cursor, max, &cs); 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);
} }

View File

@@ -3,19 +3,31 @@
#include "config.h" #include "config.h"
#include <ccan/tal/tal.h> #include <ccan/tal/tal.h>
#include <ccan/time/time.h>
#include <common/crypto_state.h> #include <common/crypto_state.h>
struct gossip_state {
/* Time for next gossip burst. */
struct timemono next_gossip;
};
/* Things we hand between daemons to talk to peers. */ /* Things we hand between daemons to talk to peers. */
struct per_peer_state { struct per_peer_state {
/* Cryptographic state needed to exchange messages with the peer (as /* Cryptographic state needed to exchange messages with the peer (as
* featured in BOLT #8) */ * featured in BOLT #8) */
struct crypto_state cs; 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 */ /* If not -1, closed on freeing */
int peer_fd, gossip_fd, gossip_store_fd; int peer_fd, gossip_fd, gossip_store_fd;
}; };
/* Allocate a new per-peer state and add destructor to close fds if set; /* 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, struct per_peer_state *new_per_peer_state(const tal_t *ctx,
const struct crypto_state *cs); 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, struct per_peer_state *fromwire_per_peer_state(const tal_t *ctx,
const u8 **cursor, size_t *max); 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 */ #endif /* LIGHTNING_COMMON_PER_PEER_STATE_H */

View File

@@ -22,13 +22,32 @@ u8 *peer_or_gossip_sync_read(const tal_t *ctx,
fd_set readfds; fd_set readfds;
u8 *msg; u8 *msg;
FD_ZERO(&readfds); for (;;) {
FD_SET(pps->peer_fd, &readfds); struct timeval tv, *tptr;
FD_SET(pps->gossip_fd, &readfds); struct timerel trel;
select(pps->peer_fd > pps->gossip_fd if (time_to_next_gossip(pps, &trel)) {
? pps->peer_fd + 1 : pps->gossip_fd + 1, tv = timerel_to_timeval(trel);
&readfds, NULL, NULL, NULL); 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)) { if (FD_ISSET(pps->peer_fd, &readfds)) {
msg = sync_crypto_read(ctx, pps); 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); 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) void handle_gossip_msg(struct per_peer_state *pps, const u8 *msg TAKES)
{ {
u8 *gossip; u8 *gossip;
u64 offset; u64 offset_shorter;
if (fromwire_gossipd_new_store_fd(msg)) { if (fromwire_gossipd_new_store_fd(msg, &offset_shorter)) {
new_gossip_store(pps, fdpass_recv(pps->gossip_fd)); gossip_store_switch_fd(pps, fdpass_recv(pps->gossip_fd),
offset_shorter);
goto out; goto out;
} else if (fromwire_gossipd_send_gossip_from_store(msg, &offset)) } else
gossip = gossip_store_read(tmpctx, pps->gossip_store_fd, offset);
else
/* It's a raw gossip msg: this copies or takes() */ /* It's a raw gossip msg: this copies or takes() */
gossip = tal_dup_arr(tmpctx, u8, msg, tal_bytelen(msg), 0); 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(); peer_failed_connection_lost();
} else { } else {
status_broken("Gossipd gave us bad send_gossip message %s", status_broken("Gossipd gave us bad send_gossip message %s",
tal_hex(msg, msg)); tal_hex(tmpctx, gossip));
peer_failed_connection_lost(); peer_failed_connection_lost();
} }

View File

@@ -1,3 +1,4 @@
#include <common/per_peer_state.h>
#include <common/wireaddr.h> #include <common/wireaddr.h>
# Communication between gossipd and connectd. # Communication between gossipd and connectd.
@@ -11,6 +12,7 @@ gossip_new_peer,,initial_routing_sync,bool
# if success: + gossip fd and gossip_store fd # if success: + gossip fd and gossip_store fd
gossip_new_peer_reply,4100 gossip_new_peer_reply,4100
gossip_new_peer_reply,,success,bool gossip_new_peer_reply,,success,bool
gossip_new_peer_reply,,gs,?struct gossip_state
# Connectd asks gossipd for any known addresses for that node. # Connectd asks gossipd for any known addresses for that node.
gossip_get_addrs,4001 gossip_get_addrs,4001
1 #include <common/wireaddr.h> #include <common/per_peer_state.h>
1 #include <common/per_peer_state.h>
2 #include <common/wireaddr.h> #include <common/wireaddr.h>
3 # Communication between gossipd and connectd. # Communication between gossipd and connectd.
4 gossip_new_peer,4000 gossip_new_peer,4000
12 gossip_new_peer_reply,,success,bool gossip_new_peer_reply,,success,bool
13 # Connectd asks gossipd for any known addresses for that node. gossip_new_peer_reply,,gs,?struct gossip_state
14 gossip_get_addrs,4001 # Connectd asks gossipd for any known addresses for that node.
15 gossip_get_addrs,4001
16 gossip_get_addrs,,id,struct node_id gossip_get_addrs,,id,struct node_id
17 gossip_get_addrs_reply,4101 gossip_get_addrs_reply,4101
18 gossip_get_addrs_reply,,num,u16 gossip_get_addrs_reply,,num,u16

View File

@@ -50,7 +50,7 @@ connectctl_connect_failed,,addrhint,?struct wireaddr_internal
connect_peer_connected,2002 connect_peer_connected,2002
connect_peer_connected,,id,struct node_id connect_peer_connected,,id,struct node_id
connect_peer_connected,,addr,struct wireaddr_internal 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,,gflen,u16
connect_peer_connected,,globalfeatures,gflen*u8 connect_peer_connected,,globalfeatures,gflen*u8
connect_peer_connected,,lflen,u16 connect_peer_connected,,lflen,u16
1 #include <common/cryptomsg.h>
50 # master -> connectd: peer has disconnected.
51 connectctl_peer_disconnected,2015
52 connectctl_peer_disconnected,,id,struct node_id
53 # master -> connectd: do you have a memleak?
54 connect_dev_memleak,2033
55 connect_dev_memleak_reply,2133
56 connect_dev_memleak_reply,,leak,bool

View File

@@ -278,16 +278,16 @@ static void connected_to_peer(struct daemon *daemon,
* few of the features of the peer and its id (for reporting). * 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 * 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 * The 'localfeatures' is a field in the `init` message, indicating properties
* when you're connected to it like we are: there are also 'globalfeatures' * 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, static bool get_gossipfds(struct daemon *daemon,
const struct node_id *id, const struct node_id *id,
const u8 *localfeatures, const u8 *localfeatures,
int *gossip_fd, struct per_peer_state *pps)
int *gossip_store_fd)
{ {
bool gossip_queries_feature, initial_routing_sync, success; bool gossip_queries_feature, initial_routing_sync, success;
u8 *msg; u8 *msg;
@@ -313,7 +313,7 @@ static bool get_gossipfds(struct daemon *daemon,
strerror(errno)); strerror(errno));
msg = wire_sync_read(tmpctx, GOSSIPCTL_FD); 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, status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Failed parsing msg gossipctl: %s", "Failed parsing msg gossipctl: %s",
tal_hex(tmpctx, msg)); 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 /* Otherwise, the next thing in the socket will be the file descriptors
* for the per-peer daemon. */ * for the per-peer daemon. */
*gossip_fd = fdpass_recv(GOSSIPCTL_FD); pps->gossip_fd = fdpass_recv(GOSSIPCTL_FD);
*gossip_store_fd = fdpass_recv(GOSSIPCTL_FD); pps->gossip_store_fd = fdpass_recv(GOSSIPCTL_FD);
return true; return true;
} }
@@ -422,7 +422,7 @@ struct io_plan *peer_connected(struct io_conn *conn,
const u8 *localfeatures TAKES) const u8 *localfeatures TAKES)
{ {
u8 *msg; u8 *msg;
int gossip_fd, gossip_store_fd; struct per_peer_state *pps;
if (node_set_get(&daemon->peers, id)) if (node_set_get(&daemon->peers, id))
return peer_reconnected(conn, daemon, id, addr, cs, return peer_reconnected(conn, daemon, id, addr, cs,
@@ -437,12 +437,19 @@ struct io_plan *peer_connected(struct io_conn *conn,
if (taken(localfeatures)) if (taken(localfeatures))
tal_steal(tmpctx, 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 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); return io_close(conn);
/* Create message to tell master peer has connected. */ /* 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); globalfeatures, localfeatures);
/*~ daemon_conn is a message queue for inter-daemon communication: we /*~ 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)); daemon_conn_send(daemon->master, take(msg));
/* io_conn_fd() extracts the fd from ccan/io's io_conn */ /* 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, io_conn_fd(conn));
daemon_conn_send_fd(daemon->master, gossip_fd); daemon_conn_send_fd(daemon->master, pps->gossip_fd);
daemon_conn_send_fd(daemon->master, gossip_store_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 /*~ Finally, we add it to the set of pubkeys: tal_dup will handle
* take() args for us, by simply tal_steal()ing it. */ * take() args for us, by simply tal_steal()ing it. */

View File

@@ -50,11 +50,11 @@ GOSSIPD_COMMON_OBJS := \
common/dev_disconnect.o \ common/dev_disconnect.o \
common/features.o \ common/features.o \
common/gen_status_wire.o \ common/gen_status_wire.o \
common/gossip_store.o \
common/key_derive.o \ common/key_derive.o \
common/memleak.o \ common/memleak.o \
common/msg_queue.o \ common/msg_queue.o \
common/node_id.o \ common/node_id.o \
common/per_peer_state.o \
common/ping.o \ common/ping.o \
common/pseudorand.o \ common/pseudorand.o \
common/status.o \ common/status.o \

View File

@@ -9,10 +9,6 @@ gossipd_get_update_reply,3601
gossipd_get_update_reply,,len,u16 gossipd_get_update_reply,,len,u16
gossipd_get_update_reply,,update,len*u8 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 # 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 # yet reached the announcement depth. So we add the channel locally so
# we (and peer) can update it already. # 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 # Update your gossip_store fd: + gossip_store_fd
gossipd_new_store_fd,3505 gossipd_new_store_fd,3505
# How much shorter the new store is, so you can offset streaming.
gossipd_new_store_fd,,offset_shorter,u64
1 # These must be distinct from WIRE_CHANNEL_ANNOUNCEMENT etc. gossip msgs!
9 gossipd_get_update_reply,,update,len*u8
10 # But usually gossipd just gives an offset into the gossip_store # Both sides have seen the funding tx being locked, but we have not
11 gossipd_send_gossip_from_store,3506 # yet reached the announcement depth. So we add the channel locally so
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.
12 gossipd_local_add_channel,3503 # we (and peer) can update it already.
13 gossipd_local_add_channel,,short_channel_id,struct short_channel_id gossipd_local_add_channel,3503
14 gossipd_local_add_channel,,remote_node_id,struct node_id gossipd_local_add_channel,,short_channel_id,struct short_channel_id
29 gossipd_new_store_fd,,offset_shorter,u64
30
31
32
33

View File

@@ -3,6 +3,7 @@
#include <ccan/array_size/array_size.h> #include <ccan/array_size/array_size.h>
#include <ccan/crc/crc.h> #include <ccan/crc/crc.h>
#include <ccan/endian/endian.h> #include <ccan/endian/endian.h>
#include <ccan/noerr/noerr.h>
#include <ccan/read_write_all/read_write_all.h> #include <ccan/read_write_all/read_write_all.h>
#include <common/gossip_store.h> #include <common/gossip_store.h>
#include <common/status.h> #include <common/status.h>
@@ -423,7 +424,7 @@ void gossip_store_delete(struct gossip_store *gs,
assert(gs->writable); assert(gs->writable);
#if DEVELOPER #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); assert(fromwire_peektype(msg) == type);
#endif #endif
if (pread(gs->fd, &belen, sizeof(belen), bcast->index) != sizeof(belen)) 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, struct gossip_store *gs,
u64 offset) 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, 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) 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) void gossip_store_load(struct routing_state *rstate, struct gossip_store *gs)

View File

@@ -4,7 +4,6 @@
# Initialize the gossip daemon. # Initialize the gossip daemon.
gossipctl_init,3000 gossipctl_init,3000
gossipctl_init,,broadcast_interval_msec,u32
gossipctl_init,,chain_hash,struct bitcoin_blkid gossipctl_init,,chain_hash,struct bitcoin_blkid
gossipctl_init,,id,struct node_id gossipctl_init,,id,struct node_id
gossipctl_init,,gflen,u16 gossipctl_init,,gflen,u16
1 #include <common/cryptomsg.h>
4 # Initialize the gossip daemon.
5 gossipctl_init,3000
6 gossipctl_init,,broadcast_interval_msec,u32 gossipctl_init,,chain_hash,struct bitcoin_blkid
gossipctl_init,,chain_hash,struct bitcoin_blkid
7 gossipctl_init,,id,struct node_id
8 gossipctl_init,,gflen,u16
9 gossipctl_init,,globalfeatures,gflen*u8

View File

@@ -104,9 +104,6 @@ struct daemon {
/* Timers: we batch gossip, and also refresh announcements */ /* Timers: we batch gossip, and also refresh announcements */
struct timers timers; struct timers timers;
/* How often we flush gossip (60 seconds unless DEVELOPER override) */
u32 broadcast_interval_msec;
/* Global features to list in node_announcement. */ /* Global features to list in node_announcement. */
u8 *globalfeatures; u8 *globalfeatures;
@@ -132,12 +129,6 @@ struct peer {
/* The two features gossip cares about (so far) */ /* The two features gossip cares about (so far) */
bool gossip_queries_feature, initial_routing_sync_feature; 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? */ /* Are there outstanding queries on short_channel_ids? */
const struct short_channel_id *scid_queries; const struct short_channel_id *scid_queries;
size_t scid_query_idx; size_t scid_query_idx;
@@ -146,9 +137,6 @@ struct peer {
struct node_id *scid_query_nodes; struct node_id *scid_query_nodes;
size_t scid_query_nodes_idx; 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? */ /* How many query responses are we expecting? */
size_t num_scid_queries_outstanding; 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); daemon_conn_send(peer->dc, msg);
} }
/*~ We have a shortcut for messages from the store: we send the offset, and /*~ We have a helper for messages from the store. */
* the other daemon reads and sends, saving us much work. */
static void queue_peer_from_store(struct peer *peer, static void queue_peer_from_store(struct peer *peer,
const struct broadcastable *bcast) const struct broadcastable *bcast)
{ {
const u8 *msg = towire_gossipd_send_gossip_from_store(NULL, struct gossip_store *gs = peer->daemon->rstate->broadcasts->gs;
bcast->index); queue_peer_msg(peer, take(gossip_store_get(NULL, gs, 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);
} }
/* BOLT #7: /* 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) static u8 *handle_gossip_timestamp_filter(struct peer *peer, const u8 *msg)
{ {
struct bitcoin_blkid chain_hash; /* FIXME: Move handling this msg to peer! */
u32 first_timestamp, timestamp_range;
if (!fromwire_gossip_timestamp_filter(msg, &chain_hash,
&first_timestamp,
&timestamp_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;
return NULL; 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) { list_for_each_safe(peers, peer, next, list) {
int gs_fd; 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 /*~ Since store has been compacted, they need a new fd for the
* new store. The only one will still work, but after this * new store. We also tell them how much this is shrunk, so
* any offsets will refer to the new store. */ * they can (approximately) tell where to start in the new store.
*/
gs_fd = gossip_store_readonly_fd(peer->daemon->rstate->broadcasts->gs); gs_fd = gossip_store_readonly_fd(peer->daemon->rstate->broadcasts->gs);
if (gs_fd < 0) { if (gs_fd < 0) {
status_broken("Can't get read-only gossip store fd:" status_broken("Can't get read-only gossip store fd:"
" killing peer"); " killing peer");
tal_free(peer); tal_free(peer);
} else { } 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(peer->dc, take(msg));
daemon_conn_send_fd(peer->dc, gs_fd); 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 /*~ This is called when the outgoing queue is empty; gossip has lower priority
* than just about anything else. */ * than just about anything else. */
static void dump_gossip(struct peer *peer) static void dump_gossip(struct peer *peer)
{ {
/* Do we have scid query replies to send? */ /* Do we have scid query replies to send? */
maybe_create_next_scid_reply(peer); 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 /*~ 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 */ /* These are the ones we send, not them */
case WIRE_GOSSIPD_GET_UPDATE_REPLY: case WIRE_GOSSIPD_GET_UPDATE_REPLY:
case WIRE_GOSSIPD_NEW_STORE_FD: case WIRE_GOSSIPD_NEW_STORE_FD:
case WIRE_GOSSIPD_SEND_GOSSIP_FROM_STORE:
break; break;
} }
@@ -1710,6 +1594,7 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn,
struct peer *peer = tal(conn, struct peer); struct peer *peer = tal(conn, struct peer);
int fds[2]; int fds[2];
int gossip_store_fd; int gossip_store_fd;
struct gossip_state *gs;
if (!fromwire_gossip_new_peer(msg, &peer->id, if (!fromwire_gossip_new_peer(msg, &peer->id,
&peer->gossip_queries_feature, &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", status_broken("Failed to get readonly store fd: %s",
strerror(errno)); strerror(errno));
daemon_conn_send(daemon->connectd, daemon_conn_send(daemon->connectd,
take(towire_gossip_new_peer_reply(NULL, false))); take(towire_gossip_new_peer_reply(NULL,
false,
NULL)));
goto done; goto done;
} }
@@ -1734,7 +1621,9 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn,
strerror(errno)); strerror(errno));
close(gossip_store_fd); close(gossip_store_fd);
daemon_conn_send(daemon->connectd, daemon_conn_send(daemon->connectd,
take(towire_gossip_new_peer_reply(NULL, false))); take(towire_gossip_new_peer_reply(NULL,
false,
NULL)));
goto done; goto done;
} }
@@ -1750,43 +1639,11 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn,
peer->num_scid_queries_outstanding = 0; peer->num_scid_queries_outstanding = 0;
peer->query_channel_blocks = NULL; peer->query_channel_blocks = NULL;
peer->num_pings_outstanding = 0; peer->num_pings_outstanding = 0;
peer->gossip_timer = NULL;
/* We keep a list so we can find peer by id */ /* We keep a list so we can find peer by id */
list_add_tail(&peer->daemon->peers, &peer->list); list_add_tail(&peer->daemon->peers, &peer->list);
tal_add_destructor(peer, destroy_peer); 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 /* This is the new connection: calls dump_gossip when nothing else to
* send. */ * send. */
peer->dc = daemon_conn_new(daemon, fds[0], 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. */ /* This sends the initial timestamp filter. */
setup_gossip_range(peer); setup_gossip_range(peer);
/* Start the gossip flowing. */ /* Start gossiping immediately */
wake_gossip_out(peer); 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, 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, fds[1]);
daemon_conn_send_fd(daemon->connectd, gossip_store_fd); 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; u32 *dev_gossip_time;
if (!fromwire_gossipctl_init(daemon, msg, if (!fromwire_gossipctl_init(daemon, msg,
/* 60,000 ms
* (unless --dev-broadcast-interval) */
&daemon->broadcast_interval_msec,
&daemon->chain_hash, &daemon->chain_hash,
&daemon->id, &daemon->globalfeatures, &daemon->id, &daemon->globalfeatures,
daemon->rgb, daemon->rgb,

View File

@@ -57,9 +57,6 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */ /* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } { 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 */ /* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED) const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); } { fprintf(stderr, "onion_type_name called!\n"); abort(); }

View File

@@ -46,9 +46,6 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */ /* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } { 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 */ /* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED) const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); } { fprintf(stderr, "onion_type_name called!\n"); abort(); }

View File

@@ -44,9 +44,6 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */ /* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } { 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 */ /* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED) const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); } { fprintf(stderr, "onion_type_name called!\n"); abort(); }

View File

@@ -44,9 +44,6 @@ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_wireaddr */ /* Generated stub for fromwire_wireaddr */
bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED) bool fromwire_wireaddr(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct wireaddr *addr UNNEEDED)
{ fprintf(stderr, "fromwire_wireaddr called!\n"); abort(); } { 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 */ /* Generated stub for onion_type_name */
const char *onion_type_name(int e UNNEEDED) const char *onion_type_name(int e UNNEEDED)
{ fprintf(stderr, "onion_type_name called!\n"); abort(); } { fprintf(stderr, "onion_type_name called!\n"); abort(); }

View File

@@ -161,7 +161,7 @@ void gossip_init(struct lightningd *ld, int connectd_fd)
err(1, "Could not subdaemon gossip"); err(1, "Could not subdaemon gossip");
msg = towire_gossipctl_init( msg = towire_gossipctl_init(
tmpctx, ld->config.broadcast_interval_msec, tmpctx,
&get_chainparams(ld)->genesis_blockhash, &ld->id, &get_chainparams(ld)->genesis_blockhash, &ld->id,
get_offered_globalfeatures(tmpctx), get_offered_globalfeatures(tmpctx),
ld->rgb, ld->rgb,

View File

@@ -801,18 +801,22 @@ void peer_connected(struct lightningd *ld, const u8 *msg,
u8 *globalfeatures, *localfeatures; u8 *globalfeatures, *localfeatures;
struct peer *peer; struct peer *peer;
struct peer_connected_hook_payload *hook_payload; struct peer_connected_hook_payload *hook_payload;
struct crypto_state cs;
hook_payload = tal(NULL, struct peer_connected_hook_payload); hook_payload = tal(NULL, struct peer_connected_hook_payload);
hook_payload->ld = ld; hook_payload->ld = ld;
if (!fromwire_connect_peer_connected(msg, msg, if (!fromwire_connect_peer_connected(hook_payload, msg,
&id, &hook_payload->addr, &id, &hook_payload->addr,
&cs, &hook_payload->pps,
&globalfeatures, &localfeatures)) &globalfeatures, &localfeatures))
fatal("Connectd gave bad CONNECT_PEER_CONNECTED message %s", fatal("Connectd gave bad CONNECT_PEER_CONNECTED message %s",
tal_hex(msg, msg)); 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, per_peer_state_set_fds(hook_payload->pps,
peer_fd, gossip_fd, gossip_store_fd); peer_fd, gossip_fd, gossip_store_fd);

View File

@@ -83,7 +83,7 @@ void fatal(const char *fmt UNNEEDED, ...)
bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) bool fromwire_channel_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED)
{ fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); } { fprintf(stderr, "fromwire_channel_dev_memleak_reply called!\n"); abort(); }
/* Generated stub for fromwire_connect_peer_connected */ /* 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(); } { fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); }
/* Generated stub for fromwire_gossip_get_incoming_channels_reply */ /* 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) 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, struct log_book *new_log_book(size_t max_mem UNNEEDED,
enum log_level printlevel UNNEEDED) enum log_level printlevel UNNEEDED)
{ fprintf(stderr, "new_log_book called!\n"); abort(); } { 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_ */ /* Generated stub for new_reltimer_ */
struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, struct oneshot *new_reltimer_(struct timers *timers UNNEEDED,
const tal_t *ctx UNNEEDED, const tal_t *ctx UNNEEDED,

View File

@@ -21,6 +21,7 @@
#include <common/features.h> #include <common/features.h>
#include <common/funding_tx.h> #include <common/funding_tx.h>
#include <common/gen_peer_status_wire.h> #include <common/gen_peer_status_wire.h>
#include <common/gossip_store.h>
#include <common/initial_channel.h> #include <common/initial_channel.h>
#include <common/key_derive.h> #include <common/key_derive.h>
#include <common/memleak.h> #include <common/memleak.h>
@@ -1438,6 +1439,14 @@ static u8 *handle_master_in(struct state *state)
"Unknown msg %s", tal_hex(tmpctx, msg)); "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[]) int main(int argc, char *argv[])
{ {
setup_locale(); setup_locale();
@@ -1524,7 +1533,13 @@ int main(int argc, char *argv[])
* opening_funder_reply or opening_fundee. */ * opening_funder_reply or opening_fundee. */
msg = NULL; msg = NULL;
while (!msg) { 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 /* Subtle: handle_master_in can do its own poll loop, so
* don't try to service more than one fd per loop. */ * don't try to service more than one fd per loop. */
/* First priority: messages from lightningd. */ /* First priority: messages from lightningd. */
@@ -1536,6 +1551,8 @@ int main(int argc, char *argv[])
/* Last priority: chit-chat from gossipd. */ /* Last priority: chit-chat from gossipd. */
else if (pollfd[1].revents & POLLIN) else if (pollfd[1].revents & POLLIN)
handle_gossip_in(state); handle_gossip_in(state);
else
try_read_gossip_store(state);
/* Since we're the top-level event loop, we clean up */ /* Since we're the top-level event loop, we clean up */
clean_tmpctx(); clean_tmpctx();

View File

@@ -136,6 +136,8 @@ def test_announce_address(node_factory, bitcoind):
l1.daemon.wait_for_log(r"\[OUT\] 0101.*004d010102030404d202000000000000000000000000000000002607039216a8b803f3acd758aa260704e00533f3e8f2aedaa8969b3d0fa03a96e857bbb28064dca5e147e934244b9ba50230032607'") 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") @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_gossip_timestamp_filter(node_factory, bitcoind): def test_gossip_timestamp_filter(node_factory, bitcoind):
# Need full IO logging so we can see gossip (from gossipd and channeld) # Need full IO logging so we can see gossip (from gossipd and channeld)

View File

@@ -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) 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(); } { fprintf(stderr, "fromwire_channel_sending_commitsig called!\n"); abort(); }
/* Generated stub for fromwire_connect_peer_connected */ /* 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(); } { fprintf(stderr, "fromwire_connect_peer_connected called!\n"); abort(); }
/* Generated stub for fromwire_gossip_get_channel_peer_reply */ /* 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) 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, void log_io(struct log *log UNNEEDED, enum log_level dir UNNEEDED, const char *comment UNNEEDED,
const void *data UNNEEDED, size_t len UNNEEDED) const void *data UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "log_io called!\n"); abort(); } { 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 */ /* Generated stub for notify_connect */
void notify_connect(struct lightningd *ld UNNEEDED, struct node_id *nodeid UNNEEDED, void notify_connect(struct lightningd *ld UNNEEDED, struct node_id *nodeid UNNEEDED,
struct wireaddr_internal *addr UNNEEDED) struct wireaddr_internal *addr UNNEEDED)