gossipd: take signature checks out of routing.c

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-01-31 14:53:33 +10:30
parent 652432a298
commit 2d09af8d56
5 changed files with 262 additions and 229 deletions

View File

@ -8,6 +8,7 @@ GOSSIPD_HEADERS_WSRC := gossipd/gossipd_wiregen.h \
gossipd/queries.h \
gossipd/routing.h \
gossipd/txout_failures.h \
gossipd/sigcheck.h \
gossipd/seeker.h
GOSSIPD_HEADERS := $(GOSSIPD_HEADERS_WSRC) gossipd/broadcast.h

View File

@ -16,6 +16,7 @@
#include <gossipd/gossipd_wiregen.h>
#include <gossipd/queries.h>
#include <gossipd/routing.h>
#include <gossipd/sigcheck.h>
#include <gossipd/txout_failures.h>
#ifndef SUPERVERBOSE
@ -579,96 +580,6 @@ struct chan *new_chan(struct routing_state *rstate,
return chan;
}
/* Verify the signature of a channel_update message */
static u8 *check_channel_update(const tal_t *ctx,
const struct node_id *node_id,
const secp256k1_ecdsa_signature *node_sig,
const u8 *update)
{
/* 2 byte msg type + 64 byte signatures */
int offset = 66;
struct sha256_double hash;
sha256_double(&hash, update + offset, tal_count(update) - offset);
if (!check_signed_hash_nodeid(&hash, node_sig, node_id))
return towire_warningfmt(ctx, NULL,
"Bad signature for %s hash %s"
" on channel_update %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
node_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, update));
return NULL;
}
static u8 *check_channel_announcement(const tal_t *ctx,
const struct node_id *node1_id, const struct node_id *node2_id,
const struct pubkey *bitcoin1_key, const struct pubkey *bitcoin2_key,
const secp256k1_ecdsa_signature *node1_sig,
const secp256k1_ecdsa_signature *node2_sig,
const secp256k1_ecdsa_signature *bitcoin1_sig,
const secp256k1_ecdsa_signature *bitcoin2_sig, const u8 *announcement)
{
/* 2 byte msg type + 256 byte signatures */
int offset = 258;
struct sha256_double hash;
sha256_double(&hash, announcement + offset,
tal_count(announcement) - offset);
if (!check_signed_hash_nodeid(&hash, node1_sig, node1_id)) {
return towire_warningfmt(ctx, NULL,
"Bad node_signature_1 %s hash %s"
" on channel_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
node1_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, announcement));
}
if (!check_signed_hash_nodeid(&hash, node2_sig, node2_id)) {
return towire_warningfmt(ctx, NULL,
"Bad node_signature_2 %s hash %s"
" on channel_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
node2_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, announcement));
}
if (!check_signed_hash(&hash, bitcoin1_sig, bitcoin1_key)) {
return towire_warningfmt(ctx, NULL,
"Bad bitcoin_signature_1 %s hash %s"
" on channel_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
bitcoin1_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, announcement));
}
if (!check_signed_hash(&hash, bitcoin2_sig, bitcoin2_key)) {
return towire_warningfmt(ctx, NULL,
"Bad bitcoin_signature_2 %s hash %s"
" on channel_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
bitcoin2_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, announcement));
}
return NULL;
}
/* We allow node announcements for this node if it doesn't otherwise exist, so
* we can process them once it does exist (a channel_announce is being
* validated right now).
@ -889,6 +800,7 @@ u8 *handle_channel_announcement(struct routing_state *rstate,
secp256k1_ecdsa_signature node_signature_1, node_signature_2;
secp256k1_ecdsa_signature bitcoin_signature_1, bitcoin_signature_2;
struct chan *chan;
const char *err;
pending = tal(rstate, struct pending_cannouncement);
pending->source_peer = tal_dup_or_null(pending, struct node_id, source_peer);
@ -990,17 +902,17 @@ u8 *handle_channel_announcement(struct routing_state *rstate,
}
/* Note that if node_id_1 or node_id_2 are malformed, it's caught here */
warn = check_channel_announcement(rstate,
&pending->node_id_1,
&pending->node_id_2,
&pending->bitcoin_key_1,
&pending->bitcoin_key_2,
&node_signature_1,
&node_signature_2,
&bitcoin_signature_1,
&bitcoin_signature_2,
pending->announce);
if (warn) {
err = sigcheck_channel_announcement(tmpctx,
&pending->node_id_1,
&pending->node_id_2,
&pending->bitcoin_key_1,
&pending->bitcoin_key_2,
&node_signature_1,
&node_signature_2,
&bitcoin_signature_1,
&bitcoin_signature_2,
pending->announce);
if (err) {
/* BOLT #7:
*
* - if `bitcoin_signature_1`, `bitcoin_signature_2`,
@ -1010,6 +922,7 @@ u8 *handle_channel_announcement(struct routing_state *rstate,
* - MAY close the connection.
* - MUST ignore the message.
*/
warn = towire_warningfmt(rstate, NULL, "%s", err);
goto malformed;
}
@ -1585,7 +1498,7 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES,
struct bitcoin_blkid chain_hash;
u8 direction;
struct pending_cannouncement *pending;
u8 *warn;
const char *err;
serialized = tal_dup_talarr(tmpctx, u8, update);
if (!fromwire_channel_update(serialized, &signature,
@ -1647,7 +1560,7 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES,
/* This may be a local channel we don't know about. If it's from a peer,
* check signature assuming it's from that peer, and if it's valid, hand to ld */
if (source_peer
&& check_channel_update(tmpctx, source_peer, &signature, serialized) == NULL) {
&& sigcheck_channel_update(tmpctx, source_peer, &signature, serialized) == NULL) {
tell_lightningd_peer_update(rstate, source_peer,
short_channel_id, fee_base_msat,
fee_proportional_millionths,
@ -1668,8 +1581,8 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES,
return NULL;
}
warn = check_channel_update(rstate, owner, &signature, serialized);
if (warn) {
err = sigcheck_channel_update(tmpctx, owner, &signature, serialized);
if (err) {
/* BOLT #7:
*
* - if `signature` is not a valid signature, using `node_id`
@ -1679,7 +1592,7 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES,
* - SHOULD send a `warning` and close the connection.
* - MUST NOT process the message further.
*/
return warn;
return towire_warningfmt(rstate, NULL, "%s", err);
}
routing_add_channel_update(rstate, take(serialized), 0, source_peer, force,
@ -1956,7 +1869,6 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann,
bool *was_unknown)
{
u8 *serialized;
struct sha256_double hash;
secp256k1_ecdsa_signature signature;
u32 timestamp;
struct node_id node_id;
@ -1966,6 +1878,7 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann,
struct wireaddr *wireaddrs;
size_t len = tal_count(node_ann);
struct tlv_node_ann_tlvs *na_tlv;
const char *err;
if (was_unknown)
*was_unknown = false;
@ -1991,31 +1904,10 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann,
return NULL;
}
sha256_double(&hash, serialized + 66, tal_count(serialized) - 66);
/* If node_id is invalid, it fails here */
if (!check_signed_hash_nodeid(&hash, &signature, &node_id)) {
/* BOLT #7:
*
* - if `signature` is not a valid signature, using
* `node_id` of the double-SHA256 of the entire
* message following the `signature` field
* (including unknown fields following
* `fee_proportional_millionths`):
* - SHOULD send a `warning` and close the connection.
* - MUST NOT process the message further.
*/
u8 *warn = towire_warningfmt(rstate, NULL,
"Bad signature for %s hash %s"
" on node_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
&signature),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, node_ann));
return warn;
}
err = sigcheck_node_announcement(tmpctx, &node_id, &signature,
serialized);
if (err)
return towire_warningfmt(rstate, NULL, "%s", err);
wireaddrs = fromwire_wireaddr_array(tmpctx, addresses);
if (!wireaddrs) {
@ -2026,11 +1918,10 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann,
* - SHOULD send a `warning`.
* - MAY close the connection.
*/
u8 *warn = towire_warningfmt(rstate, NULL,
"Malformed wireaddrs %s in %s.",
tal_hex(tmpctx, wireaddrs),
tal_hex(tmpctx, node_ann));
return warn;
return towire_warningfmt(rstate, NULL,
"Malformed wireaddrs %s in %s.",
tal_hex(tmpctx, wireaddrs),
tal_hex(tmpctx, node_ann));
}
/* May still fail, if we don't know the node. */

184
gossipd/sigcheck.c Normal file
View File

@ -0,0 +1,184 @@
#include "config.h"
#include <bitcoin/shadouble.h>
#include <bitcoin/signature.h>
#include <ccan/tal/str/str.h>
#include <common/type_to_string.h>
#include <common/wire_error.h>
#include <gossipd/sigcheck.h>
/* Verify the signature of a channel_update message */
const char *sigcheck_channel_update(const tal_t *ctx,
const struct node_id *node_id,
const secp256k1_ecdsa_signature *node_sig,
const u8 *update)
{
/* BOLT #7:
* 1. type: 258 (`channel_update`)
* 2. data:
* * [`signature`:`signature`]
* * [`chain_hash`:`chain_hash`]
* * [`short_channel_id`:`short_channel_id`]
* * [`u32`:`timestamp`]
* * [`byte`:`message_flags`]
* * [`byte`:`channel_flags`]
* * [`u16`:`cltv_expiry_delta`]
* * [`u64`:`htlc_minimum_msat`]
* * [`u32`:`fee_base_msat`]
* * [`u32`:`fee_proportional_millionths`]
* * [`u64`:`htlc_maximum_msat`]
*/
/* 2 byte msg type + 64 byte signatures */
int offset = 66;
struct sha256_double hash;
sha256_double(&hash, update + offset, tal_count(update) - offset);
if (!check_signed_hash_nodeid(&hash, node_sig, node_id))
return tal_fmt(ctx,
"Bad signature for %s hash %s"
" on channel_update %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
node_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, update));
return NULL;
}
const char *sigcheck_channel_announcement(const tal_t *ctx,
const struct node_id *node1_id,
const struct node_id *node2_id,
const struct pubkey *bitcoin1_key,
const struct pubkey *bitcoin2_key,
const secp256k1_ecdsa_signature *node1_sig,
const secp256k1_ecdsa_signature *node2_sig,
const secp256k1_ecdsa_signature *bitcoin1_sig,
const secp256k1_ecdsa_signature *bitcoin2_sig,
const u8 *announcement)
{
/* BOLT #7:
* 1. type: 256 (`channel_announcement`)
* 2. data:
* * [`signature`:`node_signature_1`]
* * [`signature`:`node_signature_2`]
* * [`signature`:`bitcoin_signature_1`]
* * [`signature`:`bitcoin_signature_2`]
* * [`u16`:`len`]
* * [`len*byte`:`features`]
* * [`chain_hash`:`chain_hash`]
* * [`short_channel_id`:`short_channel_id`]
* * [`point`:`node_id_1`]
* * [`point`:`node_id_2`]
* * [`point`:`bitcoin_key_1`]
* * [`point`:`bitcoin_key_2`]
*/
/* 2 byte msg type + 256 byte signatures */
int offset = 258;
struct sha256_double hash;
sha256_double(&hash, announcement + offset,
tal_count(announcement) - offset);
if (!check_signed_hash_nodeid(&hash, node1_sig, node1_id)) {
return tal_fmt(ctx,
"Bad node_signature_1 %s hash %s"
" on channel_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
node1_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, announcement));
}
if (!check_signed_hash_nodeid(&hash, node2_sig, node2_id)) {
return tal_fmt(ctx,
"Bad node_signature_2 %s hash %s"
" on channel_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
node2_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, announcement));
}
if (!check_signed_hash(&hash, bitcoin1_sig, bitcoin1_key)) {
return tal_fmt(ctx,
"Bad bitcoin_signature_1 %s hash %s"
" on channel_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
bitcoin1_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, announcement));
}
if (!check_signed_hash(&hash, bitcoin2_sig, bitcoin2_key)) {
return tal_fmt(ctx,
"Bad bitcoin_signature_2 %s hash %s"
" on channel_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
bitcoin2_sig),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, announcement));
}
return NULL;
}
/* Returns warning msg if signature wrong, else NULL */
const char *sigcheck_node_announcement(const tal_t *ctx,
const struct node_id *node_id,
const secp256k1_ecdsa_signature *signature,
const u8 *node_announcement)
{
/* BOLT #7:
*
* 1. type: 257 (`node_announcement`)
* 2. data:
* * [`signature`:`signature`]
* * [`u16`:`flen`]
* * [`flen*byte`:`features`]
* * [`u32`:`timestamp`]
* * [`point`:`node_id`]
* * [`3*byte`:`rgb_color`]
* * [`32*byte`:`alias`]
* * [`u16`:`addrlen`]
* * [`addrlen*byte`:`addresses`]
*/
/* 2 byte msg type + 64 byte signatures */
int offset = 66;
struct sha256_double hash;
sha256_double(&hash, node_announcement + offset, tal_count(node_announcement) - offset);
/* If node_id is invalid, it fails here */
if (!check_signed_hash_nodeid(&hash, signature, node_id)) {
/* BOLT #7:
*
* - if `signature` is not a valid signature, using
* `node_id` of the double-SHA256 of the entire
* message following the `signature` field
* (including unknown fields following
* `fee_proportional_millionths`):
* - SHOULD send a `warning` and close the connection.
* - MUST NOT process the message further.
*/
return tal_fmt(ctx,
"Bad signature for %s hash %s"
" on node_announcement %s",
type_to_string(tmpctx,
secp256k1_ecdsa_signature,
signature),
type_to_string(tmpctx,
struct sha256_double,
&hash),
tal_hex(tmpctx, node_announcement));
}
return NULL;
}

29
gossipd/sigcheck.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef LIGHTNING_GOSSIPD_SIGCHECK_H
#define LIGHTNING_GOSSIPD_SIGCHECK_H
#include "config.h"
#include <common/node_id.h>
/* Returns error msg if signature wrong, else NULL */
const char *sigcheck_channel_update(const tal_t *ctx,
const struct node_id *node_id,
const secp256k1_ecdsa_signature *node_sig,
const u8 *update);
/* Returns error msg if signature wrong, else NULL */
const char *sigcheck_channel_announcement(const tal_t *ctx,
const struct node_id *node1_id,
const struct node_id *node2_id,
const struct pubkey *bitcoin1_key,
const struct pubkey *bitcoin2_key,
const secp256k1_ecdsa_signature *node1_sig,
const secp256k1_ecdsa_signature *node2_sig,
const secp256k1_ecdsa_signature *bitcoin1_sig,
const secp256k1_ecdsa_signature *bitcoin2_sig,
const u8 *announcement);
/* Returns error msg if signature wrong, else NULL */
const char *sigcheck_node_announcement(const tal_t *ctx,
const struct node_id *node_id,
const secp256k1_ecdsa_signature *node_sig,
const u8 *node_announcement);
#endif /* LIGHTNING_GOSSIPD_SIGCHECK_H */

View File

@ -29,7 +29,8 @@ In particular, we set feature bit 19. The spec says we should set feature bit 1
#include "config.h"
#include "../common/wire_error.c"
#include "../routing.c"
#include "../sigcheck.c"
#include <assert.h>
#include <common/blinding.h>
#include <common/channel_type.h>
#include <common/ecdh.h>
@ -54,84 +55,13 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED,
const struct sha256 *h UNNEEDED,
struct pubkey *next UNNEEDED)
{ fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); }
/* Generated stub for daemon_conn_send */
void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED)
{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); }
/* Generated stub for get_cupdate_parts */
void get_cupdate_parts(const u8 *channel_update UNNEEDED,
const u8 *parts[2] UNNEEDED,
size_t sizes[2])
{ fprintf(stderr, "get_cupdate_parts called!\n"); abort(); }
/* Generated stub for gossip_store_add */
u64 gossip_store_add(struct gossip_store *gs UNNEEDED, const u8 *gossip_msg UNNEEDED,
u32 timestamp UNNEEDED, bool zombie UNNEEDED, bool spam UNNEEDED, bool dying UNNEEDED,
const u8 *addendum UNNEEDED)
{ fprintf(stderr, "gossip_store_add called!\n"); abort(); }
/* Generated stub for gossip_store_delete */
void gossip_store_delete(struct gossip_store *gs UNNEEDED,
struct broadcastable *bcast UNNEEDED,
int type UNNEEDED)
{ fprintf(stderr, "gossip_store_delete called!\n"); abort(); }
/* Generated stub for gossip_store_get */
const u8 *gossip_store_get(const tal_t *ctx UNNEEDED,
struct gossip_store *gs UNNEEDED,
u64 offset UNNEEDED)
{ fprintf(stderr, "gossip_store_get called!\n"); abort(); }
/* Generated stub for gossip_store_mark_channel_deleted */
void gossip_store_mark_channel_deleted(struct gossip_store *gs UNNEEDED,
const struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "gossip_store_mark_channel_deleted called!\n"); abort(); }
/* Generated stub for gossip_store_mark_dying */
void gossip_store_mark_dying(struct gossip_store *gs UNNEEDED,
const struct broadcastable *bcast UNNEEDED,
int type UNNEEDED)
{ fprintf(stderr, "gossip_store_mark_dying called!\n"); abort(); }
/* Generated stub for gossip_store_new */
struct gossip_store *gossip_store_new(struct routing_state *rstate UNNEEDED)
{ fprintf(stderr, "gossip_store_new called!\n"); abort(); }
/* Generated stub for in_txout_failures */
bool in_txout_failures(struct txout_failures *txf UNNEEDED,
const struct short_channel_id scid UNNEEDED)
{ fprintf(stderr, "in_txout_failures called!\n"); abort(); }
/* Generated stub for memleak_add_helper_ */
void memleak_add_helper_(const tal_t *p UNNEEDED, void (*cb)(struct htable *memtable UNNEEDED,
const tal_t *)){ }
/* Generated stub for memleak_scan_htable */
void memleak_scan_htable(struct htable *memtable UNNEEDED, const struct htable *ht UNNEEDED)
{ fprintf(stderr, "memleak_scan_htable called!\n"); abort(); }
/* Generated stub for memleak_scan_intmap_ */
void memleak_scan_intmap_(struct htable *memtable UNNEEDED, const struct intmap *m UNNEEDED)
{ fprintf(stderr, "memleak_scan_intmap_ called!\n"); abort(); }
/* Generated stub for notleak_ */
void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED)
{ fprintf(stderr, "notleak_ called!\n"); abort(); }
/* Generated stub for peer_supplied_good_gossip */
void peer_supplied_good_gossip(struct daemon *daemon UNNEEDED,
const struct node_id *source_peer UNNEEDED,
size_t amount UNNEEDED)
{ fprintf(stderr, "peer_supplied_good_gossip called!\n"); abort(); }
/* Generated stub for status_fmt */
void status_fmt(enum log_level level UNNEEDED,
const struct node_id *peer UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
/* Generated stub for towire_gossipd_remote_channel_update */
u8 *towire_gossipd_remote_channel_update(const tal_t *ctx UNNEEDED, const struct node_id *source_node UNNEEDED, const struct peer_update *peer_update UNNEEDED)
{ fprintf(stderr, "towire_gossipd_remote_channel_update called!\n"); abort(); }
/* Generated stub for txout_failures_add */
void txout_failures_add(struct txout_failures *txf UNNEEDED,
const struct short_channel_id scid UNNEEDED)
{ fprintf(stderr, "txout_failures_add called!\n"); abort(); }
/* Generated stub for txout_failures_new */
struct txout_failures *txout_failures_new(const tal_t *ctx UNNEEDED, struct daemon *daemon UNNEEDED)
{ fprintf(stderr, "txout_failures_new called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
int main(int argc, char *argv[])
{
struct bitcoin_blkid chain_hash;
u8 *features, *err;
u8 *features;
const char *err;
secp256k1_ecdsa_signature node_signature_1, node_signature_2;
secp256k1_ecdsa_signature bitcoin_signature_1, bitcoin_signature_2;
struct short_channel_id short_channel_id;
@ -156,16 +86,15 @@ int main(int argc, char *argv[])
&bitcoin_key_2))
abort();
err = check_channel_announcement(cannounce,
&node_id_1, &node_id_2,
&bitcoin_key_1, &bitcoin_key_2,
&node_signature_1, &node_signature_2,
&bitcoin_signature_1,
&bitcoin_signature_2,
cannounce);
err = sigcheck_channel_announcement(cannounce,
&node_id_1, &node_id_2,
&bitcoin_key_1, &bitcoin_key_2,
&node_signature_1, &node_signature_2,
&bitcoin_signature_1,
&bitcoin_signature_2,
cannounce);
assert(err);
assert(memmem(err, tal_bytelen(err),
"Bad node_signature_1", strlen("Bad node_signature_1")));
assert(strstr(err, "Bad node_signature_1"));
/* Turns out they didn't include the feature bit at all. */
cannounce = towire_channel_announcement(tmpctx,
@ -180,16 +109,15 @@ int main(int argc, char *argv[])
&node_id_2,
&bitcoin_key_1,
&bitcoin_key_2);
err = check_channel_announcement(cannounce,
&node_id_1, &node_id_2,
&bitcoin_key_1, &bitcoin_key_2,
&node_signature_1, &node_signature_2,
&bitcoin_signature_1,
&bitcoin_signature_2,
cannounce);
err = sigcheck_channel_announcement(cannounce,
&node_id_1, &node_id_2,
&bitcoin_key_1, &bitcoin_key_2,
&node_signature_1, &node_signature_2,
&bitcoin_signature_1,
&bitcoin_signature_2,
cannounce);
assert(err);
assert(memmem(err, tal_bytelen(err),
"Bad node_signature_2", strlen("Bad node_signature_2")));
assert(strstr(err, "Bad node_signature_2"));
common_shutdown();
return 0;