From 5d6a9f3fb00f051ca6f836893726ea1957d17aba Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 8 Jun 2018 16:02:06 +0930 Subject: [PATCH] gossipd: check consistency. This is a hack to check that our gossip state is consistent on every insert and delete. Signed-off-by: Rusty Russell --- gossipd/broadcast.c | 96 +++++++++++++++++++++++++++++++++++++++++++++ gossipd/broadcast.h | 5 +++ 2 files changed, 101 insertions(+) diff --git a/gossipd/broadcast.c b/gossipd/broadcast.c index 721c281ce..4cbbb05e4 100644 --- a/gossipd/broadcast.c +++ b/gossipd/broadcast.c @@ -1,5 +1,14 @@ +#include +#include +#include +#include +#include #include +#include +#include +#include #include +#include struct queued_message { /* Broadcast index. */ @@ -25,6 +34,7 @@ void broadcast_del(struct broadcast_state *bstate, u64 index, const u8 *payload) { const struct queued_message *q = uintmap_del(&bstate->broadcasts, index); assert(q->payload == payload); + broadcast_state_check(bstate, "broadcast_del"); } static void destroy_queued_message(struct queued_message *msg, @@ -55,6 +65,7 @@ u64 insert_broadcast(struct broadcast_state *bstate, /* Free payload, free index. */ new_queued_message(payload, bstate, payload, timestamp, bstate->next_index); + broadcast_state_check(bstate, "insert_broadcast"); return bstate->next_index++; } @@ -71,3 +82,88 @@ const u8 *next_broadcast(struct broadcast_state *bstate, } return NULL; } + +static const struct pubkey * +pubkey_keyof(const struct pubkey *pk) +{ + return pk; +} + +static size_t pubkey_hash(const struct pubkey *id) +{ + return siphash24(siphash_seed(), id, sizeof(*id)); +} + +HTABLE_DEFINE_TYPE(struct pubkey, + pubkey_keyof, + pubkey_hash, + pubkey_eq, + pubkey_set); + +static void *corrupt(const char *abortstr, const char *problem, + const struct short_channel_id *scid, + const struct pubkey *node_id) +{ + status_broken("Gossip corrupt %s %s: %s", + problem, abortstr ? abortstr : "", + scid ? type_to_string(tmpctx, + struct short_channel_id, + scid) + : type_to_string(tmpctx, struct pubkey, node_id)); + if (abortstr) + abort(); + return NULL; +} + +struct broadcast_state *broadcast_state_check(struct broadcast_state *b, + const char *abortstr) +{ + secp256k1_ecdsa_signature sig; + const u8 *msg; + u8 *features, *addresses, color[3], alias[32]; + struct bitcoin_blkid chain_hash; + struct short_channel_id scid; + struct pubkey node_id_1, node_id_2, bitcoin_key; + u32 timestamp, fees; + u16 flags, expiry; + u64 index = 0, htlc_minimum_msat; + struct pubkey_set pubkeys; + /* We actually only need a set, not a map. */ + UINTMAP(u64 *) channels; + + pubkey_set_init(&pubkeys); + uintmap_init(&channels); + + while ((msg = next_broadcast(b, 0, UINT32_MAX, &index)) != NULL) { + if (fromwire_channel_announcement(tmpctx, msg, &sig, &sig, &sig, + &sig, &features, &chain_hash, + &scid, &node_id_1, &node_id_2, + &bitcoin_key, &bitcoin_key)) { + if (!uintmap_add(&channels, scid.u64, &index)) + return corrupt(abortstr, "announced twice", + &scid, NULL); + pubkey_set_add(&pubkeys, &node_id_1); + pubkey_set_add(&pubkeys, &node_id_2); + } else if (fromwire_channel_update(msg, &sig, &chain_hash, + &scid, ×tamp, &flags, + &expiry, &htlc_minimum_msat, + &fees, &fees)) { + if (!uintmap_get(&channels, scid.u64)) + return corrupt(abortstr, + "updated before announce", + &scid, NULL); + } else if (fromwire_node_announcement(tmpctx, msg, + &sig, &features, + ×tamp, + &node_id_1, color, alias, + &addresses)) + if (!uintmap_get(&channels, scid.u64)) + return corrupt(abortstr, + "node announced before channel", + NULL, &node_id_1); + } + + pubkey_set_clear(&pubkeys); + uintmap_clear(&channels); + return b; +} diff --git a/gossipd/broadcast.h b/gossipd/broadcast.h index b9dd0073c..8be37fb40 100644 --- a/gossipd/broadcast.h +++ b/gossipd/broadcast.h @@ -29,4 +29,9 @@ void broadcast_del(struct broadcast_state *bstate, u64 index, const u8 *payload) const u8 *next_broadcast(struct broadcast_state *bstate, u32 timestamp_min, u32 timestamp_max, u64 *last_index); + +/* Returns b if all OK, otherwise aborts if abortstr non-NULL, otherwise returns + * NULL. */ +struct broadcast_state *broadcast_state_check(struct broadcast_state *b, + const char *abortstr); #endif /* LIGHTNING_GOSSIPD_BROADCAST_H */