Browse Source

testing: make sure we don't see gossip in bad order.

This is something which generally shouldn't happen, but we didn't
notice it previously.

We ignore this warning in the case where a channel was deleted: this
happens because one side can send an update while the other notices
that the channel is closed.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
8ee60e2d8e
  1. 27
      gossipd/routing.c
  2. 6
      gossipd/test/run-bench-find_route.c
  3. 6
      gossipd/test/run-find_route-specific.c
  4. 6
      gossipd/test/run-find_route.c
  5. 10
      tests/fixtures.py
  6. 12
      tests/test_lightningd.py

27
gossipd/routing.c

@ -201,6 +201,13 @@ static void init_half_chan(struct routing_state *rstate,
c->last_timestamp = time_now().ts.tv_sec - rstate->prune_timeout/2; c->last_timestamp = time_now().ts.tv_sec - rstate->prune_timeout/2;
} }
static void bad_gossip_order(const u8 *msg, const char *details)
{
status_trace("Bad gossip order: %s before announcement %s",
wire_type_name(fromwire_peektype(msg)),
details);
}
struct chan *new_chan(struct routing_state *rstate, struct chan *new_chan(struct routing_state *rstate,
const struct short_channel_id *scid, const struct short_channel_id *scid,
const struct pubkey *id1, const struct pubkey *id1,
@ -1015,9 +1022,12 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update)
} }
if (!chan) { if (!chan) {
SUPERVERBOSE("Ignoring update for unknown channel %s", bad_gossip_order(serialized,
type_to_string(tmpctx, struct short_channel_id, tal_fmt(tmpctx, "%s(%u)",
&short_channel_id)); type_to_string(tmpctx,
struct short_channel_id,
&short_channel_id),
flags));
return NULL; return NULL;
} }
} }
@ -1245,11 +1255,9 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann)
pna = pending_node_map_get(rstate->pending_node_map, pna = pending_node_map_get(rstate->pending_node_map,
&node_id.pubkey); &node_id.pubkey);
if (!pna) { if (!pna) {
SUPERVERBOSE("Node not found, was the node_announcement " bad_gossip_order(serialized,
"for node %s preceded by at least " type_to_string(tmpctx, struct pubkey,
"channel_announcement?", &node_id));
type_to_string(tmpctx, struct pubkey,
&node_id));
} else if (pna->timestamp < timestamp) { } else if (pna->timestamp < timestamp) {
SUPERVERBOSE( SUPERVERBOSE(
"Deferring node_announcement for node %s", "Deferring node_announcement for node %s",
@ -1519,6 +1527,9 @@ void handle_local_add_channel(struct routing_state *rstate, const u8 *msg)
return; return;
} }
status_trace("local_add_channel %s",
type_to_string(tmpctx, struct short_channel_id, &scid));
/* Create new (unannounced) channel */ /* Create new (unannounced) channel */
new_chan(rstate, &scid, &rstate->local_id, &remote_node_id); new_chan(rstate, &scid, &rstate->local_id, &remote_node_id);
} }

6
gossipd/test/run-bench-find_route.c

@ -83,6 +83,9 @@ bool fromwire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const vo
/* Generated stub for fromwire_node_announcement */ /* Generated stub for fromwire_node_announcement */
bool fromwire_node_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, u8 **features UNNEEDED, u32 *timestamp UNNEEDED, struct pubkey *node_id UNNEEDED, u8 rgb_color[3] UNNEEDED, u8 alias[32] UNNEEDED, u8 **addresses UNNEEDED) bool fromwire_node_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, u8 **features UNNEEDED, u32 *timestamp UNNEEDED, struct pubkey *node_id UNNEEDED, u8 rgb_color[3] UNNEEDED, u8 alias[32] UNNEEDED, u8 **addresses UNNEEDED)
{ fprintf(stderr, "fromwire_node_announcement called!\n"); abort(); } { fprintf(stderr, "fromwire_node_announcement called!\n"); abort(); }
/* Generated stub for fromwire_peektype */
int fromwire_peektype(const u8 *cursor UNNEEDED)
{ fprintf(stderr, "fromwire_peektype called!\n"); abort(); }
/* Generated stub for fromwire_u8 */ /* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); } { fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
@ -123,6 +126,9 @@ u8 *towire_gossip_store_local_add_channel(const tal_t *ctx UNNEEDED, const u8 *l
/* Generated stub for towire_gossip_store_node_announcement */ /* Generated stub for towire_gossip_store_node_announcement */
u8 *towire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED) u8 *towire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_node_announcement called!\n"); abort(); } { fprintf(stderr, "towire_gossip_store_node_announcement called!\n"); abort(); }
/* Generated stub for wire_type_name */
const char *wire_type_name(int e UNNEEDED)
{ fprintf(stderr, "wire_type_name called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */ /* AUTOGENERATED MOCKS END */
/* Updates existing route if required. */ /* Updates existing route if required. */

6
gossipd/test/run-find_route-specific.c

@ -47,6 +47,9 @@ bool fromwire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const vo
/* Generated stub for fromwire_node_announcement */ /* Generated stub for fromwire_node_announcement */
bool fromwire_node_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, u8 **features UNNEEDED, u32 *timestamp UNNEEDED, struct pubkey *node_id UNNEEDED, u8 rgb_color[3] UNNEEDED, u8 alias[32] UNNEEDED, u8 **addresses UNNEEDED) bool fromwire_node_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, u8 **features UNNEEDED, u32 *timestamp UNNEEDED, struct pubkey *node_id UNNEEDED, u8 rgb_color[3] UNNEEDED, u8 alias[32] UNNEEDED, u8 **addresses UNNEEDED)
{ fprintf(stderr, "fromwire_node_announcement called!\n"); abort(); } { fprintf(stderr, "fromwire_node_announcement called!\n"); abort(); }
/* Generated stub for fromwire_peektype */
int fromwire_peektype(const u8 *cursor UNNEEDED)
{ fprintf(stderr, "fromwire_peektype called!\n"); abort(); }
/* Generated stub for fromwire_u8 */ /* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); } { fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
@ -87,6 +90,9 @@ u8 *towire_gossip_store_local_add_channel(const tal_t *ctx UNNEEDED, const u8 *l
/* Generated stub for towire_gossip_store_node_announcement */ /* Generated stub for towire_gossip_store_node_announcement */
u8 *towire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED) u8 *towire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_node_announcement called!\n"); abort(); } { fprintf(stderr, "towire_gossip_store_node_announcement called!\n"); abort(); }
/* Generated stub for wire_type_name */
const char *wire_type_name(int e UNNEEDED)
{ fprintf(stderr, "wire_type_name called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */ /* AUTOGENERATED MOCKS END */
const void *trc; const void *trc;

6
gossipd/test/run-find_route.c

@ -45,6 +45,9 @@ bool fromwire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const vo
/* Generated stub for fromwire_node_announcement */ /* Generated stub for fromwire_node_announcement */
bool fromwire_node_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, u8 **features UNNEEDED, u32 *timestamp UNNEEDED, struct pubkey *node_id UNNEEDED, u8 rgb_color[3] UNNEEDED, u8 alias[32] UNNEEDED, u8 **addresses UNNEEDED) bool fromwire_node_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED, u8 **features UNNEEDED, u32 *timestamp UNNEEDED, struct pubkey *node_id UNNEEDED, u8 rgb_color[3] UNNEEDED, u8 alias[32] UNNEEDED, u8 **addresses UNNEEDED)
{ fprintf(stderr, "fromwire_node_announcement called!\n"); abort(); } { fprintf(stderr, "fromwire_node_announcement called!\n"); abort(); }
/* Generated stub for fromwire_peektype */
int fromwire_peektype(const u8 *cursor UNNEEDED)
{ fprintf(stderr, "fromwire_peektype called!\n"); abort(); }
/* Generated stub for fromwire_u8 */ /* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); } { fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
@ -85,6 +88,9 @@ u8 *towire_gossip_store_local_add_channel(const tal_t *ctx UNNEEDED, const u8 *l
/* Generated stub for towire_gossip_store_node_announcement */ /* Generated stub for towire_gossip_store_node_announcement */
u8 *towire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED) u8 *towire_gossip_store_node_announcement(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED)
{ fprintf(stderr, "towire_gossip_store_node_announcement called!\n"); abort(); } { fprintf(stderr, "towire_gossip_store_node_announcement called!\n"); abort(); }
/* Generated stub for wire_type_name */
const char *wire_type_name(int e UNNEEDED)
{ fprintf(stderr, "wire_type_name called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */ /* AUTOGENERATED MOCKS END */
/* Updates existing route if required. */ /* Updates existing route if required. */

10
tests/fixtures.py

@ -91,6 +91,10 @@ def node_factory(directory, test_name, bitcoind, executor):
err_count += checkReconnect(node) err_count += checkReconnect(node)
if err_count: if err_count:
raise ValueError("{} nodes had unexpected reconnections".format(err_count)) raise ValueError("{} nodes had unexpected reconnections".format(err_count))
for node in nf.nodes:
err_count += checkBadGossipOrder(node)
if err_count:
raise ValueError("{} nodes had bad gossip order".format(err_count))
if not ok: if not ok:
raise Exception("At least one lightning exited with unexpected non-zero return code") raise Exception("At least one lightning exited with unexpected non-zero return code")
@ -147,6 +151,12 @@ def checkReconnect(node):
return 0 return 0
def checkBadGossipOrder(node):
if node.daemon.is_in_log('Bad gossip order') and not node.daemon.is_in_log('Deleting channel'):
return 1
return 0
@pytest.fixture @pytest.fixture
def executor(): def executor():
ex = futures.ThreadPoolExecutor(max_workers=20) ex = futures.ThreadPoolExecutor(max_workers=20)

12
tests/test_lightningd.py

@ -299,6 +299,13 @@ class BaseLightningDTests(unittest.TestCase):
return 1 return 1
return 0 return 0
def checkBadGossipOrder(self, node):
# We can have a race where we notice a channel deleted and someone
# sends an update.
if node.daemon.is_in_log('Bad gossip order') and not node.daemon.is_in_log('Deleting channel'):
return 1
return 0
def tearDown(self): def tearDown(self):
ok = self.node_factory.killall([not n.may_fail for n in self.node_factory.nodes]) ok = self.node_factory.killall([not n.may_fail for n in self.node_factory.nodes])
self.executor.shutdown(wait=False) self.executor.shutdown(wait=False)
@ -322,6 +329,11 @@ class BaseLightningDTests(unittest.TestCase):
if err_count: if err_count:
raise ValueError("{} nodes had unexpected reconnections".format(err_count)) raise ValueError("{} nodes had unexpected reconnections".format(err_count))
for node in self.node_factory.nodes:
err_count += self.checkBadGossipOrder(node)
if err_count:
raise ValueError("{} nodes had bad gossip order".format(err_count))
if not ok: if not ok:
raise Exception("At least one lightning exited with unexpected non-zero return code") raise Exception("At least one lightning exited with unexpected non-zero return code")

Loading…
Cancel
Save