From 565f7deec06bb2fbac3a6293a75784b17f537da7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 11 Nov 2025 11:33:22 +1030 Subject: [PATCH] connectd: at disconnected, tell lightningd how long we were connected. Signed-off-by: Rusty Russell --- connectd/connectd.c | 32 +++++++++++++++------ connectd/connectd.h | 6 +++- connectd/connectd_wire.csv | 2 ++ connectd/handshake.c | 14 ++++++++- connectd/handshake.h | 8 ++++-- connectd/multiplex.c | 5 ++-- connectd/peer_exchange_initmsg.c | 6 ++++ connectd/peer_exchange_initmsg.h | 1 + connectd/test/run-initiator-success.c | 1 + connectd/test/run-responder-success.c | 1 + devtools/gossipwith.c | 1 + lightningd/peer_control.c | 18 ++++++++---- lightningd/test/run-invoice-select-inchan.c | 4 +-- tests/fuzz/connectd_handshake.h | 1 + wallet/test/run-wallet.c | 4 +-- 15 files changed, 79 insertions(+), 25 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 7352feb80..ea93b2301 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -112,6 +112,7 @@ static struct peer *new_peer(struct daemon *daemon, const struct crypto_state *cs, const u8 *their_features, enum is_websocket is_websocket, + struct timemono connect_starttime, struct io_conn *conn STEALS, int *fd_for_subd) { @@ -119,6 +120,7 @@ static struct peer *new_peer(struct daemon *daemon, peer->daemon = daemon; peer->id = *id; + peer->connect_starttime = connect_starttime; peer->counter = daemon->connection_counter++; peer->cs = *cs; peer->subds = tal_arr(peer, struct subd *, 0); @@ -258,11 +260,12 @@ static void reset_reconnect_timer(struct peer *peer) void send_disconnected(struct daemon *daemon, const struct node_id *id, - u64 connectd_counter) + u64 connectd_counter, + struct timemono starttime) { /* lightningd: it's gone */ daemon_conn_send(daemon->master, - take(towire_connectd_peer_disconnected(NULL, id, connectd_counter))); + take(towire_connectd_peer_disconnected(NULL, id, connectd_counter, time_to_nsec(timemono_since(starttime))))); /* Tell gossipd to stop asking this peer gossip queries */ daemon_conn_send(daemon->gossipd, @@ -282,6 +285,7 @@ struct io_plan *peer_connected(struct io_conn *conn, struct crypto_state *cs, const u8 *their_features TAKES, enum is_websocket is_websocket, + struct timemono starttime, bool incoming) { u8 *msg; @@ -294,11 +298,13 @@ struct io_plan *peer_connected(struct io_conn *conn, const char *connect_reason; u64 connect_time_nsec; u64 prev_connectd_counter; + struct timemono prev_connect_start; /* We remove any previous connection immediately, on the assumption it's dead */ oldpeer = peer_htable_get(daemon->peers, id); if (oldpeer) { prev_connectd_counter = oldpeer->counter; + prev_connect_start = oldpeer->connect_starttime; destroy_peer_immediately(oldpeer); } @@ -320,7 +326,8 @@ struct io_plan *peer_connected(struct io_conn *conn, if (unsup != -1) { /* We were going to send a reconnect message, but not now! */ if (oldpeer) - send_disconnected(daemon, id, prev_connectd_counter); + send_disconnected(daemon, id, prev_connectd_counter, + prev_connect_start); status_peer_unusual(id, "Unsupported feature %u", unsup); msg = towire_warningfmt(NULL, NULL, "Unsupported feature %u", unsup); @@ -331,7 +338,8 @@ struct io_plan *peer_connected(struct io_conn *conn, if (!feature_check_depends(their_features, &depender, &missing)) { /* We were going to send a reconnect message, but not now! */ if (oldpeer) - send_disconnected(daemon, id, prev_connectd_counter); + send_disconnected(daemon, id, prev_connectd_counter, + prev_connect_start); status_peer_unusual(id, "Feature %zu requires feature %zu", depender, missing); msg = towire_warningfmt(NULL, NULL, @@ -374,13 +382,14 @@ struct io_plan *peer_connected(struct io_conn *conn, } /* This contains the per-peer state info; gossipd fills in pps->gs */ - peer = new_peer(daemon, id, cs, their_features, is_websocket, conn, + peer = new_peer(daemon, id, cs, their_features, is_websocket, starttime, conn, &subd_fd); /* Only takes over conn if it succeeds. */ if (!peer) { /* We were going to send a reconnect message, but not now! */ if (oldpeer) - send_disconnected(daemon, id, prev_connectd_counter); + send_disconnected(daemon, id, prev_connectd_counter, + prev_connect_start); return io_close(conn); } @@ -398,7 +407,8 @@ struct io_plan *peer_connected(struct io_conn *conn, prev_connectd_counter, peer->counter, addr, remote_addr, - incoming, their_features); + incoming, their_features, + time_to_nsec(timemono_since(prev_connect_start))); } else { /* Tell gossipd about new peer */ msg = towire_gossipd_new_peer(NULL, id, option_gossip_queries); @@ -438,13 +448,15 @@ static struct io_plan *handshake_in_success(struct io_conn *conn, struct crypto_state *cs, struct oneshot *timeout, enum is_websocket is_websocket, + struct timemono starttime, struct daemon *daemon) { struct node_id id; node_id_from_pubkey(&id, id_key); status_peer_debug(&id, "Connect IN"); return peer_exchange_initmsg(conn, daemon, daemon->our_features, - cs, &id, addr, timeout, is_websocket, true); + cs, &id, addr, timeout, is_websocket, + starttime, true); } /*~ If the timer goes off, we simply free everything, which hangs up. */ @@ -730,6 +742,7 @@ static struct io_plan *handshake_out_success(struct io_conn *conn, struct crypto_state *cs, struct oneshot *timeout, enum is_websocket is_websocket, + struct timemono starttime, struct connecting *connect) { struct node_id id; @@ -739,7 +752,8 @@ static struct io_plan *handshake_out_success(struct io_conn *conn, status_peer_debug(&id, "Connect OUT"); return peer_exchange_initmsg(conn, connect->daemon, connect->daemon->our_features, - cs, &id, addr, timeout, is_websocket, false); + cs, &id, addr, timeout, is_websocket, + starttime, false); } struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect) diff --git a/connectd/connectd.h b/connectd/connectd.h index b6ab7a41f..8a5762330 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -64,6 +64,8 @@ struct peer { struct node_id id; /* Counters and keys for symmetric crypto */ struct crypto_state cs; + /* Time when we first connected */ + struct timemono connect_starttime; /* Connection to the peer (NULL if it's disconnected and we're flushing) */ struct io_conn *to_peer; @@ -388,12 +390,14 @@ struct io_plan *peer_connected(struct io_conn *conn, struct crypto_state *cs, const u8 *their_features TAKES, enum is_websocket is_websocket, + struct timemono starttime, bool incoming); /* Tell gossipd and lightningd that this peer is gone. */ void send_disconnected(struct daemon *daemon, const struct node_id *id, - u64 connectd_counter); + u64 connectd_counter, + struct timemono starttime); /* Free peer immediately (don't wait for draining). */ void destroy_peer_immediately(struct peer *peer); diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index 913482dad..c4ad70ea0 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -90,6 +90,7 @@ msgdata,connectd_peer_connected,connect_nsec,u64, msgtype,connectd_peer_disconnected,2006 msgdata,connectd_peer_disconnected,id,node_id, msgdata,connectd_peer_disconnected,counter,u64, +msgdata,connectd_peer_disconnected,connected_time_nsec,u64, # Connectd -> master: peer reconnected (disconnect & connect) msgtype,connectd_peer_reconnected,2010 @@ -101,6 +102,7 @@ msgdata,connectd_peer_reconnected,remote_addr,?wireaddr, msgdata,connectd_peer_reconnected,incoming,bool, msgdata,connectd_peer_reconnected,flen,u16, msgdata,connectd_peer_reconnected,features,u8,flen +msgdata,connectd_peer_reconnected,connected_time_nsec,u64, # Master -> connectd: make peer active immediately (we want to talk) (+ fd to subd). msgtype,connectd_peer_connect_subd,2004 diff --git a/connectd/handshake.c b/connectd/handshake.c index 3a11dead0..09e44bfa9 100644 --- a/connectd/handshake.c +++ b/connectd/handshake.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -178,6 +179,9 @@ struct handshake { /* Are we connected via a websocket? */ enum is_websocket is_websocket; + /* Time they first connected */ + struct timemono starttime; + /* Function to call once handshake complete. */ struct io_plan *(*cb)(struct io_conn *conn, const struct pubkey *their_id, @@ -185,6 +189,7 @@ struct handshake { struct crypto_state *cs, struct oneshot *timeout, enum is_websocket is_websocket, + struct timemono starttime, void *cbarg); void *cbarg; }; @@ -357,12 +362,14 @@ static struct io_plan *handshake_succeeded(struct io_conn *conn, struct crypto_state *cs, struct oneshot *timeout, enum is_websocket is_websocket, + struct timemono starttime, void *cbarg); void *cbarg; struct pubkey their_id; struct wireaddr_internal addr; struct oneshot *timeout; enum is_websocket is_websocket; + struct timemono starttime; /* BOLT #8: * @@ -396,9 +403,10 @@ static struct io_plan *handshake_succeeded(struct io_conn *conn, addr = h->addr; timeout = h->timeout; is_websocket = h->is_websocket; + starttime = h->starttime; tal_free(h); - return cb(conn, &their_id, &addr, &cs, timeout, is_websocket, cbarg); + return cb(conn, &their_id, &addr, &cs, timeout, is_websocket, starttime, cbarg); } static struct handshake *new_handshake(const tal_t *ctx, @@ -983,12 +991,14 @@ struct io_plan *responder_handshake_(struct io_conn *conn, struct crypto_state *, struct oneshot *, enum is_websocket, + struct timemono, void *cbarg), void *cbarg) { struct handshake *h = new_handshake(conn, my_id); h->side = RESPONDER; + h->starttime = time_mono(); h->my_id = *my_id; h->addr = *addr; h->cbarg = cbarg; @@ -1011,12 +1021,14 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, struct crypto_state *, struct oneshot *timeout, enum is_websocket is_websocket, + struct timemono, void *cbarg), void *cbarg) { struct handshake *h = new_handshake(conn, their_id); h->side = INITIATOR; + h->starttime = time_mono(); h->my_id = *my_id; h->their_id = *their_id; h->addr = *addr; diff --git a/connectd/handshake.h b/connectd/handshake.h index ec52fb3ca..6447ae089 100644 --- a/connectd/handshake.h +++ b/connectd/handshake.h @@ -26,7 +26,8 @@ enum is_websocket { const struct wireaddr_internal *, \ struct crypto_state *, \ struct oneshot *, \ - enum is_websocket), \ + enum is_websocket, \ + struct timemono), \ (cbarg)) @@ -42,6 +43,7 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, struct crypto_state *, struct oneshot *timeout, enum is_websocket, + struct timemono, void *cbarg), void *cbarg); @@ -55,7 +57,8 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, const struct wireaddr_internal *, \ struct crypto_state *, \ struct oneshot *, \ - enum is_websocket), \ + enum is_websocket, \ + struct timemono), \ (cbarg)) struct io_plan *responder_handshake_(struct io_conn *conn, @@ -69,6 +72,7 @@ struct io_plan *responder_handshake_(struct io_conn *conn, struct crypto_state *, struct oneshot *, enum is_websocket, + struct timemono, void *cbarg), void *cbarg); #endif /* LIGHTNING_CONNECTD_HANDSHAKE_H */ diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 2778a22ff..a06a21079 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -1392,9 +1392,10 @@ static void destroy_peer_conn(struct io_conn *peer_conn, struct peer *peer) { assert(peer->to_peer == peer_conn); - /* We are no longer connected. Tell lightningd & gossipd*/ + /* We are no longer connected. Tell lightningd & gossipd */ peer->to_peer = NULL; - send_disconnected(peer->daemon, &peer->id, peer->counter); + send_disconnected(peer->daemon, &peer->id, peer->counter, + peer->connect_starttime); /* Wake subds: give them 5 seconds to flush. */ for (size_t i = 0; i < tal_count(peer->subds); i++) { diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index bbcb6b44d..a73213696 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -34,6 +34,9 @@ struct early_peer { /* Timeout in case it takes too long */ struct oneshot *timeout; + + /* We record time when we first accepted socket */ + struct timemono starttime; }; static bool contains_common_chain(struct bitcoin_blkid *chains) @@ -152,6 +155,7 @@ static struct io_plan *peer_init_received(struct io_conn *conn, &peer->cs, take(features), peer->is_websocket, + peer->starttime, peer->incoming); } @@ -206,6 +210,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, const struct wireaddr_internal *addr, struct oneshot *timeout, enum is_websocket is_websocket, + struct timemono starttime, bool incoming) { /* If conn is closed, forget peer */ @@ -220,6 +225,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, peer->incoming = incoming; peer->is_websocket = is_websocket; peer->timeout = timeout; + peer->starttime = starttime; /* BOLT #1: * diff --git a/connectd/peer_exchange_initmsg.h b/connectd/peer_exchange_initmsg.h index 702e13504..1254b8647 100644 --- a/connectd/peer_exchange_initmsg.h +++ b/connectd/peer_exchange_initmsg.h @@ -19,6 +19,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, const struct wireaddr_internal *addr, struct oneshot *timeout, enum is_websocket is_websocket, + struct timemono starttime, bool incoming); #endif /* LIGHTNING_CONNECTD_PEER_EXCHANGE_INITMSG_H */ diff --git a/connectd/test/run-initiator-success.c b/connectd/test/run-initiator-success.c index c083571f1..6a652ca5c 100644 --- a/connectd/test/run-initiator-success.c +++ b/connectd/test/run-initiator-success.c @@ -186,6 +186,7 @@ static struct io_plan *success(struct io_conn *conn UNUSED, struct crypto_state *cs, struct oneshot *timeout UNUSED, enum is_websocket is_websocket UNUSED, + struct timemono starttime UNUSED, void *unused UNUSED) { assert(pubkey_eq(them, &rs_pub)); diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c index 881c63c4b..c4c2e7339 100644 --- a/connectd/test/run-responder-success.c +++ b/connectd/test/run-responder-success.c @@ -185,6 +185,7 @@ static struct io_plan *success(struct io_conn *conn UNUSED, struct crypto_state *cs, struct oneshot *timeout UNUSED, enum is_websocket is_websocket UNUSED, + struct timemono starttime UNUSED, void *unused UNUSED) { assert(secret_eq_str(&cs->sk, expect_sk)); diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index 827c1a68d..84b396828 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -182,6 +182,7 @@ static struct io_plan *handshake_success(struct io_conn *conn, struct crypto_state *cs, struct oneshot *timer, enum is_websocket is_websocket, + struct timemono starttime, char **args) { int peer_fd = io_conn_fd(conn); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index ae2f017d1..dd0396d6b 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -43,6 +43,7 @@ static void peer_disconnected(struct lightningd *ld, const struct node_id *id, u64 connectd_counter, + u64 connected_time_nsec, bool fail_connect_attempts); /* Common pattern: create a sockpair for this channel, return one as a peer_fd */ @@ -1723,21 +1724,22 @@ void handle_peer_connected(struct lightningd *ld, const u8 *msg) &their_features, &connect_reason, &connect_nsec)) { - u64 prev_connectd_counter; + u64 prev_connectd_counter, connected_time_nsec; if (!fromwire_connectd_peer_reconnected(hook_payload, msg, &id, &prev_connectd_counter, &connectd_counter, &hook_payload->addr, &hook_payload->remote_addr, &hook_payload->incoming, - &their_features)) { + &their_features, + &connected_time_nsec)) { fatal("Connectd gave bad CONNECT_PEER_(RE)CONNECTED message %s", tal_hex(msg, msg)); } /* Reconnect? Mark the disconnect *first*, but don't * fail any connect attempts: this is a race. */ log_peer_debug(ld->log, &id, "peer reconnected"); - peer_disconnected(ld, &id, prev_connectd_counter, false); + peer_disconnected(ld, &id, prev_connectd_counter, connected_time_nsec, false); connect_reason = tal_strdup(hook_payload, ""); connect_nsec = 0; } @@ -2083,6 +2085,7 @@ static void destroy_disconnect_command(struct disconnect_command *dc) static void peer_disconnected(struct lightningd *ld, const struct node_id *id, u64 connectd_counter, + u64 connected_time_nsec, bool fail_connect_attempts) { struct disconnect_command *i, *next; @@ -2127,13 +2130,16 @@ static void peer_disconnected(struct lightningd *ld, void handle_peer_disconnected(struct lightningd *ld, const u8 *msg) { struct node_id id; - u64 connectd_counter; + u64 connectd_counter, connected_time_nsec; - if (!fromwire_connectd_peer_disconnected(msg, &id, &connectd_counter)) + if (!fromwire_connectd_peer_disconnected(msg, + &id, + &connectd_counter, + &connected_time_nsec)) fatal("Connectd gave bad PEER_DISCONNECTED message %s", tal_hex(msg, msg)); - peer_disconnected(ld, &id, connectd_counter, true); + peer_disconnected(ld, &id, connectd_counter, connected_time_nsec, true); } void update_channel_from_inflight(struct lightningd *ld, diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 3ed72c704..44ce1a93e 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -273,10 +273,10 @@ bool fromwire_channeld_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNE bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *counter UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct wireaddr **remote_addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED, wirestring **connect_reason UNNEEDED, u64 *connect_nsec UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_connected called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_disconnected */ -bool fromwire_connectd_peer_disconnected(const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *counter UNNEEDED) +bool fromwire_connectd_peer_disconnected(const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *counter UNNEEDED, u64 *connect_time_nsec UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_disconnected called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_reconnected */ -bool fromwire_connectd_peer_reconnected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *prev_counter UNNEEDED, u64 *counter UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct wireaddr **remote_addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED) +bool fromwire_connectd_peer_reconnected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *prev_counter UNNEEDED, u64 *counter UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct wireaddr **remote_addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED, u64 *connect_time_nsec UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_reconnected called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_spoke */ bool fromwire_connectd_peer_spoke(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *counter UNNEEDED, u16 *msgtype UNNEEDED, struct channel_id *channel_id UNNEEDED, wirestring **error UNNEEDED) diff --git a/tests/fuzz/connectd_handshake.h b/tests/fuzz/connectd_handshake.h index 6216e2359..139ee25d4 100644 --- a/tests/fuzz/connectd_handshake.h +++ b/tests/fuzz/connectd_handshake.h @@ -147,6 +147,7 @@ static struct io_plan * success(struct io_conn *conn UNUSED, const struct pubkey *them UNUSED, const struct wireaddr_internal *addr UNUSED, struct crypto_state *cs, struct oneshot *timeout UNUSED, enum is_websocket is_websocket UNUSED, + struct timemono starttime UNUSED, void *unused UNUSED) { assert(false && "handshake unexpectedly succeeded"); diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 54f0a3858..45609a6b5 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -302,10 +302,10 @@ bool fromwire_channeld_sending_commitsig(const tal_t *ctx UNNEEDED, const void * bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *counter UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct wireaddr **remote_addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED, wirestring **connect_reason UNNEEDED, u64 *connect_nsec UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_connected called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_disconnected */ -bool fromwire_connectd_peer_disconnected(const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *counter UNNEEDED) +bool fromwire_connectd_peer_disconnected(const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *counter UNNEEDED, u64 *connect_time_nsec UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_disconnected called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_reconnected */ -bool fromwire_connectd_peer_reconnected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *prev_counter UNNEEDED, u64 *counter UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct wireaddr **remote_addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED) +bool fromwire_connectd_peer_reconnected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *prev_counter UNNEEDED, u64 *counter UNNEEDED, struct wireaddr_internal *addr UNNEEDED, struct wireaddr **remote_addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED, u64 *connect_time_nsec UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_reconnected called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_spoke */ bool fromwire_connectd_peer_spoke(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u64 *counter UNNEEDED, u16 *msgtype UNNEEDED, struct channel_id *channel_id UNNEEDED, wirestring **error UNNEEDED)