From 31d44575ba1627749311396501c54aab2b466132 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:25:54 +1030 Subject: [PATCH 01/51] lightningd: close one more fd for subdaemons. Noticed by stracing for an unrelated problem. Signed-off-by: Rusty Russell --- lightningd/subd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lightningd/subd.c b/lightningd/subd.c index ee9d0d79d4b9..bebd5adc1282 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -241,7 +241,7 @@ static int subd(const char *path, const char *name, goto child_errno_fail; /* Make (fairly!) sure all other fds are closed. */ - closefrom(tal_count(fds) + 1); + closefrom(tal_count(fds)); num_args = 0; args[num_args++] = tal_strdup(NULL, path); From b7268b3e1f3f7f1df6364231382fe51630e939ec Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:26:54 +1030 Subject: [PATCH 02/51] lightningd: handle channel cleanups more explicitly. 1. Freeing an unconfirmed channel already releases the subd, so don't do that explicitly. 2. Use channel->owner to transfer ownership where possible, using channel_set_owner() which handles all the cases. This simplifies the code and makes it more readable, IMHO. Signed-off-by: Rusty Russell --- lightningd/channel.c | 2 +- lightningd/opening_common.c | 9 +++------ lightningd/opening_control.c | 10 ++-------- lightningd/subd.c | 2 +- lightningd/subd.h | 5 +++-- wallet/test/run-wallet.c | 2 +- 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index 617b89ad9589..7dd36581458d 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -824,7 +824,7 @@ void channel_internal_error(struct channel *channel, const char *fmt, ...) channel_cleanup_commands(channel, why); if (channel_unsaved(channel)) { - subd_release_channel(channel->owner, channel); + channel_set_owner(channel, NULL); delete_channel(channel); tal_free(why); return; diff --git a/lightningd/opening_common.c b/lightningd/opening_common.c index 635aaeef5975..0b02b41d5de7 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -17,8 +17,9 @@ static void destroy_uncommitted_channel(struct uncommitted_channel *uc) { - if (uc->open_daemon) { - struct subd *open_daemon= uc->open_daemon; + struct subd *open_daemon = uc->open_daemon; + + if (open_daemon) { uc->open_daemon = NULL; subd_release_channel(open_daemon, uc); } @@ -115,10 +116,6 @@ void kill_uncommitted_channel(struct uncommitted_channel *uc, { log_info(uc->log, "Killing opening daemon: %s", why); - /* Close opend daemon. */ - subd_release_channel(uc->open_daemon, uc); - uc->open_daemon = NULL; - uncommitted_channel_disconnect(uc, LOG_INFORM, why); tal_free(uc); } diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index dd378219f90c..9e78a6963766 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -319,9 +319,7 @@ static void opening_funder_start_replied(struct subd *openingd, const u8 *resp, return; failed: - subd_release_channel(openingd, fc->uc); - fc->uc->open_daemon = NULL; - /* Frees fc too, and tmpctx */ + /* Frees fc too */ tal_free(fc->uc); } @@ -414,9 +412,7 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, peer_start_channeld(channel, pps, NULL, false, NULL); cleanup: - subd_release_channel(openingd, fc->uc); - fc->uc->open_daemon = NULL; - /* Frees fc too, and tmpctx */ + /* Frees fc too */ tal_free(fc->uc); } @@ -528,8 +524,6 @@ static void opening_fundee_finished(struct subd *openingd, /* On to normal operation! */ peer_start_channeld(channel, pps, fwd_msg, false, NULL); - subd_release_channel(openingd, uc); - uc->open_daemon = NULL; tal_free(uc); return; diff --git a/lightningd/subd.c b/lightningd/subd.c index bebd5adc1282..a42849b48805 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -888,7 +888,7 @@ struct subd *subd_shutdown(struct subd *sd, unsigned int seconds) return tal_free(sd); } -void subd_release_channel(struct subd *owner, void *channel) +void subd_release_channel(struct subd *owner, const void *channel) { /* If owner is a per-peer-daemon, and not already freeing itself... */ if (owner->channel) { diff --git a/lightningd/subd.h b/lightningd/subd.h index 94fabf9e3a32..73b9534bda2b 100644 --- a/lightningd/subd.h +++ b/lightningd/subd.h @@ -197,9 +197,10 @@ void subd_req_(const tal_t *ctx, * @channel: channel to release. * * If the subdaemon is not already shutting down, and it is a per-channel - * subdaemon, this shuts it down. + * subdaemon, this shuts it down. Don't call this directly, use + * channel_set_owner() or uncommitted_channel_release_subd(). */ -void subd_release_channel(struct subd *owner, void *channel); +void subd_release_channel(struct subd *owner, const void *channel); /** * subd_shutdown - try to politely shut down a subdaemon. diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 2d65f6e7f0ed..e961f515d1f2 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -655,7 +655,7 @@ u8 *serialize_onionpacket( const struct onionpacket *packet UNNEEDED) { fprintf(stderr, "serialize_onionpacket called!\n"); abort(); } /* Generated stub for subd_release_channel */ -void subd_release_channel(struct subd *owner UNNEEDED, void *channel UNNEEDED) +void subd_release_channel(struct subd *owner UNNEEDED, const void *channel UNNEEDED) { fprintf(stderr, "subd_release_channel called!\n"); abort(); } /* Generated stub for subd_req_ */ void subd_req_(const tal_t *ctx UNNEEDED, From 23e0c9e1a3d6ecc7b3298a820a7d59e5b162239b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:27:54 +1030 Subject: [PATCH 03/51] common: is_msg_gossip_broadcast() for putting things in filter. We don't need the other "gossip" messages in our echo-suppression filter. Signed-off-by: Rusty Russell --- common/read_peer_msg.c | 3 ++- wire/peer_wire.c | 54 ++++++++++++++++++++++++++++++++++++++++++ wire/peer_wire.h | 2 ++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/common/read_peer_msg.c b/common/read_peer_msg.c index 7fc4b0f05f5b..dc58c4a8c5e8 100644 --- a/common/read_peer_msg.c +++ b/common/read_peer_msg.c @@ -181,7 +181,8 @@ bool handle_peer_gossip_or_error(struct per_peer_state *pps, sync_crypto_write(pps, take(pong)); return true; } else if (is_msg_for_gossipd(msg)) { - gossip_rcvd_filter_add(pps->grf, msg); + if (is_msg_gossip_broadcast(msg)) + gossip_rcvd_filter_add(pps->grf, msg); wire_sync_write(pps->gossip_fd, msg); /* wire_sync_write takes, so don't take again. */ return true; diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 340085d282cc..33156f8be6c1 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -108,6 +108,60 @@ bool is_msg_for_gossipd(const u8 *cursor) return false; } +bool is_msg_gossip_broadcast(const u8 *cursor) +{ + switch ((enum peer_wire)fromwire_peektype(cursor)) { + case WIRE_CHANNEL_ANNOUNCEMENT: + case WIRE_NODE_ANNOUNCEMENT: + case WIRE_CHANNEL_UPDATE: + return true; + case WIRE_QUERY_SHORT_CHANNEL_IDS: + case WIRE_REPLY_SHORT_CHANNEL_IDS_END: + case WIRE_QUERY_CHANNEL_RANGE: + case WIRE_REPLY_CHANNEL_RANGE: + case WIRE_ONION_MESSAGE: + case WIRE_OBS2_ONION_MESSAGE: + case WIRE_WARNING: + case WIRE_INIT: + case WIRE_PING: + case WIRE_PONG: + case WIRE_ERROR: + case WIRE_OPEN_CHANNEL: + case WIRE_ACCEPT_CHANNEL: + case WIRE_FUNDING_CREATED: + case WIRE_FUNDING_SIGNED: + case WIRE_FUNDING_LOCKED: + case WIRE_SHUTDOWN: + case WIRE_CLOSING_SIGNED: + case WIRE_UPDATE_ADD_HTLC: + case WIRE_UPDATE_FULFILL_HTLC: + case WIRE_UPDATE_FAIL_HTLC: + case WIRE_UPDATE_FAIL_MALFORMED_HTLC: + case WIRE_COMMITMENT_SIGNED: + case WIRE_REVOKE_AND_ACK: + case WIRE_UPDATE_FEE: + case WIRE_UPDATE_BLOCKHEIGHT: + case WIRE_CHANNEL_REESTABLISH: + case WIRE_ANNOUNCEMENT_SIGNATURES: + case WIRE_GOSSIP_TIMESTAMP_FILTER: + case WIRE_TX_ADD_INPUT: + case WIRE_TX_REMOVE_INPUT: + case WIRE_TX_ADD_OUTPUT: + case WIRE_TX_REMOVE_OUTPUT: + case WIRE_TX_COMPLETE: + case WIRE_TX_SIGNATURES: + case WIRE_OPEN_CHANNEL2: + case WIRE_ACCEPT_CHANNEL2: + case WIRE_INIT_RBF: + case WIRE_ACK_RBF: +#if EXPERIMENTAL_FEATURES + case WIRE_STFU: +#endif + break; + } + return false; +} + /* Return true if it's an unknown ODD message. cursor is a tal ptr. */ bool is_unknown_msg_discardable(const u8 *cursor) { diff --git a/wire/peer_wire.h b/wire/peer_wire.h index 12c951b8ff3e..d57a84d20bd7 100644 --- a/wire/peer_wire.h +++ b/wire/peer_wire.h @@ -23,6 +23,8 @@ bool is_unknown_msg_discardable(const u8 *cursor); /* Return true if it's a message for gossipd. */ bool is_msg_for_gossipd(const u8 *cursor); +/* Return true if it's a gossip update or announcement. */ +bool is_msg_gossip_broadcast(const u8 *cursor); /* Extract channel_id from various packets, return true if possible. */ bool extract_channel_id(const u8 *in_pkt, struct channel_id *channel_id); From 3bf0a20ab17bf982f7ac0e328950daff78da4c30 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:28:54 +1030 Subject: [PATCH 04/51] connectd: clean up lightningd connection handling. They all returned the same thing anyway. Signed-off-by: Rusty Russell --- connectd/connectd.c | 56 +++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index e855552f9c74..12adfdc97310 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1537,9 +1537,7 @@ static struct wireaddr_internal *setup_listeners(const tal_t *ctx, /*~ Parse the incoming connect init message from lightningd ("master") and * assign config variables to the daemon; it should be the first message we * get. */ -static struct io_plan *connect_init(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void connect_init(struct daemon *daemon, const u8 *msg) { struct wireaddr *proxyaddr; struct wireaddr_internal *binding; @@ -1606,15 +1604,10 @@ static struct io_plan *connect_init(struct io_conn *conn, take(towire_connectd_init_reply(NULL, binding, announcable))); - - /* Read the next message. */ - return daemon_conn_read_next(conn, daemon->master); } /*~ lightningd tells us to go! */ -static struct io_plan *connect_activate(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void connect_activate(struct daemon *daemon, const u8 *msg) { bool do_listen; @@ -1645,7 +1638,6 @@ static struct io_plan *connect_activate(struct io_conn *conn, /* OK, we're ready! */ daemon_conn_send(daemon->master, take(towire_connectd_activate_reply(NULL))); - return daemon_conn_read_next(conn, daemon->master); } /* BOLT #10: @@ -1861,8 +1853,7 @@ static void try_connect_peer(struct daemon *daemon, } /* lightningd tells us to connect to a peer by id, with optional addr hint. */ -static struct io_plan *connect_to_peer(struct io_conn *conn, - struct daemon *daemon, const u8 *msg) +static void connect_to_peer(struct daemon *daemon, const u8 *msg) { struct node_id id; u32 seconds_waited; @@ -1874,7 +1865,6 @@ static struct io_plan *connect_to_peer(struct io_conn *conn, master_badmsg(WIRE_CONNECTD_CONNECT_TO_PEER, msg); try_connect_peer(daemon, &id, seconds_waited, addrhint); - return daemon_conn_read_next(conn, daemon->master); } /* A peer is gone: clean things up. */ @@ -1900,8 +1890,7 @@ static void cleanup_dead_peer(struct daemon *daemon, const struct node_id *id) } /* lightningd tells us a peer has disconnected. */ -static struct io_plan *peer_disconnected(struct io_conn *conn, - struct daemon *daemon, const u8 *msg) +static void peer_disconnected(struct daemon *daemon, const u8 *msg) { struct node_id id; @@ -1909,9 +1898,6 @@ static struct io_plan *peer_disconnected(struct io_conn *conn, master_badmsg(WIRE_CONNECTD_PEER_DISCONNECTED, msg); cleanup_dead_peer(daemon, &id); - - /* Read the next message from lightningd. */ - return daemon_conn_read_next(conn, daemon->master); } /* lightningd tells us to send a final (usually error) message to peer, then @@ -1932,8 +1918,8 @@ static struct io_plan *send_final_msg(struct io_conn *conn, u8 *msg) } /* lightningd tells us to send a msg and disconnect. */ -static struct io_plan *peer_final_msg(struct io_conn *conn, - struct daemon *daemon, const u8 *msg) +static void peer_final_msg(struct io_conn *conn, + struct daemon *daemon, const u8 *msg) { struct per_peer_state *pps; struct final_msg_data *f = tal(NULL, struct final_msg_data); @@ -1969,15 +1955,10 @@ static struct io_plan *peer_final_msg(struct io_conn *conn, /* Organize io loop to write out that message, it will free f * once closed */ tal_steal(io_new_conn(daemon, fds[0], send_final_msg, finalmsg), f); - - /* Read the next message from lightningd. */ - return daemon_conn_read_next(conn, daemon->master); } #if DEVELOPER -static struct io_plan *dev_connect_memleak(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void dev_connect_memleak(struct daemon *daemon, const u8 *msg) { struct htable *memtable; bool found_leak; @@ -1991,7 +1972,6 @@ static struct io_plan *dev_connect_memleak(struct io_conn *conn, daemon_conn_send(daemon->master, take(towire_connectd_dev_memleak_reply(NULL, found_leak))); - return daemon_conn_read_next(conn, daemon->master); } #endif /* DEVELOPER */ @@ -2005,23 +1985,29 @@ static struct io_plan *recv_req(struct io_conn *conn, * connect requests and disconnected messages. */ switch (t) { case WIRE_CONNECTD_INIT: - return connect_init(conn, daemon, msg); + connect_init(daemon, msg); + goto out; case WIRE_CONNECTD_ACTIVATE: - return connect_activate(conn, daemon, msg); + connect_activate(daemon, msg); + goto out; case WIRE_CONNECTD_CONNECT_TO_PEER: - return connect_to_peer(conn, daemon, msg); + connect_to_peer(daemon, msg); + goto out; case WIRE_CONNECTD_PEER_DISCONNECTED: - return peer_disconnected(conn, daemon, msg); + peer_disconnected(daemon, msg); + goto out; case WIRE_CONNECTD_PEER_FINAL_MSG: - return peer_final_msg(conn, daemon, msg); + peer_final_msg(conn, daemon, msg); + goto out; case WIRE_CONNECTD_DEV_MEMLEAK: #if DEVELOPER - return dev_connect_memleak(conn, daemon, msg); + dev_connect_memleak(daemon, msg); + goto out; #endif /* We send these, we don't receive them */ case WIRE_CONNECTD_INIT_REPLY: @@ -2036,6 +2022,10 @@ static struct io_plan *recv_req(struct io_conn *conn, /* Master shouldn't give bad requests. */ status_failed(STATUS_FAIL_MASTER_IO, "%i: %s", t, tal_hex(tmpctx, msg)); + +out: + /* Read the next message. */ + return daemon_conn_read_next(conn, daemon->master); } /*~ UNUSED is defined to an __attribute__ for GCC; at one stage we tried to use From 0fd02f710900debfba95f5afadee4840b61e7a29 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:29:54 +1030 Subject: [PATCH 05/51] common: generalize extract_channel_id(). connectd is going to end up using this do demux; make it fast and complete. Fixing this reveals a problem in openingd: it now extracts the channel_id from funding_signed (which is where we transition off the temporary), and gets upset. So fix that. Signed-off-by: Rusty Russell --- channeld/test/run-commit_tx.c | 2 +- cli/test/run-human-mode.c | 2 +- cli/test/run-large-input.c | 2 +- cli/test/run-remove-hint.c | 2 +- common/channel_id.c | 4 +- common/channel_id.h | 2 +- common/read_peer_msg.c | 3 + common/test/run-blindedpath_enctlv.c | 2 +- common/test/run-blindedpath_onion.c | 2 +- common/test/run-bolt12_merkle-json.c | 2 +- common/test/run-bolt12_merkle.c | 2 +- common/test/run-gossmap_local.c | 2 +- common/test/run-route-specific.c | 2 +- common/test/run-route.c | 2 +- .../test/run-route_blinding_override_test.c | 2 +- common/test/run-route_blinding_test.c | 2 +- lightningd/test/run-find_my_abspath.c | 2 +- lightningd/test/run-invoice-select-inchan.c | 2 +- lightningd/test/run-jsonrpc.c | 2 +- lightningd/test/run-log-pruning.c | 2 +- lightningd/test/run-shuffle_fds.c | 2 +- openingd/openingd.c | 16 +- plugins/test/run-funder_policy.c | 2 +- plugins/test/run-route-overlong.c | 2 +- wire/peer_wire.c | 257 ++++++++++++++++-- wire/test/run-tlvstream.c | 2 +- 26 files changed, 264 insertions(+), 60 deletions(-) diff --git a/channeld/test/run-commit_tx.c b/channeld/test/run-commit_tx.c index 7610fbd9a3b7..f222e7ae3d59 100644 --- a/channeld/test/run-commit_tx.c +++ b/channeld/test/run-commit_tx.c @@ -24,7 +24,7 @@ static bool print_superverbose; bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/cli/test/run-human-mode.c b/cli/test/run-human-mode.c index a3a122b1d0e8..bf7c4a25f82a 100644 --- a/cli/test/run-human-mode.c +++ b/cli/test/run-human-mode.c @@ -70,7 +70,7 @@ struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UN bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/cli/test/run-large-input.c b/cli/test/run-large-input.c index 7bb64233326b..40c8d67f91e9 100644 --- a/cli/test/run-large-input.c +++ b/cli/test/run-large-input.c @@ -70,7 +70,7 @@ struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UN bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/cli/test/run-remove-hint.c b/cli/test/run-remove-hint.c index 3311a9aec7d3..18e21e490e45 100644 --- a/cli/test/run-remove-hint.c +++ b/cli/test/run-remove-hint.c @@ -73,7 +73,7 @@ struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UN bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/common/channel_id.c b/common/channel_id.c index 517427b7469c..c2f4ce6e04dc 100644 --- a/common/channel_id.c +++ b/common/channel_id.c @@ -88,10 +88,10 @@ void towire_channel_id(u8 **pptr, const struct channel_id *channel_id) towire(pptr, channel_id, sizeof(*channel_id)); } -void fromwire_channel_id(const u8 **cursor, size_t *max, +bool fromwire_channel_id(const u8 **cursor, size_t *max, struct channel_id *channel_id) { - fromwire(cursor, max, channel_id, sizeof(*channel_id)); + return fromwire(cursor, max, channel_id, sizeof(*channel_id)) != NULL; } REGISTER_TYPE_TO_HEXSTR(channel_id); diff --git a/common/channel_id.h b/common/channel_id.h index 81b6ef0248ea..d6ce8687aaf7 100644 --- a/common/channel_id.h +++ b/common/channel_id.h @@ -38,6 +38,6 @@ void derive_tmp_channel_id(struct channel_id *channel_id, /* Marshalling/unmarshalling functions */ void towire_channel_id(u8 **pptr, const struct channel_id *channel_id); -void fromwire_channel_id(const u8 **cursor, size_t *max, +bool fromwire_channel_id(const u8 **cursor, size_t *max, struct channel_id *channel_id); #endif /* LIGHTNING_COMMON_CHANNEL_ID_H */ diff --git a/common/read_peer_msg.c b/common/read_peer_msg.c index dc58c4a8c5e8..f40c15c46829 100644 --- a/common/read_peer_msg.c +++ b/common/read_peer_msg.c @@ -103,6 +103,9 @@ bool is_peer_error(const tal_t *ctx, const u8 *msg, bool is_wrong_channel(const u8 *msg, const struct channel_id *expected, struct channel_id *actual) { + if (!expected) + return false; + if (!extract_channel_id(msg, actual)) return false; diff --git a/common/test/run-blindedpath_enctlv.c b/common/test/run-blindedpath_enctlv.c index a1d32e5a3af3..9c619b7b3fd9 100644 --- a/common/test/run-blindedpath_enctlv.c +++ b/common/test/run-blindedpath_enctlv.c @@ -50,7 +50,7 @@ struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_amount_sat called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/common/test/run-blindedpath_onion.c b/common/test/run-blindedpath_onion.c index 191e157af697..4b51804ea175 100644 --- a/common/test/run-blindedpath_onion.c +++ b/common/test/run-blindedpath_onion.c @@ -56,7 +56,7 @@ struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_amount_sat called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/common/test/run-bolt12_merkle-json.c b/common/test/run-bolt12_merkle-json.c index eb62379cbc7c..ebdd325d5886 100644 --- a/common/test/run-bolt12_merkle-json.c +++ b/common/test/run-bolt12_merkle-json.c @@ -19,7 +19,7 @@ /* AUTOGENERATED MOCKS START */ /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/common/test/run-bolt12_merkle.c b/common/test/run-bolt12_merkle.c index 1610e3ea8737..83abb27d133a 100644 --- a/common/test/run-bolt12_merkle.c +++ b/common/test/run-bolt12_merkle.c @@ -22,7 +22,7 @@ int features_unsupported(const struct feature_set *our_features UNNEEDED, enum feature_place p UNNEEDED) { fprintf(stderr, "features_unsupported called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_onionmsg_path */ diff --git a/common/test/run-gossmap_local.c b/common/test/run-gossmap_local.c index 605c2cb8d54b..1d8d19cc9cf0 100644 --- a/common/test/run-gossmap_local.c +++ b/common/test/run-gossmap_local.c @@ -16,7 +16,7 @@ bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for towire_bigsize */ diff --git a/common/test/run-route-specific.c b/common/test/run-route-specific.c index e58ef4689afc..a591f16cd5bb 100644 --- a/common/test/run-route-specific.c +++ b/common/test/run-route-specific.c @@ -25,7 +25,7 @@ bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_tlv */ diff --git a/common/test/run-route.c b/common/test/run-route.c index e1fac36ebfe4..ad6fadc8e60e 100644 --- a/common/test/run-route.c +++ b/common/test/run-route.c @@ -18,7 +18,7 @@ bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_tlv */ diff --git a/common/test/run-route_blinding_override_test.c b/common/test/run-route_blinding_override_test.c index 5025c8ff7d2f..b8e2552cb5f2 100644 --- a/common/test/run-route_blinding_override_test.c +++ b/common/test/run-route_blinding_override_test.c @@ -63,7 +63,7 @@ struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_amount_sat called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/common/test/run-route_blinding_test.c b/common/test/run-route_blinding_test.c index d9f141839536..22076d9568b7 100644 --- a/common/test/run-route_blinding_test.c +++ b/common/test/run-route_blinding_test.c @@ -63,7 +63,7 @@ struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_amount_sat called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index 24e53c97abad..55d198f68038 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -76,7 +76,7 @@ void free_htlcs(struct lightningd *ld UNNEEDED, const struct channel *channel UN bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 242b8b689de5..0b241ac71fda 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -203,7 +203,7 @@ void fixup_htlcs_out(struct lightningd *ld UNNEEDED) bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_channeld_dev_memleak_reply */ diff --git a/lightningd/test/run-jsonrpc.c b/lightningd/test/run-jsonrpc.c index 1479612d1138..01806dadf442 100644 --- a/lightningd/test/run-jsonrpc.c +++ b/lightningd/test/run-jsonrpc.c @@ -22,7 +22,7 @@ const char *feerate_name(enum feerate feerate UNNEEDED) bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/lightningd/test/run-log-pruning.c b/lightningd/test/run-log-pruning.c index 6bda5f337c18..3db0a81dc676 100644 --- a/lightningd/test/run-log-pruning.c +++ b/lightningd/test/run-log-pruning.c @@ -21,7 +21,7 @@ struct command_result *command_success(struct command *cmd UNNEEDED, bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/lightningd/test/run-shuffle_fds.c b/lightningd/test/run-shuffle_fds.c index 7f9a3806036c..c2a00d667439 100644 --- a/lightningd/test/run-shuffle_fds.c +++ b/lightningd/test/run-shuffle_fds.c @@ -57,7 +57,7 @@ void fatal(const char *fmt UNNEEDED, ...) bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/openingd/openingd.c b/openingd/openingd.c index 54f4be8462d9..fede6c8119d6 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -177,7 +177,8 @@ static void set_reserve(struct state *state, const struct amount_sat dust_limit) /*~ Handle random messages we might get during opening negotiation, (eg. gossip) * returning the first non-handled one, or NULL if we aborted negotiation. */ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, - bool am_opener) + bool am_opener, + const struct channel_id *alternate) { /* This is an event loop of its own. That's generally considered poor * form, but we use it in a very limited way. */ @@ -250,7 +251,8 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, * keeps things simple: if we wanted to change this, we would * probably be best with another daemon to de-multiplex them; * this could be connectd itself, in fact. */ - if (is_wrong_channel(msg, &state->channel_id, &actual)) { + if (is_wrong_channel(msg, &state->channel_id, &actual) + && is_wrong_channel(msg, alternate, &actual)) { status_debug("Rejecting %s for unknown channel_id %s", peer_wire_name(fromwire_peektype(msg)), type_to_string(tmpctx, struct channel_id, @@ -401,7 +403,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) "Funding channel start: offered, now waiting for accept_channel"); /* ... since their reply should be immediate. */ - msg = opening_negotiate_msg(tmpctx, state, true); + msg = opening_negotiate_msg(tmpctx, state, true, NULL); if (!msg) return NULL; @@ -652,8 +654,10 @@ static bool funder_finalize_channel_setup(struct state *state, "Funding channel: create first tx, now waiting for their signature"); /* Now they send us their signature for that first commitment - * transaction. */ - msg = opening_negotiate_msg(tmpctx, state, true); + * transaction. Note that errors may refer to the temporary channel + * id (state->channel_id), but success should refer to the new + * "cid" */ + msg = opening_negotiate_msg(tmpctx, state, true, &cid); if (!msg) goto fail; @@ -1052,7 +1056,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) "Incoming channel: accepted, now waiting for them to create funding tx"); /* This is a loop which handles gossip until we get a non-gossip msg */ - msg = opening_negotiate_msg(tmpctx, state, false); + msg = opening_negotiate_msg(tmpctx, state, false, NULL); if (!msg) return NULL; diff --git a/plugins/test/run-funder_policy.c b/plugins/test/run-funder_policy.c index 8efb543e5958..a91a5867615e 100644 --- a/plugins/test/run-funder_policy.c +++ b/plugins/test/run-funder_policy.c @@ -9,7 +9,7 @@ bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for fromwire_node_id */ diff --git a/plugins/test/run-route-overlong.c b/plugins/test/run-route-overlong.c index 3999a31cfe87..2ca73fd9452e 100644 --- a/plugins/test/run-route-overlong.c +++ b/plugins/test/run-route-overlong.c @@ -21,7 +21,7 @@ bool feature_offered(const u8 *features UNNEEDED, size_t f UNNEEDED) bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for json_add_amount_msat_compat */ diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 33156f8be6c1..1ed291db5c35 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -1,4 +1,5 @@ #include "config.h" +#include #include static bool unknown_type(enum peer_wire t) @@ -172,38 +173,234 @@ bool is_unknown_msg_discardable(const u8 *cursor) /* Extract channel_id from various packets, return true if possible. */ bool extract_channel_id(const u8 *in_pkt, struct channel_id *channel_id) { - struct amount_sat ignored_sat; - struct amount_msat ignored_msat; - u64 ignored_u64; - u32 ignored_u32; - u16 ignored_u16; - u8 ignored_u8; - struct pubkey ignored_pubkey; - struct bitcoin_blkid ignored_chainhash; - struct secret ignored_secret; - struct tlv_open_channel_tlvs *tlvs = tlv_open_channel_tlvs_new(tmpctx); -#if EXPERIMENTAL_FEATURES - struct tlv_channel_reestablish_tlvs *reestab_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); -#endif + const u8 *cursor = in_pkt; + size_t max = tal_bytelen(in_pkt); + enum peer_wire t; + + t = fromwire_u16(&cursor, &max); + + /* We carefully quote bolts here, in case anything changes! */ + switch (t) { + /* These ones don't have a channel_id */ + case WIRE_INIT: + case WIRE_PING: + case WIRE_PONG: + case WIRE_CHANNEL_ANNOUNCEMENT: + case WIRE_NODE_ANNOUNCEMENT: + case WIRE_CHANNEL_UPDATE: + case WIRE_QUERY_SHORT_CHANNEL_IDS: + case WIRE_REPLY_SHORT_CHANNEL_IDS_END: + case WIRE_QUERY_CHANNEL_RANGE: + case WIRE_REPLY_CHANNEL_RANGE: + case WIRE_GOSSIP_TIMESTAMP_FILTER: + case WIRE_OBS2_ONION_MESSAGE: + case WIRE_ONION_MESSAGE: + return false; + + /* Special cases: */ + case WIRE_ERROR: + /* BOLT #1: + * 1. type: 17 (`error`) + * 2. data: + * * [`channel_id`:`channel_id`] + *... + * The channel is referred to by `channel_id`, unless + * `channel_id` is 0 + */ + /* fall thru */ + case WIRE_WARNING: + /* BOLT-warning #1: + * 1. type: 1 (`warning`) + * 2. data: + * * [`channel_id`:`channel_id`] + *... + * The channel is referred to by `channel_id`, unless + * `channel_id` is 0 + */ + if (!fromwire_channel_id(&cursor, &max, channel_id)) + return false; + if (memeqzero(channel_id->id, sizeof(channel_id->id))) + return false; + return true; - if (fromwire_channel_reestablish(in_pkt, channel_id, - &ignored_u64, &ignored_u64, - &ignored_secret, &ignored_pubkey + case WIRE_OPEN_CHANNEL: + /* BOLT #2: + * 1. type: 32 (`open_channel`) + * 2. data: + * * [`chain_hash`:`chain_hash`] + * * [`32*byte`:`temporary_channel_id`] + */ + case WIRE_OPEN_CHANNEL2: + /* BOLT-dualfund #2: + * 1. type: 64 (`open_channel2`) + * 2. data: + * * [`chain_hash`:`chain_hash`] + * * [`channel_id`:`zerod_channel_id`] + */ + + /* Skip over chain_hash */ + fromwire_pad(&cursor, &max, sizeof(struct bitcoin_blkid)); + + /* These have them at the start */ + case WIRE_TX_ADD_INPUT: + /* BOLT-dualfund #2: + * 1. type: 66 (`tx_add_input`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_TX_ADD_OUTPUT: + /* BOLT-dualfund #2: + * 1. type: 67 (`tx_add_output`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_TX_REMOVE_INPUT: + /* BOLT-dualfund #2: + * 1. type: 68 (`tx_remove_input`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_TX_REMOVE_OUTPUT: + /* BOLT-dualfund #2: + * 1. type: 69 (`tx_remove_output`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_TX_COMPLETE: + /* BOLT-dualfund #2: + * 1. type: 70 (`tx_complete`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_TX_SIGNATURES: + /* BOLT-dualfund #2: + * 1. type: 71 (`tx_signatures`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_ACCEPT_CHANNEL: + /* BOLT #2: + * 1. type: 33 (`accept_channel`) + * 2. data: + * * [`32*byte`:`temporary_channel_id`] + */ + case WIRE_FUNDING_CREATED: + /* BOLT #2: + * 1. type: 34 (`funding_created`) + * 2. data: + * * [`32*byte`:`temporary_channel_id`] + */ + case WIRE_FUNDING_SIGNED: + /* BOLT #2: + * 1. type: 35 (`funding_signed`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_FUNDING_LOCKED: + /* BOLT #2: + * 1. type: 36 (`funding_locked`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_ACCEPT_CHANNEL2: + /* BOLT-dualfund #2: + * 1. type: 65 (`accept_channel2`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_INIT_RBF: + /* BOLT-dualfund #2: + * 1. type: 72 (`init_rbf`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_ACK_RBF: + /* BOLT-dualfund #2: + * 1. type: 73 (`ack_rbf`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_SHUTDOWN: + /* BOLT #2: + * 1. type: 38 (`shutdown`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_CLOSING_SIGNED: + /* BOLT #2: + * 1. type: 39 (`closing_signed`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_UPDATE_ADD_HTLC: + /* BOLT #2: + * 1. type: 128 (`update_add_htlc`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_UPDATE_FULFILL_HTLC: + /* BOLT #2: + * 1. type: 130 (`update_fulfill_htlc`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_UPDATE_FAIL_HTLC: + /* BOLT #2: + * 1. type: 131 (`update_fail_htlc`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_UPDATE_FAIL_MALFORMED_HTLC: + /* BOLT #2: + * 1. type: 135 (`update_fail_malformed_htlc`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_COMMITMENT_SIGNED: + /* BOLT #2: + * 1. type: 132 (`commitment_signed`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_REVOKE_AND_ACK: + /* BOLT #2: + * 1. type: 133 (`revoke_and_ack`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_UPDATE_FEE: + /* BOLT #2: + * 1. type: 134 (`update_fee`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_UPDATE_BLOCKHEIGHT: + /* BOLT-liquidity-ads #2: + * 1. type: 137 (`update_blockheight`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_CHANNEL_REESTABLISH: + /* BOLT #2: + * 1. type: 136 (`channel_reestablish`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ + case WIRE_ANNOUNCEMENT_SIGNATURES: + /* BOLT #7: + * 1. type: 259 (`announcement_signatures`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ #if EXPERIMENTAL_FEATURES - , reestab_tlvs + case WIRE_STFU: + /* BOLT-quiescent #2: + * 1. type: 2 (`stfu`) + * 2. data: + * * [`channel_id`:`channel_id`] + */ #endif - )) - return true; - if (fromwire_open_channel(in_pkt, &ignored_chainhash, - channel_id, &ignored_sat, - &ignored_msat, &ignored_sat, - &ignored_msat, &ignored_sat, - &ignored_msat, &ignored_u32, - &ignored_u16, &ignored_u16, - &ignored_pubkey, &ignored_pubkey, - &ignored_pubkey, &ignored_pubkey, - &ignored_pubkey, &ignored_pubkey, - &ignored_u8, tlvs)) - return true; + return fromwire_channel_id(&cursor, &max, channel_id); + } return false; } diff --git a/wire/test/run-tlvstream.c b/wire/test/run-tlvstream.c index b658d85f89d9..76b27b61252e 100644 --- a/wire/test/run-tlvstream.c +++ b/wire/test/run-tlvstream.c @@ -26,7 +26,7 @@ static const char *reason; const struct chainparams *chainparams_by_chainhash(const struct bitcoin_blkid *chain_hash UNNEEDED) { fprintf(stderr, "chainparams_by_chainhash called!\n"); abort(); } /* Generated stub for fromwire_channel_id */ -void fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, +bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "fromwire_channel_id called!\n"); abort(); } /* Generated stub for towire_channel_id */ From bb635a06bb4ece3e4bb3c10967b0128228a486b8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:30:54 +1030 Subject: [PATCH 06/51] common/socket_close: don't wait forever. The "read until closed" trick doesn't work if the other end doesn't close (as found in the next patch, where we use DEV_DISCONNECT_DISABLE_AFTER). Signed-off-by: Rusty Russell --- common/socket_close.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/common/socket_close.c b/common/socket_close.c index 3c192e47e38d..7d19ec76814b 100644 --- a/common/socket_close.c +++ b/common/socket_close.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include @@ -18,9 +20,15 @@ Simplified (minus all the error checks): close(fd); */ +/* makes read() return EINTR */ +static void break_read(int signum) +{ +} + bool socket_close(int fd) { char unused[64]; + struct sigaction act, old_act; int sys_res; sys_res = shutdown(fd, SHUT_WR); @@ -29,20 +37,22 @@ bool socket_close(int fd) return false; } - for (;;) { - do { - sys_res = read(fd, unused, sizeof(unused)); - } while (sys_res < 0 && errno == EINTR); - if (sys_res < 0) { - close_noerr(fd); - return false; - } - if (sys_res == 0) - break; - } + /* Let's not get too enthusiastic about waiting. */ + memset(&act, 0, sizeof(act)); + act.sa_handler = break_read; + sigaction(SIGALRM, &act, &old_act); - if (close(fd) < 0) + alarm(5); + + while ((sys_res = read(fd, unused, sizeof(unused))) > 0); + + alarm(0); + sigaction(SIGALRM, &old_act, NULL); + + if (sys_res < 0) { + close_noerr(fd); return false; - else - return true; + } + + return close(fd) == 0; } From 99c08f358c2ae0647342cde18b0d691572acd54b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:31:54 +1030 Subject: [PATCH 07/51] pytest: disable dev-disconnect blackhole tests. These would have to be done by connectd, not the local daemon, once it's intermediating. Otherwise the remote peer won't see any change. Signed-off-by: Rusty Russell --- tests/test_connection.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_connection.py b/tests/test_connection.py index eb62b1b9322b..7c8603d989f6 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -493,6 +493,7 @@ def test_reconnect_signed(node_factory): l2.daemon.wait_for_log(' to CHANNELD_NORMAL') +@pytest.mark.skip('needs blackhold support') @pytest.mark.developer @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @@ -532,6 +533,7 @@ def test_reconnect_openingd(node_factory): l2.daemon.wait_for_log(r'channeld-chan#[0-9]: pid [0-9]+, msgfd [0-9]+') +@pytest.mark.skip('needs blackhold support') @pytest.mark.developer def test_reconnect_gossiping(node_factory): # connectd thinks we're still gossiping; peer reconnects. @@ -3030,6 +3032,7 @@ def test_restart_many_payments(node_factory, bitcoind): wait_for(lambda: 'pending' not in [p['status'] for p in n.rpc.listsendpays()['payments']]) +@pytest.mark.skip('needs blackhold support') @pytest.mark.developer("need dev-disconnect") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') @@ -3085,6 +3088,7 @@ def test_fail_unconfirmed(node_factory, bitcoind, executor): l1.fundchannel(l2, 200000, wait_for_active=True) +@pytest.mark.skip('needs blackhold support') @pytest.mark.developer("need dev-disconnect") @unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') @pytest.mark.openchannel('v2') @@ -3391,6 +3395,7 @@ def test_nonstatic_channel(node_factory, bitcoind): l1.rpc.close(l2.info['id']) +@pytest.mark.skip('needs blackhold support') @pytest.mark.developer("need --dev-timeout-secs") @pytest.mark.openchannel('v1') def test_connection_timeout(node_factory): From 81abdcdf566ae2390ac23f0838f577b550801542 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:32:54 +1030 Subject: [PATCH 08/51] dev_disconnect: remove @ marker. Once connectd is doing this, we can't close as soon as we send, and in fact we can't do 'fail write' either. Signed-off-by: Rusty Russell --- common/crypto_sync.c | 2 -- common/dev_disconnect.h | 4 +-- connectd/peer_exchange_initmsg.c | 2 -- tests/test_closing.py | 22 +++++++------- tests/test_connection.py | 48 +++++++------------------------ tests/test_misc.py | 4 +-- tests/test_opening.py | 49 ++------------------------------ 7 files changed, 28 insertions(+), 103 deletions(-) diff --git a/common/crypto_sync.c b/common/crypto_sync.c index 93733884b073..29d8cd92e89f 100644 --- a/common/crypto_sync.c +++ b/common/crypto_sync.c @@ -29,8 +29,6 @@ void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) case DEV_DISCONNECT_BEFORE: dev_sabotage_fd(pps->peer_fd, true); peer_failed_connection_lost(); - case DEV_DISCONNECT_DROPPKT: - enc = tal_free(enc); /* FALL THRU */ case DEV_DISCONNECT_AFTER: post_sabotage = true; post_close = true; diff --git a/common/dev_disconnect.h b/common/dev_disconnect.h index 3c0f4b8973d4..739e82355b7f 100644 --- a/common/dev_disconnect.h +++ b/common/dev_disconnect.h @@ -7,12 +7,10 @@ enum dev_disconnect { /* Do nothing. */ DEV_DISCONNECT_NORMAL = '=', - /* Close connection before sending packet (and fail write). */ + /* Close connection before sending packet. */ DEV_DISCONNECT_BEFORE = '-', /* Close connection after sending packet. */ DEV_DISCONNECT_AFTER = '+', - /* Close connection after dropping packet. */ - DEV_DISCONNECT_DROPPKT = '@', /* Swallow all writes from now on, and do no more reads. */ DEV_DISCONNECT_BLACKHOLE = '0', /* Don't use connection after sending packet, but don't close. */ diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index 9398bb75adad..d960a83d0587 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -204,8 +204,6 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, case DEV_DISCONNECT_BEFORE: dev_sabotage_fd(io_conn_fd(conn), true); break; - case DEV_DISCONNECT_DROPPKT: - peer->msg = tal_free(peer->msg); /* FALL THRU */ case DEV_DISCONNECT_AFTER: next = peer_write_postclose; break; diff --git a/tests/test_closing.py b/tests/test_closing.py index ea0f448d45f1..e82dc3871844 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -292,7 +292,6 @@ def test_closing_different_fees(node_factory, bitcoind, executor): @pytest.mark.developer("needs DEVELOPER=1") def test_closing_negotiation_reconnect(node_factory, bitcoind): disconnects = ['-WIRE_CLOSING_SIGNED', - '@WIRE_CLOSING_SIGNED', '+WIRE_CLOSING_SIGNED'] l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': disconnects, 'may_reconnect': True}, @@ -1761,7 +1760,7 @@ def test_onchain_dust_out(node_factory, bitcoind, executor): coin_mvt_plugin = os.path.join(os.getcwd(), 'tests/plugins/coin_movements.py') # HTLC 1->2, 1 fails after it's irrevocably committed - disconnects = ['@WIRE_REVOKE_AND_ACK', 'permfail'] + disconnects = ['-WIRE_REVOKE_AND_ACK', 'permfail'] # Feerates identical so we don't get gratuitous commit to update them l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': disconnects, @@ -3155,13 +3154,13 @@ def test_htlc_rexmit_while_closing(node_factory, executor): @pytest.mark.developer("needs dev_disconnect") def test_you_forgot_closed_channel(node_factory, executor): """Ideally you'd keep talking to us about closed channels: simple""" - disconnects = ['@WIRE_CLOSING_SIGNED'] + disconnects = ['xWIRE_CLOSING_SIGNED'] l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, - 'dev-no-reconnect': None}, - {'may_reconnect': True, 'dev-no-reconnect': None, - 'disconnect': disconnects}]) + 'disconnect': disconnects}, + {'may_reconnect': True, + 'dev-no-reconnect': None}]) l1.pay(l2, 200000) @@ -3172,6 +3171,7 @@ def test_you_forgot_closed_channel(node_factory, executor): assert only_one(only_one(l1.rpc.listpeers()['peers'])['channels'])['state'] == 'CLOSINGD_SIGEXCHANGE' # l1 reconnects, it should succeed. + l1.rpc.disconnect(l2.info['id'], force=True) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) fut.result(TIMEOUT) @@ -3179,13 +3179,13 @@ def test_you_forgot_closed_channel(node_factory, executor): @pytest.mark.developer("needs dev_disconnect") def test_you_forgot_closed_channel_onchain(node_factory, bitcoind, executor): """Ideally you'd keep talking to us about closed channels: even if close is mined""" - disconnects = ['@WIRE_CLOSING_SIGNED'] + disconnects = ['xWIRE_CLOSING_SIGNED'] l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, - 'dev-no-reconnect': None}, - {'may_reconnect': True, 'dev-no-reconnect': None, - 'disconnect': disconnects}]) + 'disconnect': disconnects}, + {'may_reconnect': True, + 'dev-no-reconnect': None}]) l1.pay(l2, 200000) @@ -3207,6 +3207,8 @@ def no_new_blocks(req): wait_for(lambda: only_one(only_one(l2.rpc.listpeers()['peers'])['channels'])['state'] == 'ONCHAIN') # l1 reconnects, it should succeed. + # l1 will disconnect once it sees block + wait_for(lambda: only_one(l1.rpc.listpeers()['peers'])['connected'] is False) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) fut.result(TIMEOUT) diff --git a/tests/test_connection.py b/tests/test_connection.py index 7c8603d989f6..c72b69928bbd 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -289,7 +289,6 @@ def test_channel_abandon(node_factory, bitcoind): def test_disconnect(node_factory): # These should all make us fail disconnects = ['-WIRE_INIT', - '@WIRE_INIT', '+WIRE_INIT'] l1 = node_factory.get_node(disconnect=disconnects) l2 = node_factory.get_node() @@ -298,8 +297,6 @@ def test_disconnect(node_factory): l1.rpc.connect(l2.info['id'], 'localhost', l2.port) with pytest.raises(RpcError): l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - with pytest.raises(RpcError): - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # Should have 3 connect fails. for d in disconnects: @@ -317,22 +314,16 @@ def test_disconnect(node_factory): def test_disconnect_opener(node_factory): # Now error on opener side during channel open. disconnects = ['-WIRE_OPEN_CHANNEL', - '@WIRE_OPEN_CHANNEL', '+WIRE_OPEN_CHANNEL', - '-WIRE_FUNDING_CREATED', - '@WIRE_FUNDING_CREATED'] + '-WIRE_FUNDING_CREATED'] if EXPERIMENTAL_DUAL_FUND: disconnects = ['-WIRE_OPEN_CHANNEL2', - '@WIRE_OPEN_CHANNEL2', '+WIRE_OPEN_CHANNEL2', '-WIRE_TX_ADD_INPUT', - '@WIRE_TX_ADD_INPUT', '+WIRE_TX_ADD_INPUT', '-WIRE_TX_ADD_OUTPUT', - '@WIRE_TX_ADD_OUTPUT', '+WIRE_TX_ADD_OUTPUT', '-WIRE_TX_COMPLETE', - '@WIRE_TX_COMPLETE', '+WIRE_TX_COMPLETE'] l1 = node_factory.get_node(disconnect=disconnects) @@ -361,14 +352,11 @@ def test_disconnect_opener(node_factory): def test_disconnect_fundee(node_factory): # Now error on fundee side during channel open. disconnects = ['-WIRE_ACCEPT_CHANNEL', - '@WIRE_ACCEPT_CHANNEL', '+WIRE_ACCEPT_CHANNEL'] if EXPERIMENTAL_DUAL_FUND: disconnects = ['-WIRE_ACCEPT_CHANNEL2', - '@WIRE_ACCEPT_CHANNEL2', '+WIRE_ACCEPT_CHANNEL2', '-WIRE_TX_COMPLETE', - '@WIRE_TX_COMPLETE', '+WIRE_TX_COMPLETE'] l1 = node_factory.get_node() @@ -397,16 +385,12 @@ def test_disconnect_fundee(node_factory): def test_disconnect_fundee_v2(node_factory): # Now error on fundee side during channel open, with them funding disconnects = ['-WIRE_ACCEPT_CHANNEL2', - '@WIRE_ACCEPT_CHANNEL2', '+WIRE_ACCEPT_CHANNEL2', '-WIRE_TX_ADD_INPUT', - '@WIRE_TX_ADD_INPUT', '+WIRE_TX_ADD_INPUT', '-WIRE_TX_ADD_OUTPUT', - '@WIRE_TX_ADD_OUTPUT', '+WIRE_TX_ADD_OUTPUT', '-WIRE_TX_COMPLETE', - '@WIRE_TX_COMPLETE', '+WIRE_TX_COMPLETE'] l1 = node_factory.get_node() @@ -440,9 +424,9 @@ def test_disconnect_fundee_v2(node_factory): def test_disconnect_half_signed(node_factory): # Now, these are the corner cases. Fundee sends funding_signed, # but opener doesn't receive it. - disconnects = ['@WIRE_FUNDING_SIGNED'] + disconnects = ['-WIRE_FUNDING_SIGNED'] if EXPERIMENTAL_DUAL_FUND: - disconnects = ['@WIRE_COMMITMENT_SIGNED'] + disconnects = ['-WIRE_COMMITMENT_SIGNED'] l1 = node_factory.get_node() l2 = node_factory.get_node(disconnect=disconnects) @@ -567,7 +551,7 @@ def test_reconnect_no_update(node_factory, executor, bitcoind): reconnects. See comments for details. """ - disconnects = ["@WIRE_FUNDING_LOCKED", "@WIRE_SHUTDOWN"] + disconnects = ["-WIRE_FUNDING_LOCKED", "-WIRE_SHUTDOWN"] # Allow bad gossip because it might receive WIRE_CHANNEL_UPDATE before # announcement of the disconnection l1 = node_factory.get_node(may_reconnect=True, allow_bad_gossip=True) @@ -591,7 +575,7 @@ def test_reconnect_no_update(node_factory, executor, bitcoind): # For closingd reconnection l1.daemon.start() - # Close will trigger the @WIRE_SHUTDOWN and we then wait for the + # Close will trigger the -WIRE_SHUTDOWN and we then wait for the # automatic reconnection to trigger the retransmission. l1.rpc.close(l2.info['id'], 0) l2.daemon.wait_for_log(r"channeld.* Retransmitting funding_locked for channel") @@ -645,7 +629,6 @@ def test_connect_stresstest(node_factory, executor): def test_reconnect_normal(node_factory): # Should reconnect fine even if locked message gets lost. disconnects = ['-WIRE_FUNDING_LOCKED', - '@WIRE_FUNDING_LOCKED', '+WIRE_FUNDING_LOCKED'] l1 = node_factory.get_node(disconnect=disconnects, may_reconnect=True) @@ -661,8 +644,7 @@ def test_reconnect_normal(node_factory): def test_reconnect_sender_add1(node_factory): # Fail after add is OK, will cause payment failure though. disconnects = ['-WIRE_UPDATE_ADD_HTLC-nocommit', - '+WIRE_UPDATE_ADD_HTLC-nocommit', - '@WIRE_UPDATE_ADD_HTLC-nocommit'] + '+WIRE_UPDATE_ADD_HTLC-nocommit'] # Feerates identical so we don't get gratuitous commit to update them l1 = node_factory.get_node(disconnect=disconnects, @@ -697,10 +679,8 @@ def test_reconnect_sender_add1(node_factory): @pytest.mark.openchannel('v2') def test_reconnect_sender_add(node_factory): disconnects = ['-WIRE_COMMITMENT_SIGNED', - '@WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED', '-WIRE_REVOKE_AND_ACK', - '@WIRE_REVOKE_AND_ACK', '+WIRE_REVOKE_AND_ACK'] if EXPERIMENTAL_DUAL_FUND: disconnects = ['=WIRE_COMMITMENT_SIGNED'] + disconnects @@ -733,10 +713,8 @@ def test_reconnect_sender_add(node_factory): @pytest.mark.openchannel('v2') def test_reconnect_receiver_add(node_factory): disconnects = ['-WIRE_COMMITMENT_SIGNED', - '@WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED', '-WIRE_REVOKE_AND_ACK', - '@WIRE_REVOKE_AND_ACK', '+WIRE_REVOKE_AND_ACK'] if EXPERIMENTAL_DUAL_FUND: @@ -767,14 +745,11 @@ def test_reconnect_receiver_fulfill(node_factory): # Ordering matters: after +WIRE_UPDATE_FULFILL_HTLC, channeld # will continue and try to send WIRE_COMMITMENT_SIGNED: if # that's the next failure, it will do two in one run. - disconnects = ['@WIRE_UPDATE_FULFILL_HTLC', - '+WIRE_UPDATE_FULFILL_HTLC', + disconnects = ['+WIRE_UPDATE_FULFILL_HTLC', '-WIRE_UPDATE_FULFILL_HTLC', '-WIRE_COMMITMENT_SIGNED', - '@WIRE_COMMITMENT_SIGNED', '+WIRE_COMMITMENT_SIGNED', '-WIRE_REVOKE_AND_ACK', - '@WIRE_REVOKE_AND_ACK', '+WIRE_REVOKE_AND_ACK'] l1 = node_factory.get_node(may_reconnect=True) l2 = node_factory.get_node(disconnect=disconnects, @@ -801,7 +776,6 @@ def test_reconnect_receiver_fulfill(node_factory): @pytest.mark.openchannel('v2') def test_shutdown_reconnect(node_factory): disconnects = ['-WIRE_SHUTDOWN', - '@WIRE_SHUTDOWN', '+WIRE_SHUTDOWN'] l1 = node_factory.get_node(disconnect=disconnects, may_reconnect=True) @@ -1797,7 +1771,7 @@ def test_multifunding_disconnect(node_factory): ''' Test disconnection during multifundchannel ''' - # TODO: Note that @WIRE_FUNDING_SIGNED does not + # TODO: Note that -WIRE_FUNDING_SIGNED does not # work. # See test_disconnect_half_signed. # If disconnected when the peer believes it sent @@ -1807,9 +1781,7 @@ def test_multifunding_disconnect(node_factory): # never send it. disconnects = ["-WIRE_INIT", "-WIRE_ACCEPT_CHANNEL", - "@WIRE_ACCEPT_CHANNEL", - "+WIRE_ACCEPT_CHANNEL", - "-WIRE_FUNDING_SIGNED"] + "+WIRE_ACCEPT_CHANNEL"] l1 = node_factory.get_node() l2 = node_factory.get_node(disconnect=disconnects) l3 = node_factory.get_node() @@ -1828,7 +1800,7 @@ def test_multifunding_disconnect(node_factory): l1.rpc.multifundchannel(destinations) # TODO: failing at the fundchannel_complete phase - # (@WIRE_FUNDING_SIGNED +@WIRE_FUNDING_SIGNED) + # (-WIRE_FUNDING_SIGNED +-WIRE_FUNDING_SIGNED) # leaves the peer (l2 in this case) in a state # where it is waiting for an incoming channel, # even though we no longer have a channel going to diff --git a/tests/test_misc.py b/tests/test_misc.py index b7e2120cd62a..7580432d66bd 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -316,7 +316,7 @@ def test_htlc_out_timeout(node_factory, bitcoind, executor): """Test that we drop onchain if the peer doesn't time out HTLC""" # HTLC 1->2, 1 fails after it's irrevocably committed, can't reconnect - disconnects = ['@WIRE_REVOKE_AND_ACK'] + disconnects = ['-WIRE_REVOKE_AND_ACK'] # Feerates identical so we don't get gratuitous commit to update them l1 = node_factory.get_node(disconnect=disconnects, options={'dev-no-reconnect': None}, @@ -336,7 +336,7 @@ def test_htlc_out_timeout(node_factory, bitcoind, executor): executor.submit(l1.rpc.dev_pay, inv, use_shadow=False) # l1 will disconnect, and not reconnect. - l1.daemon.wait_for_log('dev_disconnect: @WIRE_REVOKE_AND_ACK') + l1.daemon.wait_for_log('dev_disconnect: -WIRE_REVOKE_AND_ACK') # Takes 6 blocks to timeout (cltv-final + 1), but we also give grace period of 1 block. # shadow route can add extra blocks! diff --git a/tests/test_opening.py b/tests/test_opening.py index 31e74d3d3e91..c56537bf81a9 100644 --- a/tests/test_opening.py +++ b/tests/test_opening.py @@ -508,7 +508,6 @@ def test_v2_rbf_multi(node_factory, bitcoind, chainparams): @pytest.mark.openchannel('v2') def test_rbf_reconnect_init(node_factory, bitcoind, chainparams): disconnects = ['-WIRE_INIT_RBF', - '@WIRE_INIT_RBF', '+WIRE_INIT_RBF'] l1, l2 = node_factory.get_nodes(2, @@ -559,7 +558,6 @@ def test_rbf_reconnect_init(node_factory, bitcoind, chainparams): @pytest.mark.openchannel('v2') def test_rbf_reconnect_ack(node_factory, bitcoind, chainparams): disconnects = ['-WIRE_ACK_RBF', - '@WIRE_ACK_RBF', '+WIRE_ACK_RBF'] l1, l2 = node_factory.get_nodes(2, @@ -611,13 +609,10 @@ def test_rbf_reconnect_ack(node_factory, bitcoind, chainparams): def test_rbf_reconnect_tx_construct(node_factory, bitcoind, chainparams): disconnects = ['=WIRE_TX_ADD_INPUT', # Initial funding succeeds '-WIRE_TX_ADD_INPUT', - '@WIRE_TX_ADD_INPUT', '+WIRE_TX_ADD_INPUT', '-WIRE_TX_ADD_OUTPUT', - '@WIRE_TX_ADD_OUTPUT', '+WIRE_TX_ADD_OUTPUT', '-WIRE_TX_COMPLETE', - '@WIRE_TX_COMPLETE', '+WIRE_TX_COMPLETE'] l1, l2 = node_factory.get_nodes(2, @@ -652,14 +647,14 @@ def test_rbf_reconnect_tx_construct(node_factory, bitcoind, chainparams): excess_as_change=True) # Run through TX_ADD wires - for d in disconnects[1:-3]: + for d in disconnects[1:-2]: l1.rpc.connect(l2.info['id'], 'localhost', l2.port) with pytest.raises(RpcError): l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt']) assert l1.rpc.getpeer(l2.info['id']) is not None # Now we finish off the completes failure check - for d in disconnects[-3:]: + for d in disconnects[-2:]: l1.rpc.connect(l2.info['id'], 'localhost', l2.port) bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt']) with pytest.raises(RpcError): @@ -679,8 +674,6 @@ def test_rbf_reconnect_tx_sigs(node_factory, bitcoind, chainparams): disconnects = ['=WIRE_TX_SIGNATURES', # Initial funding succeeds '-WIRE_TX_SIGNATURES', # When we send tx-sigs, RBF '=WIRE_TX_SIGNATURES', # When we reconnect - '@WIRE_TX_SIGNATURES', # When we RBF again - '=WIRE_TX_SIGNATURES', # When we reconnect '+WIRE_TX_SIGNATURES'] # When we RBF again l1, l2 = node_factory.get_nodes(2, @@ -753,52 +746,16 @@ def test_rbf_reconnect_tx_sigs(node_factory, bitcoind, chainparams): l1.daemon.wait_for_log('peer_in WIRE_CHANNEL_REESTABLISH') l1.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES') - # Now we initiate the RBF + # 2nd RBF bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'], funding_feerate=next_feerate) update = l1.rpc.openchannel_update(chan_id, bump['psbt']) - - # Sign our inputs, and continue signed_psbt = l1.rpc.signpsbt(update['psbt'])['signed_psbt'] # Second time we error after we send our sigs with pytest.raises(RpcError, match='Owning subdaemon dualopend died'): l1.rpc.openchannel_signed(chan_id, signed_psbt) - # We reconnect and try again. feerate should have bumped - rate = int(find_next_feerate(l1, l2)[:-5]) - # We bump the feerate to beat the min-relay fee - next_feerate = '{}perkw'.format(rate * 2) - - startweight = 42 + 172 # base weight, funding output - initpsbt = l1.rpc.utxopsbt(chan_amount, next_feerate, startweight, - prev_utxos, reservedok=True, - min_witness_weight=110, - excess_as_change=True) - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - - # l2 gets our sigs and broadcasts them - l2.daemon.wait_for_log('peer_in WIRE_CHANNEL_REESTABLISH') - l2.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES') - l2.daemon.wait_for_log('sendrawtx exit 0') - - # Wait until we've done re-establish, if we try to - # RBF again too quickly, it'll fail since they haven't - # had time to process our sigs yet - l1.daemon.wait_for_log('peer_in WIRE_CHANNEL_REESTABLISH') - l1.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES') - - # 3rd RBF - bump = l1.rpc.openchannel_bump(chan_id, chan_amount, initpsbt['psbt'], - funding_feerate=next_feerate) - update = l1.rpc.openchannel_update(chan_id, bump['psbt']) - signed_psbt = l1.rpc.signpsbt(update['psbt'])['signed_psbt'] - - # Third time we error after we send our sigs - with pytest.raises(RpcError, match='Owning subdaemon dualopend died'): - l1.rpc.openchannel_signed(chan_id, signed_psbt) - # l2 gets our sigs l2.daemon.wait_for_log('peer_in WIRE_TX_SIGNATURES') l2.daemon.wait_for_log('sendrawtx exit 0') From d4ad4ce73b245132e82b1d320629af495f5df879 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:33:54 +1030 Subject: [PATCH 09/51] channeld: add dev-disable-commit-after instead of dev-disconnect -nocommit It was always a hack, but an impossible one once connectd will be interpreting dev-disconnect! Signed-off-by: Rusty Russell --- channeld/channeld.c | 137 ++++++++++++++++++++--------------- channeld/channeld_wire.csv | 1 + common/dev_disconnect.c | 14 +--- common/dev_disconnect.h | 2 - lightningd/channel_control.c | 120 +++++++++++++++--------------- lightningd/lightningd.c | 1 + lightningd/lightningd.h | 3 + lightningd/options.c | 4 + tests/test_closing.py | 44 +++++------ tests/test_connection.py | 37 +++++----- tests/test_pay.py | 16 ++-- 11 files changed, 198 insertions(+), 181 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 4b1dcf12052c..de1a4741bf59 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -158,6 +158,10 @@ struct peer { struct msg_queue *update_queue; #endif +#if DEVELOPER + /* If set, don't fire commit counter when this hits 0 */ + u32 *dev_disable_commit; +#endif /* Information used for reestablishment. */ bool last_was_revoke; struct changed_htlc *last_sent_commit; @@ -1248,8 +1252,7 @@ static void send_commit(struct peer *peer) u32 feerate_target; #if DEVELOPER - /* Hack to suppress all commit sends if dev_disconnect says to */ - if (dev_suppress_commit) { + if (peer->dev_disable_commit && !*peer->dev_disable_commit) { peer->commit_timer = NULL; return; } @@ -1384,6 +1387,14 @@ static void send_commit(struct peer *peer) } else pbase = NULL; +#if DEVELOPER + if (peer->dev_disable_commit) { + (*peer->dev_disable_commit)--; + if (*peer->dev_disable_commit == 0) + status_unusual("dev-disable-commit-after: disabling"); + } +#endif + status_debug("Telling master we're about to commit..."); /* Tell master to save this next commit to database, then wait. */ msg = sending_commitsig_msg(NULL, peer->next_index[REMOTE], @@ -3655,7 +3666,7 @@ static void handle_send_ping(struct peer *peer, const u8 *msg) #if DEVELOPER static void handle_dev_reenable_commit(struct peer *peer) { - dev_suppress_commit = false; + peer->dev_disable_commit = tal_free(peer->dev_disable_commit); start_commit_timer(peer); status_debug("dev_reenable_commit"); wire_sync_write(MASTER_FD, @@ -3828,6 +3839,7 @@ static void init_channel(struct peer *peer) struct penalty_base *pbases; u8 *reestablish_only; struct channel_type *channel_type; + u32 *dev_disable_commit; /* Always NULL */ #if !DEVELOPER bool dev_fail_process_onionpacket; /* Ignored */ #endif @@ -3836,66 +3848,71 @@ static void init_channel(struct peer *peer) msg = wire_sync_read(tmpctx, MASTER_FD); if (!fromwire_channeld_init(peer, msg, - &chainparams, - &peer->our_features, - &peer->channel_id, - &funding, - &funding_sats, - &minimum_depth, - &peer->our_blockheight, - &blockheight_states, - &lease_expiry, - &conf[LOCAL], &conf[REMOTE], - &fee_states, - &peer->feerate_min, - &peer->feerate_max, - &peer->feerate_penalty, - &peer->their_commit_sig, - &peer->pps, - &funding_pubkey[REMOTE], - &points[REMOTE], - &peer->remote_per_commit, - &peer->old_remote_per_commit, - &opener, - &peer->fee_base, - &peer->fee_per_satoshi, - &local_msat, - &points[LOCAL], - &funding_pubkey[LOCAL], - &peer->node_ids[LOCAL], - &peer->node_ids[REMOTE], - &peer->commit_msec, - &peer->cltv_delta, - &peer->last_was_revoke, - &peer->last_sent_commit, - &peer->next_index[LOCAL], - &peer->next_index[REMOTE], - &peer->revocations_received, - &peer->htlc_id, - &htlcs, - &peer->funding_locked[LOCAL], - &peer->funding_locked[REMOTE], - &peer->short_channel_ids[LOCAL], - &reconnected, - &peer->send_shutdown, - &peer->shutdown_sent[REMOTE], - &peer->final_scriptpubkey, - &peer->channel_flags, - &fwd_msg, - &peer->announce_depth_reached, - &last_remote_per_commit_secret, - &peer->their_features, - &peer->remote_upfront_shutdown_script, - &remote_ann_node_sig, - &remote_ann_bitcoin_sig, - &channel_type, - &dev_fast_gossip, - &dev_fail_process_onionpacket, - &pbases, - &reestablish_only)) { + &chainparams, + &peer->our_features, + &peer->channel_id, + &funding, + &funding_sats, + &minimum_depth, + &peer->our_blockheight, + &blockheight_states, + &lease_expiry, + &conf[LOCAL], &conf[REMOTE], + &fee_states, + &peer->feerate_min, + &peer->feerate_max, + &peer->feerate_penalty, + &peer->their_commit_sig, + &peer->pps, + &funding_pubkey[REMOTE], + &points[REMOTE], + &peer->remote_per_commit, + &peer->old_remote_per_commit, + &opener, + &peer->fee_base, + &peer->fee_per_satoshi, + &local_msat, + &points[LOCAL], + &funding_pubkey[LOCAL], + &peer->node_ids[LOCAL], + &peer->node_ids[REMOTE], + &peer->commit_msec, + &peer->cltv_delta, + &peer->last_was_revoke, + &peer->last_sent_commit, + &peer->next_index[LOCAL], + &peer->next_index[REMOTE], + &peer->revocations_received, + &peer->htlc_id, + &htlcs, + &peer->funding_locked[LOCAL], + &peer->funding_locked[REMOTE], + &peer->short_channel_ids[LOCAL], + &reconnected, + &peer->send_shutdown, + &peer->shutdown_sent[REMOTE], + &peer->final_scriptpubkey, + &peer->channel_flags, + &fwd_msg, + &peer->announce_depth_reached, + &last_remote_per_commit_secret, + &peer->their_features, + &peer->remote_upfront_shutdown_script, + &remote_ann_node_sig, + &remote_ann_bitcoin_sig, + &channel_type, + &dev_fast_gossip, + &dev_fail_process_onionpacket, + &dev_disable_commit, + &pbases, + &reestablish_only)) { master_badmsg(WIRE_CHANNELD_INIT, msg); } +#if DEVELOPER + peer->dev_disable_commit = dev_disable_commit; +#endif + status_debug("option_static_remotekey = %u, option_anchor_outputs = %u", channel_type_has(channel_type, OPT_STATIC_REMOTEKEY), channel_type_has(channel_type, OPT_ANCHOR_OUTPUTS)); diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index 7888fb4d4ce6..f2eca498d7bb 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -74,6 +74,7 @@ msgdata,channeld_init,remote_ann_bitcoin_sig,?secp256k1_ecdsa_signature, msgdata,channeld_init,desired_type,channel_type, msgdata,channeld_init,dev_fast_gossip,bool, msgdata,channeld_init,dev_fail_process_onionpacket,bool, +msgdata,channeld_init,dev_disable_commit,?u32, msgdata,channeld_init,num_penalty_bases,u32, msgdata,channeld_init,pbases,penalty_base,num_penalty_bases msgdata,channeld_init,reestablish_only_len,u16, diff --git a/common/dev_disconnect.c b/common/dev_disconnect.c index bb2453c30f50..0dd088290541 100644 --- a/common/dev_disconnect.c +++ b/common/dev_disconnect.c @@ -15,9 +15,6 @@ static int dev_disconnect_fd = -1; static char dev_disconnect_line[200]; static int dev_disconnect_count, dev_disconnect_len; -static bool dev_disconnect_nocommit; - -bool dev_suppress_commit; static void next_dev_disconnect(void) { @@ -36,12 +33,6 @@ static void next_dev_disconnect(void) dev_disconnect_line[r] = '\n'; dev_disconnect_len = strcspn(dev_disconnect_line, "\n"); dev_disconnect_line[dev_disconnect_len] = '\0'; - if (strends(dev_disconnect_line, "-nocommit")) { - dev_disconnect_line[strlen(dev_disconnect_line) - - strlen("-nocommit")] = '\0'; - dev_disconnect_nocommit = true; - } else - dev_disconnect_nocommit = false; asterisk = strchr(dev_disconnect_line, '*'); if (asterisk) { @@ -79,10 +70,7 @@ enum dev_disconnect dev_disconnect(int pkt_type) err(1, "lseek failure"); } - status_debug("dev_disconnect: %s%s", dev_disconnect_line, - dev_disconnect_nocommit ? "-nocommit" : ""); - if (dev_disconnect_nocommit) - dev_suppress_commit = true; + status_debug("dev_disconnect: %s", dev_disconnect_line); return dev_disconnect_line[0]; } diff --git a/common/dev_disconnect.h b/common/dev_disconnect.h index 739e82355b7f..0f4ae524a4f3 100644 --- a/common/dev_disconnect.h +++ b/common/dev_disconnect.h @@ -29,8 +29,6 @@ void dev_blackhole_fd(int fd); /* For debug code to set in daemon. */ void dev_disconnect_init(int fd); -/* Hack for channeld to do DEV_DISCONNECT_SUPPRESS_COMMIT. */ -extern bool dev_suppress_commit; #endif /* DEVELOPER */ #endif /* LIGHTNING_COMMON_DEV_DISCONNECT_H */ diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index e6fb0af00ab0..3d9b8dabd05b 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -646,68 +646,72 @@ void peer_start_channeld(struct channel *channel, tmpctx, channel->peer->ld->wallet, channel->dbid); initmsg = towire_channeld_init(tmpctx, - chainparams, - ld->our_features, - &channel->cid, - &channel->funding, - channel->funding_sats, - channel->minimum_depth, - get_block_height(ld->topology), - channel->blockheight_states, - channel->lease_expiry, - &channel->our_config, - &channel->channel_info.their_config, - channel->fee_states, - feerate_min(ld, NULL), - feerate_max(ld, NULL), - try_get_feerate(ld->topology, FEERATE_PENALTY), - &channel->last_sig, - pps, - &channel->channel_info.remote_fundingkey, - &channel->channel_info.theirbase, - &channel->channel_info.remote_per_commit, - &channel->channel_info.old_remote_per_commit, - channel->opener, - channel->feerate_base, - channel->feerate_ppm, - channel->our_msat, - &channel->local_basepoints, - &channel->local_funding_pubkey, - &ld->id, - &channel->peer->id, - cfg->commit_time_ms, - cfg->cltv_expiry_delta, - channel->last_was_revoke, - channel->last_sent_commit, - channel->next_index[LOCAL], - channel->next_index[REMOTE], - num_revocations, - channel->next_htlc_id, - htlcs, - channel->scid != NULL, - channel->remote_funding_locked, - &scid, - reconnected, + chainparams, + ld->our_features, + &channel->cid, + &channel->funding, + channel->funding_sats, + channel->minimum_depth, + get_block_height(ld->topology), + channel->blockheight_states, + channel->lease_expiry, + &channel->our_config, + &channel->channel_info.their_config, + channel->fee_states, + feerate_min(ld, NULL), + feerate_max(ld, NULL), + try_get_feerate(ld->topology, FEERATE_PENALTY), + &channel->last_sig, + pps, + &channel->channel_info.remote_fundingkey, + &channel->channel_info.theirbase, + &channel->channel_info.remote_per_commit, + &channel->channel_info.old_remote_per_commit, + channel->opener, + channel->feerate_base, + channel->feerate_ppm, + channel->our_msat, + &channel->local_basepoints, + &channel->local_funding_pubkey, + &ld->id, + &channel->peer->id, + cfg->commit_time_ms, + cfg->cltv_expiry_delta, + channel->last_was_revoke, + channel->last_sent_commit, + channel->next_index[LOCAL], + channel->next_index[REMOTE], + num_revocations, + channel->next_htlc_id, + htlcs, + channel->scid != NULL, + channel->remote_funding_locked, + &scid, + reconnected, /* Anything that indicates we are or have * shut down */ - channel->state == CHANNELD_SHUTTING_DOWN + channel->state == CHANNELD_SHUTTING_DOWN || channel->state == CLOSINGD_SIGEXCHANGE || channel_closed(channel), - channel->shutdown_scriptpubkey[REMOTE] != NULL, - channel->shutdown_scriptpubkey[LOCAL], - channel->channel_flags, - fwd_msg, - reached_announce_depth, - &last_remote_per_commit_secret, - channel->peer->their_features, - channel->remote_upfront_shutdown_script, - remote_ann_node_sig, - remote_ann_bitcoin_sig, - channel->type, - IFDEV(ld->dev_fast_gossip, false), - IFDEV(dev_fail_process_onionpacket, false), - pbases, - reestablish_only); + channel->shutdown_scriptpubkey[REMOTE] != NULL, + channel->shutdown_scriptpubkey[LOCAL], + channel->channel_flags, + fwd_msg, + reached_announce_depth, + &last_remote_per_commit_secret, + channel->peer->their_features, + channel->remote_upfront_shutdown_script, + remote_ann_node_sig, + remote_ann_bitcoin_sig, + channel->type, + IFDEV(ld->dev_fast_gossip, false), + IFDEV(dev_fail_process_onionpacket, false), + IFDEV(ld->dev_disable_commit == -1 + ? NULL + : (u32 *)&ld->dev_disable_commit, + NULL), + pbases, + reestablish_only); /* We don't expect a response: we are triggered by funding_depth_cb. */ subd_send_msg(channel->owner, take(initmsg)); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index f406e68d04b9..45b8f4adc8f1 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -133,6 +133,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->dev_max_funding_unconfirmed = 2016; ld->dev_ignore_modern_onion = false; ld->dev_ignore_obsolete_onion = false; + ld->dev_disable_commit = -1; #endif /*~ These are CCAN lists: an embedded double-linked list. It's not diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 8fabc615076a..884b2f921744 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -250,6 +250,9 @@ struct lightningd { /* Special switches to test onion compatibility */ bool dev_ignore_modern_onion, dev_ignore_obsolete_onion; + + /* Tell channeld to disable commits after this many. */ + int dev_disable_commit; #endif /* DEVELOPER */ /* tor support */ diff --git a/lightningd/options.c b/lightningd/options.c index 146fbee7e248..a1f263a0e139 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -697,6 +697,10 @@ static void dev_register_opts(struct lightningd *ld) opt_register_noarg("--dev-no-obsolete-onion", opt_set_bool, &ld->dev_ignore_obsolete_onion, "Ignore obsolete onion messages"); + opt_register_arg("--dev-disable-commit-after", + opt_set_intval, opt_show_intval, + &ld->dev_disable_commit, + "Disable commit timer after this many commits"); } #endif /* DEVELOPER */ diff --git a/tests/test_closing.py b/tests/test_closing.py index e82dc3871844..cd54e6c54bff 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -510,7 +510,7 @@ def test_closing_negotiation_step_700sat(node_factory, bitcoind, chainparams): closing_negotiation_step(node_factory, bitcoind, chainparams, opts) -@pytest.mark.developer("needs DEVELOPER=1") +@pytest.mark.developer("needs dev-disable-commit-after") def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams): """Test penalty transaction with an incoming HTLC""" @@ -518,12 +518,12 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams): coin_mvt_plugin = os.path.join(os.getcwd(), 'tests/plugins/coin_movements.py') # We suppress each one after first commit; HTLC gets added not fulfilled. # Feerates identical so we don't get gratuitous commit to update them - l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': ['=WIRE_COMMITMENT_SIGNED-nocommit'], + l1, l2 = node_factory.line_graph(2, opts=[{'dev-disable-commit-after': 1, 'may_fail': True, 'feerates': (7500, 7500, 7500, 7500), 'allow_broken_log': True, 'plugin': coin_mvt_plugin}, - {'disconnect': ['=WIRE_COMMITMENT_SIGNED-nocommit'], + {'dev-disable-commit-after': 1, 'plugin': coin_mvt_plugin}]) channel_id = first_channel_id(l1, l2) @@ -535,8 +535,8 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams): assert len(l2.getactivechannels()) == 2 # They should both have commitments blocked now. - l1.daemon.wait_for_log('=WIRE_COMMITMENT_SIGNED-nocommit') - l2.daemon.wait_for_log('=WIRE_COMMITMENT_SIGNED-nocommit') + l1.daemon.wait_for_log('dev-disable-commit-after: disabling') + l2.daemon.wait_for_log('dev-disable-commit-after: disabling') # Make sure l1 got l2's commitment to the HTLC, and sent to master. l1.daemon.wait_for_log('got commitsig') @@ -606,7 +606,7 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams): assert account_balance(l2, channel_id) == 0 -@pytest.mark.developer("needs DEVELOPER=1") +@pytest.mark.developer("needs dev-disable-commit-after") def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams): """Test penalty transaction with an outgoing HTLC""" @@ -615,20 +615,20 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams): # First we need to get funds to l2, so suppress after second. # Feerates identical so we don't get gratuitous commit to update them l1, l2 = node_factory.line_graph(2, - opts=[{'disconnect': ['=WIRE_COMMITMENT_SIGNED*3-nocommit'], + opts=[{'dev-disable-commit-after': 3, 'may_fail': True, 'feerates': (7500, 7500, 7500, 7500), 'allow_broken_log': True, 'plugin': coin_mvt_plugin}, - {'disconnect': ['=WIRE_COMMITMENT_SIGNED*3-nocommit'], + {'dev-disable-commit-after': 3, 'plugin': coin_mvt_plugin}]) channel_id = first_channel_id(l1, l2) # Move some across to l2. l1.pay(l2, 200000000) - assert not l1.daemon.is_in_log('=WIRE_COMMITMENT_SIGNED') - assert not l2.daemon.is_in_log('=WIRE_COMMITMENT_SIGNED') + assert not l1.daemon.is_in_log('dev-disable-commit-after: disabling') + assert not l2.daemon.is_in_log('dev-disable-commit-after: disabling') # Now, this will get stuck due to l1 commit being disabled.. t = executor.submit(l2.pay, l1, 100000000) @@ -638,8 +638,8 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams): l1.daemon.wait_for_log('peer_in WIRE_COMMITMENT_SIGNED') # They should both have commitments blocked now. - l1.daemon.wait_for_log('dev_disconnect: =WIRE_COMMITMENT_SIGNED') - l2.daemon.wait_for_log('dev_disconnect: =WIRE_COMMITMENT_SIGNED') + l1.daemon.wait_for_log('dev-disable-commit-after: disabling') + l2.daemon.wait_for_log('dev-disable-commit-after: disabling') # Make sure both sides got revoke_and_ack for that commitment. l1.daemon.wait_for_log('peer_in WIRE_REVOKE_AND_ACK') @@ -1405,10 +1405,10 @@ def test_penalty_rbf_normal(node_factory, bitcoind, executor, chainparams): # l1 is the thief, which causes our honest upstanding lightningd # code to break, so l1 can fail. # Initially, disconnect before the HTLC can be resolved. - l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], + l1 = node_factory.get_node(options={'dev-disable-commit-after': 1}, may_fail=True, allow_broken_log=True) - l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], - options={'watchtime-blocks': to_self_delay}) + l2 = node_factory.get_node(options={'dev-disable-commit-after': 1, + 'watchtime-blocks': to_self_delay}) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.fundchannel(l2, 10**7) @@ -1421,8 +1421,8 @@ def test_penalty_rbf_normal(node_factory, bitcoind, executor, chainparams): assert len(l2.getactivechannels()) == 2 # Wait for the disconnection. - l1.daemon.wait_for_log('=WIRE_COMMITMENT_SIGNED-nocommit') - l2.daemon.wait_for_log('=WIRE_COMMITMENT_SIGNED-nocommit') + l1.daemon.wait_for_log('dev-disable-commit-after: disabling') + l2.daemon.wait_for_log('dev-disable-commit-after: disabling') # Make sure l1 gets the new HTLC. l1.daemon.wait_for_log('got commitsig') @@ -1511,10 +1511,10 @@ def test_penalty_rbf_burn(node_factory, bitcoind, executor, chainparams): # l1 is the thief, which causes our honest upstanding lightningd # code to break, so l1 can fail. # Initially, disconnect before the HTLC can be resolved. - l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], + l1 = node_factory.get_node(options={'dev-disable-commit-after': 1}, may_fail=True, allow_broken_log=True) - l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], - options={'watchtime-blocks': to_self_delay}) + l2 = node_factory.get_node(options={'dev-disable-commit-after': 1, + 'watchtime-blocks': to_self_delay}) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.fundchannel(l2, 10**7) @@ -1527,8 +1527,8 @@ def test_penalty_rbf_burn(node_factory, bitcoind, executor, chainparams): assert len(l2.getactivechannels()) == 2 # Wait for the disconnection. - l1.daemon.wait_for_log('=WIRE_COMMITMENT_SIGNED-nocommit') - l2.daemon.wait_for_log('=WIRE_COMMITMENT_SIGNED-nocommit') + l1.daemon.wait_for_log('dev-disable-commit-after: disabling') + l2.daemon.wait_for_log('dev-disable-commit-after: disabling') # Make sure l1 gets the new HTLC. l1.daemon.wait_for_log('got commitsig') diff --git a/tests/test_connection.py b/tests/test_connection.py index c72b69928bbd..ad7b04b2682f 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -643,8 +643,8 @@ def test_reconnect_normal(node_factory): @pytest.mark.openchannel('v2') def test_reconnect_sender_add1(node_factory): # Fail after add is OK, will cause payment failure though. - disconnects = ['-WIRE_UPDATE_ADD_HTLC-nocommit', - '+WIRE_UPDATE_ADD_HTLC-nocommit'] + disconnects = ['-WIRE_UPDATE_ADD_HTLC', + '+WIRE_UPDATE_ADD_HTLC'] # Feerates identical so we don't get gratuitous commit to update them l1 = node_factory.get_node(disconnect=disconnects, @@ -2080,14 +2080,14 @@ def test_channel_persistence(node_factory, bitcoind, executor): # mysteriously die while committing the first HTLC so we can # check that HTLCs reloaded from the DB work. # Feerates identical so we don't get gratuitous commit to update them - disconnect = ['=WIRE_COMMITMENT_SIGNED-nocommit'] - + disable_commit_after = 1 if EXPERIMENTAL_DUAL_FUND: - disconnect = ['=WIRE_COMMITMENT_SIGNED'] + disconnect + disable_commit_after = 2 l1 = node_factory.get_node(may_reconnect=True, feerates=(7500, 7500, 7500, 7500)) - l2 = node_factory.get_node(disconnect=disconnect, may_reconnect=True) + l2 = node_factory.get_node(options={'dev-disable-commit-after': disable_commit_after}, + may_reconnect=True) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) # Neither node should have a channel open, they are just connected @@ -2114,7 +2114,7 @@ def test_channel_persistence(node_factory, bitcoind, executor): l2.daemon.kill() # Clear the disconnect and timer stop so we can proceed normally - del l2.daemon.opts['dev-disconnect'] + del l2.daemon.opts['dev-disable-commit-after'] # Wait for l1 to notice wait_for(lambda: 'connected' not in only_one(l1.rpc.listpeers()['peers'][0]['channels'])) @@ -2840,10 +2840,9 @@ def test_dataloss_protection(node_factory, bitcoind): @pytest.mark.developer("needs dev_disconnect") def test_restart_multi_htlc_rexmit(node_factory, bitcoind, executor): # l1 disables commit timer once we send first htlc, dies on commit - disconnects = ['=WIRE_UPDATE_ADD_HTLC-nocommit', - '-WIRE_COMMITMENT_SIGNED'] - l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': disconnects, - 'may_reconnect': True}, + l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': ['-WIRE_COMMITMENT_SIGNED'], + 'may_reconnect': True, + 'dev-disable-commit-after': 0}, {'may_reconnect': True}]) executor.submit(l1.pay, l2, 20000) @@ -3392,9 +3391,9 @@ def test_htlc_retransmit_order(node_factory, executor): l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, 'feerates': (7500, 7500, 7500, 7500), - 'disconnect': ['=WIRE_UPDATE_ADD_HTLC-nocommit', - '=WIRE_UPDATE_ADD_HTLC*' + str(NUM_HTLCS - 1), - '-WIRE_COMMITMENT_SIGNED']}, + 'disconnect': ['=WIRE_UPDATE_ADD_HTLC*' + str(NUM_HTLCS), + '-WIRE_COMMITMENT_SIGNED'], + 'dev-disable-commit-after': 0}, {'may_reconnect': True}]) invoices = [l2.rpc.invoice(1000, str(x), str(x)) for x in range(NUM_HTLCS)] @@ -3407,7 +3406,7 @@ def test_htlc_retransmit_order(node_factory, executor): for inv in invoices: executor.submit(l1.rpc.sendpay, [routestep], inv['payment_hash'], payment_secret=inv['payment_secret']) - l1.daemon.wait_for_logs(['dev_disconnect'] * 2) + l1.daemon.wait_for_log('dev_disconnect') l1.rpc.call('dev-reenable-commit', [l2.info['id']]) l1.daemon.wait_for_log('dev_disconnect') @@ -3614,8 +3613,7 @@ def test_upgrade_statickey_fail(node_factory, executor, bitcoind): l1_disconnects = ['-WIRE_COMMITMENT_SIGNED', '-WIRE_REVOKE_AND_ACK'] l2_disconnects = ['-WIRE_REVOKE_AND_ACK', - '-WIRE_COMMITMENT_SIGNED', - '=WIRE_UPDATE_FAIL_HTLC-nocommit'] + '-WIRE_COMMITMENT_SIGNED'] l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True, 'dev-no-reconnect': None, @@ -3625,13 +3623,14 @@ def test_upgrade_statickey_fail(node_factory, executor, bitcoind): 'feerates': (7500, 7500, 7500, 7500)}, {'may_reconnect': True, 'dev-no-reconnect': None, - 'disconnect': l2_disconnects}]) + 'disconnect': l2_disconnects, + 'dev-disable-commit-after': 1}]) # This HTLC will fail l1.rpc.sendpay([{'msatoshi': 1000, 'id': l2.info['id'], 'delay': 5, 'channel': '1x1x1'}], '00' * 32, payment_secret='00' * 32) # Each one should cause one disconnection, no upgrade. - for d in l1_disconnects + l2_disconnects[:-1]: + for d in l1_disconnects + l2_disconnects: l1.daemon.wait_for_log('Peer connection lost') l2.daemon.wait_for_log('Peer connection lost') assert not l1.daemon.is_in_log('option_static_remotekey enabled') diff --git a/tests/test_pay.py b/tests/test_pay.py index 96922a82f41a..5516099d90ac 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -450,7 +450,7 @@ def test_payment_failed_persistence(node_factory, executor): @pytest.mark.developer("needs DEVELOPER=1") def test_payment_duplicate_uncommitted(node_factory, executor): # We want to test two payments at the same time, before we send commit - l1 = node_factory.get_node(disconnect=['=WIRE_UPDATE_ADD_HTLC-nocommit']) + l1 = node_factory.get_node(options={'dev-disable-commit-after': 0}) l2 = node_factory.get_node() l1.rpc.connect(l2.info['id'], 'localhost', l2.port) @@ -463,7 +463,7 @@ def test_payment_duplicate_uncommitted(node_factory, executor): fut = executor.submit(l1.rpc.pay, inv1['bolt11']) # Make sure that's started... - l1.daemon.wait_for_log('dev_disconnect: =WIRE_UPDATE_ADD_HTLC-nocommit') + l1.daemon.wait_for_log('peer_out WIRE_UPDATE_ADD_HTLC') # We should see it in listsendpays payments = l1.rpc.listsendpays()['payments'] @@ -2809,12 +2809,12 @@ def truncate_encode(i: int): assert(e.error['data']['raw_message'] == "400f00000000000003e80000006c") -@pytest.mark.developer("needs dev-disconnect, dev-no-htlc-timeout") +@pytest.mark.developer("needs dev-disable-commit-after, dev-no-htlc-timeout") @pytest.mark.openchannel('v1') @pytest.mark.openchannel('v2') def test_partial_payment(node_factory, bitcoind, executor): # We want to test two payments at the same time, before we send commit - l1, l2, l3, l4 = node_factory.get_nodes(4, [{}] + [{'disconnect': ['=WIRE_UPDATE_ADD_HTLC-nocommit'], 'dev-no-htlc-timeout': None}] * 2 + [{'plugin': os.path.join(os.getcwd(), 'tests/plugins/print_htlc_onion.py')}]) + l1, l2, l3, l4 = node_factory.get_nodes(4, [{}] + [{'dev-disable-commit-after': 0, 'dev-no-htlc-timeout': None}] * 2 + [{'plugin': os.path.join(os.getcwd(), 'tests/plugins/print_htlc_onion.py')}]) # Two routes to l4: one via l2, and one via l3. l1.rpc.connect(l2.info['id'], 'localhost', l2.port) @@ -2925,13 +2925,15 @@ def test_partial_payment(node_factory, bitcoind, executor): groupid=1, ) - # Make sure they've done the suppress-commitment thing before we unsuppress - l2.daemon.wait_for_log(r'dev_disconnect') - l3.daemon.wait_for_log(r'dev_disconnect') + # Make sure they've got the HTLCs before we unsuppress + l2.daemon.wait_for_logs('peer_in WIRE_UPDATE_ADD_HTLC') + l3.daemon.wait_for_log('peer_in WIRE_UPDATE_ADD_HTLC') # Now continue, payments will succeed due to MPP. l2.rpc.dev_reenable_commit(l4.info['id']) l3.rpc.dev_reenable_commit(l4.info['id']) + l2.rpc.dev_reenable_commit(l1.info['id']) + l3.rpc.dev_reenable_commit(l1.info['id']) res = l1.rpc.waitsendpay(payment_hash=inv['payment_hash'], partid=1) assert res['partid'] == 1 From 2975aa349d4713a1ecb670c57101fb2fc246b2ea Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:34:54 +1030 Subject: [PATCH 10/51] gossipd: local_direction helper to generalize is_local_channel. Increasingly we want to know is it local, and get the direction: it's more efficient to do both at once. Signed-off-by: Rusty Russell --- gossipd/routing.c | 13 +++---------- gossipd/routing.h | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/gossipd/routing.c b/gossipd/routing.c index d246b2ee53fc..560e1423932d 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -795,13 +795,6 @@ static void destroy_pending_cannouncement(struct pending_cannouncement *pending, pending_cannouncement_map_del(&rstate->pending_cannouncements, pending); } -static bool is_local_channel(const struct routing_state *rstate, - const struct chan *chan) -{ - return node_id_eq(&chan->nodes[0]->id, &rstate->local_id) - || node_id_eq(&chan->nodes[1]->id, &rstate->local_id); -} - static void add_channel_announce_to_broadcast(struct routing_state *rstate, struct chan *chan, const u8 *channel_announce, @@ -809,7 +802,7 @@ static void add_channel_announce_to_broadcast(struct routing_state *rstate, u32 index) { u8 *addendum = towire_gossip_store_channel_amount(tmpctx, chan->sat); - bool is_local = is_local_channel(rstate, chan); + bool is_local = local_direction(rstate, chan, NULL); chan->bcast.timestamp = timestamp; /* 0, unless we're loading from store */ @@ -1381,7 +1374,7 @@ bool routing_add_channel_update(struct routing_state *rstate, } else if (!is_chan_public(chan)) { /* For private channels, we get updates without an announce: don't * broadcast them! But save local ones to store anyway. */ - assert(is_local_channel(rstate, chan)); + assert(local_direction(rstate, chan, NULL)); /* Don't save if we're loading from store */ if (!index) { hc->bcast.index @@ -1399,7 +1392,7 @@ bool routing_add_channel_update(struct routing_state *rstate, hc->bcast.index = gossip_store_add(rstate->gs, update, hc->bcast.timestamp, - is_local_channel(rstate, chan), + local_direction(rstate, chan, NULL), NULL); if (hc->bcast.timestamp > rstate->last_timestamp && hc->bcast.timestamp < time_now().ts.tv_sec) diff --git a/gossipd/routing.h b/gossipd/routing.h index a0ec756f09fe..1a8a08d0cde0 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -273,6 +273,21 @@ struct routing_state { #endif }; +/* Which direction are we? False if neither. */ +static inline bool local_direction(struct routing_state *rstate, + const struct chan *chan, + int *direction) +{ + for (int dir = 0; dir <= 1; (dir)++) { + if (node_id_eq(&chan->nodes[dir]->id, &rstate->local_id)) { + if (direction) + *direction = dir; + return true; + } + } + return false; +} + static inline struct chan * get_channel(const struct routing_state *rstate, const struct short_channel_id *scid) From 37abe30539790861f2a763d73b081d976806b88d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:35:54 +1030 Subject: [PATCH 11/51] gossipd: rewrite update generation, remove local_chan. local_chan was mainly around so we could "soft" disable channels (and really disable them once we used the channel_update in an error message). Instead we introduce the idea of a "deferred_update": it's either deferred indefinitely (a peer goes offline, if we need to send it in an error we'll apply it immediatly), or simply delayed to avoid spamming everyone. The resulting rewrite is much clearer, IMHO. Signed-off-by: Rusty Russell --- gossipd/gossip_generation.c | 591 ++++++++++++++++++++++--------- gossipd/gossip_generation.h | 14 +- gossipd/gossipd.c | 128 ++++--- gossipd/gossipd.h | 3 + gossipd/routing.c | 35 -- gossipd/routing.h | 75 +--- gossipd/test/run-onion_message.c | 12 +- 7 files changed, 523 insertions(+), 335 deletions(-) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 7e71e5b81262..6ca0ff3e521e 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -307,48 +307,136 @@ void maybe_send_own_node_announce(struct daemon *daemon, bool startup) update_own_node_announcement(daemon, startup); } -/* Our timer callbacks take a single argument, so we marshall everything - * we need into this structure: */ -struct local_cupdate { - struct daemon *daemon; - struct local_chan *local_chan; +/* Fast accessors for channel_update fields */ +static u8 *channel_flags_access(const u8 *channel_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`] + */ + /* Note: 2 bytes for `type` field */ + return cast_const(u8 *, &channel_update[2 + 64 + 32 + 8 + 4 + 1]); +} - bool disable; - bool even_if_identical; - bool even_if_too_soon; +static u8 *timestamp_access(const u8 *channel_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`] + */ + /* Note: 2 bytes for `type` field */ + return cast_const(u8 *, &channel_update[2 + 64 + 32 + 8]); +} - u16 cltv_expiry_delta; - struct amount_msat htlc_minimum, htlc_maximum; - u32 fee_base_msat, fee_proportional_millionths; -}; +static bool is_disabled(const u8 *channel_update) +{ + return *channel_flags_access(channel_update) & ROUTING_FLAGS_DISABLED; +} -/* This generates a `channel_update` message for one of our channels. We do - * this here, rather than in `channeld` because we (may) need to do it - * ourselves anyway if channeld dies, or when we refresh it once a week, - * and so we can avoid creating redundant ones. */ -static void update_local_channel(struct local_cupdate *lc /* frees! */) +static bool is_enabled(const u8 *channel_update) { - struct daemon *daemon = lc->daemon; - secp256k1_ecdsa_signature dummy_sig; - u8 *update, *msg; - u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec, next; - u8 message_flags, channel_flags; - struct chan *chan = lc->local_chan->chan; - struct half_chan *hc; - const int direction = lc->local_chan->direction; + return !is_disabled(channel_update); +} - /* Discard existing timer. */ - lc->local_chan->channel_update_timer - = tal_free(lc->local_chan->channel_update_timer); - /* So valgrind doesn't complain */ - memset(&dummy_sig, 0, sizeof(dummy_sig)); +static u32 timestamp_for_update(struct daemon *daemon, + const u32 *prev_timestamp, + bool disable) +{ + u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec; /* Create an unsigned channel_update: we backdate enables, so * we can always send a disable in an emergency. */ - if (!lc->disable) + if (!disable) timestamp -= GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); + if (prev_timestamp) { + /* Timestamps can't go backwards! */ + if (timestamp < *prev_timestamp) + timestamp = *prev_timestamp + 1; + + /* If we ever use set-based propagation, ensuring the toggle + * the lower bit in consecutive timestamps makes it more + * robust. */ + if ((timestamp & 1) == (*prev_timestamp & 1)) + timestamp++; + } + + return timestamp; +} + +static u8 *sign_and_timestamp_update(const tal_t *ctx, + struct daemon *daemon, + const struct chan *chan, + int direction, + u8 *unsigned_update TAKES) +{ + u8 *msg, *update; + be32 timestamp; + const u32 *prev_timestamp; + const struct half_chan *hc = &chan->half[direction]; + + if (is_halfchan_defined(hc)) + prev_timestamp = &hc->bcast.timestamp; + else + prev_timestamp = NULL; + + /* Get an appropriate timestamp */ + timestamp = cpu_to_be32(timestamp_for_update(daemon, + prev_timestamp, + is_disabled(unsigned_update))); + memcpy(timestamp_access(unsigned_update), ×tamp, sizeof(timestamp)); + + /* Note that we treat the hsmd as synchronous. This is simple (no + * callback hell)!, but may need to change to async if we ever want + * remote HSMs */ + if (!wire_sync_write(HSM_FD, + towire_hsmd_cupdate_sig_req(tmpctx, unsigned_update))) { + status_failed(STATUS_FAIL_HSM_IO, "Writing cupdate_sig_req: %s", + strerror(errno)); + } + + msg = wire_sync_read(tmpctx, HSM_FD); + if (!msg || !fromwire_hsmd_cupdate_sig_reply(ctx, msg, &update)) { + status_failed(STATUS_FAIL_HSM_IO, + "Reading cupdate_sig_req: %s", + strerror(errno)); + } + + if (taken(unsigned_update)) + tal_free(unsigned_update); + + return update; +} + +static u8 *create_unsigned_update(const tal_t *ctx, + const struct short_channel_id *scid, + int direction, + bool disable, + u16 cltv_expiry_delta, + struct amount_msat htlc_minimum, + struct amount_msat htlc_maximum, + u32 fee_base_msat, + u32 fee_proportional_millionths) +{ + secp256k1_ecdsa_signature dummy_sig; + u8 message_flags, channel_flags; + + /* So valgrind doesn't complain */ + memset(&dummy_sig, 0, sizeof(dummy_sig)); + /* BOLT #7: * * The `channel_flags` bitfield is used to indicate the direction of @@ -362,7 +450,7 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */) * | 1 | `disable` | Disable the channel. | */ channel_flags = direction; - if (lc->disable) + if (disable) channel_flags |= ROUTING_FLAGS_DISABLED; /* BOLT #7: @@ -376,101 +464,43 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */) */ message_flags = 0 | ROUTING_OPT_HTLC_MAX_MSAT; - /* Convenience variable. */ - hc = &chan->half[direction]; - - /* If we ever use set-based propagation, ensuring the toggle - * the lower bit in consecutive timestamps makes it more - * robust. */ - if (is_halfchan_defined(hc) - && (timestamp & 1) == (hc->bcast.timestamp & 1)) - timestamp++; - - /* We create an update with a dummy signature, and hand to hsmd to get - * it signed. */ - update = towire_channel_update_option_channel_htlc_max(tmpctx, &dummy_sig, + /* We create an update with a dummy signature and timestamp. */ + return towire_channel_update_option_channel_htlc_max(ctx, + &dummy_sig, /* sig set later */ &chainparams->genesis_blockhash, - &chan->scid, - timestamp, + scid, + 0, /* timestamp set later */ message_flags, channel_flags, - lc->cltv_expiry_delta, - lc->htlc_minimum, - lc->fee_base_msat, - lc->fee_proportional_millionths, - lc->htlc_maximum); - - if (is_halfchan_defined(hc)) { - /* Suppress duplicates. */ - if (!lc->even_if_identical - && !cupdate_different(daemon->rstate->gs, hc, update)) { - tal_free(lc); - return; - } - - /* Is it too soon to send another update? */ - next = hc->bcast.timestamp - + GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); - - if (timestamp < next && !lc->even_if_too_soon) { - status_debug("channel_update %s/%u: delaying %u secs", - type_to_string(tmpctx, - struct short_channel_id, - &chan->scid), - direction, - next - timestamp); - lc->local_chan->channel_update_timer - = new_reltimer(&daemon->timers, lc, - time_from_sec(next - timestamp), - update_local_channel, - lc); - /* If local chan vanishes, so does update, and timer. */ - notleak(tal_steal(lc->local_chan, lc)); - return; - } - } - - /* Note that we treat the hsmd as synchronous. This is simple (no - * callback hell)!, but may need to change to async if we ever want - * remote HSMs */ - if (!wire_sync_write(HSM_FD, - towire_hsmd_cupdate_sig_req(tmpctx, update))) { - status_failed(STATUS_FAIL_HSM_IO, "Writing cupdate_sig_req: %s", - strerror(errno)); - } + cltv_expiry_delta, + htlc_minimum, + fee_base_msat, + fee_proportional_millionths, + htlc_maximum); +} - msg = wire_sync_read(tmpctx, HSM_FD); - if (!msg || !fromwire_hsmd_cupdate_sig_reply(tmpctx, msg, &update)) { - status_failed(STATUS_FAIL_HSM_IO, - "Reading cupdate_sig_req: %s", - strerror(errno)); - } +static void apply_update(struct daemon *daemon, + const struct chan *chan, + int direction, + u8 *update TAKES) +{ + u8 *msg; + struct peer *peer = find_peer(daemon, &chan->nodes[!direction]->id); - /* BOLT #7: - * - * The origin node: - *... - * - MAY create a `channel_update` to communicate the channel parameters to the - * channel peer, even though the channel has not yet been announced (i.e. the - * `announce_channel` bit was not set). - */ if (!is_chan_public(chan)) { + /* Save and restore taken state, for handle_channel_update */ + bool update_taken = taken(update); + /* handle_channel_update will not put private updates in the * broadcast list, but we send it direct to the peer (if we * have one connected) now */ - struct peer *peer = find_peer(daemon, - &chan->nodes[!direction]->id); if (peer) queue_peer_msg(peer, update); + + if (update_taken) + take(update); } - /* We feed it into routing.c like any other channel_update; it may - * discard it (eg. non-public channel), but it should not complain - * about it being invalid! __func__ is a magic C constant which - * expands to this function name. */ - msg = handle_channel_update(daemon->rstate, update, - find_peer(daemon, - &chan->nodes[!direction]->id), - NULL, true); + msg = handle_channel_update(daemon->rstate, update, peer, NULL, true); if (msg) status_failed(STATUS_FAIL_INTERNAL_ERROR, "%s: rejected local channel update %s: %s", @@ -481,72 +511,181 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */) * tmpctx, so it's actually OK. */ tal_hex(tmpctx, update), tal_hex(tmpctx, msg)); - - tal_free(lc); } -/* This is a refresh of a local channel: sends an update if one is needed. */ -void refresh_local_channel(struct daemon *daemon, - struct local_chan *local_chan, - bool even_if_identical) +static void sign_timestamp_and_apply_update(struct daemon *daemon, + const struct chan *chan, + int direction, + u8 *update TAKES) { - const struct half_chan *hc; - struct local_cupdate *lc; - u8 *prev; - secp256k1_ecdsa_signature signature; - struct bitcoin_blkid chain_hash; - struct short_channel_id short_channel_id; - u32 timestamp; - u8 message_flags, channel_flags; + update = sign_and_timestamp_update(NULL, daemon, chan, direction, + update); + apply_update(daemon, chan, direction, take(update)); +} - hc = &local_chan->chan->half[local_chan->direction]; +/* We don't want to thrash the gossip network, so we often defer sending an + * update. We track them here. */ +struct deferred_update { + struct daemon *daemon; + /* Off daemon->deferred_updates */ + struct list_node list; + /* Channel it's for (and owner) */ + const struct chan *chan; + int direction; + /* Timer which will fire when it's time to apply. */ + struct oneshot *channel_update_timer; + /* The actual `update_channel` to apply */ + u8 *update; +}; - /* Don't generate a channel_update for an uninitialized channel. */ - if (!is_halfchan_defined(hc)) - return; +static struct deferred_update *find_deferred_update(struct daemon *daemon, + const struct chan *chan) +{ + struct deferred_update *du; - /* If there's an update pending already, force it to apply now. */ - if (local_chan->channel_update_timer) { - lc = reltimer_arg(local_chan->channel_update_timer); - lc->even_if_too_soon = true; - update_local_channel(lc); - /* Free timer */ - local_chan->channel_update_timer - = tal_free(local_chan->channel_update_timer); + list_for_each(&daemon->deferred_updates, du, list) { + if (du->chan == chan) + return du; } + return NULL; +} + +static void destroy_deferred_update(struct deferred_update *du) +{ + list_del(&du->list); +} + +static void apply_deferred_update(struct deferred_update *du) +{ + apply_update(du->daemon, du->chan, du->direction, take(du->update)); + tal_free(du); +} + +static void defer_update(struct daemon *daemon, + u32 delay, + const struct chan *chan, + int direction, + u8 *unsigned_update TAKES) +{ + struct deferred_update *du; + + /* Override any existing one */ + tal_free(find_deferred_update(daemon, chan)); + + /* If chan is gone, so are we. */ + du = tal(chan, struct deferred_update); + du->daemon = daemon; + du->chan = chan; + du->direction = direction; + du->update = sign_and_timestamp_update(du, daemon, chan, direction, + unsigned_update); + if (delay != 0xFFFFFFFF) + du->channel_update_timer = new_reltimer(&daemon->timers, du, + time_from_sec(delay), + apply_deferred_update, + du); + else + du->channel_update_timer = NULL; + list_add_tail(&daemon->deferred_updates, &du->list); + tal_add_destructor(du, destroy_deferred_update); +} + +/* If there is a pending update for this local channel, apply immediately. */ +bool local_channel_update_latest(struct daemon *daemon, struct chan *chan) +{ + struct deferred_update *du; + + du = find_deferred_update(daemon, chan); + if (!du) + return false; + + /* Frees itself */ + apply_deferred_update(du); + return true; +} + +/* Get previous update. */ +static u8 *prev_update(const tal_t *ctx, + struct daemon *daemon, const struct chan *chan, int direction) +{ + u8 *prev; - lc = tal(NULL, struct local_cupdate); - lc->daemon = daemon; - lc->local_chan = local_chan; - lc->even_if_identical = even_if_identical; - lc->even_if_too_soon = false; + if (!is_halfchan_defined(&chan->half[direction])) + return NULL; prev = cast_const(u8 *, gossip_store_get(tmpctx, daemon->rstate->gs, - local_chan->chan->half[local_chan->direction] - .bcast.index)); + chan->half[direction].bcast.index)); /* If it's a private update, unwrap */ - fromwire_gossip_store_private_update(tmpctx, prev, &prev); + if (!fromwire_gossip_store_private_update(ctx, prev, &prev)) + tal_steal(ctx, prev); + return prev; +} + +/* This is a refresh of a local channel (after 13 days). */ +void refresh_local_channel(struct daemon *daemon, + struct chan *chan, int direction) +{ + u16 cltv_expiry_delta; + struct amount_msat htlc_minimum, htlc_maximum; + u32 fee_base_msat, fee_proportional_millionths, timestamp; + u8 *prev, *update; + u8 message_flags, channel_flags; + secp256k1_ecdsa_signature signature; + struct bitcoin_blkid chain_hash; + struct short_channel_id short_channel_id; + + /* If there's a pending update, apply it and we're done. */ + if (local_channel_update_latest(daemon, chan)) + return; + + prev = prev_update(tmpctx, daemon, chan, direction); + if (!prev) + return; if (!fromwire_channel_update_option_channel_htlc_max(prev, &signature, &chain_hash, &short_channel_id, ×tamp, &message_flags, &channel_flags, - &lc->cltv_expiry_delta, - &lc->htlc_minimum, - &lc->fee_base_msat, - &lc->fee_proportional_millionths, - &lc->htlc_maximum)) { + &cltv_expiry_delta, + &htlc_minimum, + &fee_base_msat, + &fee_proportional_millionths, + &htlc_maximum)) { status_broken("Could not decode local channel_update %s!", tal_hex(tmpctx, prev)); - tal_free(lc); return; } - lc->disable = (channel_flags & ROUTING_FLAGS_DISABLED) - || local_chan->local_disabled; - update_local_channel(lc); + /* BOLT #7: + * + * The `channel_flags` bitfield is used to indicate the direction of + * the channel: it identifies the node that this update originated + * from and signals various options concerning the channel. The + * following table specifies the meaning of its individual bits: + * + * | Bit Position | Name | Meaning | + * | ------------- | ----------- | -------------------------------- | + * | 0 | `direction` | Direction this update refers to. | + * | 1 | `disable` | Disable the channel. | + */ + if (direction != (channel_flags & ROUTING_FLAGS_DIRECTION)) { + status_broken("Wrong channel direction %s!", + tal_hex(tmpctx, prev)); + return; + } + + /* Don't refresh disabled channels. */ + if (channel_flags & ROUTING_FLAGS_DISABLED) + return; + + update = create_unsigned_update(NULL, &short_channel_id, direction, + false, cltv_expiry_delta, + htlc_minimum, htlc_maximum, + fee_base_msat, + fee_proportional_millionths); + sign_timestamp_and_apply_update(daemon, chan, direction, take(update)); } /* channeld asks us to update the local channel. */ @@ -555,43 +694,141 @@ bool handle_local_channel_update(struct daemon *daemon, const u8 *msg) { struct short_channel_id scid; - struct local_cupdate *lc = tal(tmpctx, struct local_cupdate); - - lc->daemon = daemon; - lc->even_if_identical = false; - lc->even_if_too_soon = false; + bool disable; + u16 cltv_expiry_delta; + struct amount_msat htlc_minimum, htlc_maximum; + u32 fee_base_msat, fee_proportional_millionths; + struct chan *chan; + int direction; + u8 *unsigned_update; + const struct half_chan *hc; /* FIXME: We should get scid from lightningd when setting up the * connection, so no per-peer daemon can mess with channels other than * its own! */ if (!fromwire_gossipd_local_channel_update(msg, &scid, - &lc->disable, - &lc->cltv_expiry_delta, - &lc->htlc_minimum, - &lc->fee_base_msat, - &lc->fee_proportional_millionths, - &lc->htlc_maximum)) { + &disable, + &cltv_expiry_delta, + &htlc_minimum, + &fee_base_msat, + &fee_proportional_millionths, + &htlc_maximum)) { status_peer_broken(src, "bad local_channel_update %s", tal_hex(tmpctx, msg)); return false; } - lc->local_chan = local_chan_map_get(&daemon->rstate->local_chan_map, - &scid); + chan = get_channel(daemon->rstate, &scid); /* Can theoretically happen if channel just closed. */ - if (!lc->local_chan) { + if (!chan) { status_peer_debug(src, "local_channel_update for unknown %s", type_to_string(tmpctx, struct short_channel_id, &scid)); return true; } - /* Remove soft local_disabled flag, if they're marking it enabled. */ - if (!lc->disable) - local_enable_chan(daemon->rstate, lc->local_chan->chan); + if (!local_direction(daemon->rstate, chan, &direction)) { + status_peer_broken(src, "bad local_channel_update chan %s", + type_to_string(tmpctx, + struct short_channel_id, + &scid)); + return false; + } + + unsigned_update = create_unsigned_update(tmpctx, &scid, direction, + disable, cltv_expiry_delta, + htlc_minimum, htlc_maximum, + fee_base_msat, + fee_proportional_millionths); - /* Apply the update they told us */ - update_local_channel(tal_steal(NULL, lc)); + hc = &chan->half[direction]; + + /* Ignore duplicates. */ + if (is_halfchan_defined(hc) + && !cupdate_different(daemon->rstate->gs, hc, unsigned_update)) + return true; + + /* Too early? Defer (don't worry if it's unannounced). */ + if (hc && is_chan_public(chan)) { + u32 now = time_now().ts.tv_sec; + u32 next_time = hc->bcast.timestamp + + GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip); + if (now < next_time) { + defer_update(daemon, next_time - now, + chan, direction, take(unsigned_update)); + return true; + } + } + + sign_timestamp_and_apply_update(daemon, chan, direction, + take(unsigned_update)); return true; } + +/* Take update, set/unset disabled flag (and update timestamp). + */ +static void set_disable_flag(u8 *channel_update, bool disable) +{ + u8 *channel_flags = channel_flags_access(channel_update); + + if (disable) + *channel_flags |= ROUTING_FLAGS_DISABLED; + else + *channel_flags &= ~ROUTING_FLAGS_DISABLED; +} + +/* We don't immediately disable, to avoid flapping. */ +void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction) +{ + struct deferred_update *du; + u8 *update = prev_update(tmpctx, daemon, chan, direction); + if (!update) + return; + + du = find_deferred_update(daemon, chan); + + /* Will a deferred update disable it already? OK, nothing to do. */ + if (du && is_disabled(du->update)) + return; + + /* OK, we definitely don't want deferred update to re-enable! */ + tal_free(du); + + /* Is it already disabled? */ + if (is_disabled(update)) + return; + + /* This is deferred indefinitely (flushed if needed though) */ + set_disable_flag(update, true); + defer_update(daemon, 0xFFFFFFFF, chan, direction, take(update)); +} + +void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction) +{ + struct deferred_update *du; + u8 *update = prev_update(tmpctx, daemon, chan, direction); + + + if (!update) + return; + + du = find_deferred_update(daemon, chan); + + /* Will a deferred update enable it? If so, apply immediately. */ + if (du && is_enabled(du->update)) { + apply_deferred_update(du); + return; + } + + /* OK, we definitely don't want deferred update to disable! */ + tal_free(du); + + /* Is it already enabled? */ + if (is_enabled(update)) + return; + + /* Apply this enabling update immediately. */ + set_disable_flag(update, false); + sign_timestamp_and_apply_update(daemon, chan, direction, take(update)); +} diff --git a/gossipd/gossip_generation.h b/gossipd/gossip_generation.h index d58f5151e56b..2e7b396f547f 100644 --- a/gossipd/gossip_generation.h +++ b/gossipd/gossip_generation.h @@ -35,10 +35,18 @@ bool nannounce_different(struct gossip_store *gs, /* Should we announce our own node? Called at strategic places. */ void maybe_send_own_node_announce(struct daemon *daemon, bool startup); -/* This is a refresh of a local channel: sends an update if one is needed. */ +/* Flush any pending changes to this channel. */ +bool local_channel_update_latest(struct daemon *daemon, struct chan *chan); + +/* Disable this local channel (lazily) */ +void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction); + +/* Re-enable this local channel */ +void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction); + +/* This is a refresh of a local channel which is > 13 days old. */ void refresh_local_channel(struct daemon *daemon, - struct local_chan *local_chan, - bool even_if_identical); + struct chan *chan, int direction); /* channeld asks us to update the local channel. */ bool handle_local_channel_update(struct daemon *daemon, diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 3fc121b83480..098fe652f345 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -44,15 +44,32 @@ * whole-channel flag which indicates it's not available; we use this when a * peer disconnects, and generate a `channel_update` to tell the world lazily * when someone asks. */ -static void peer_disable_channels(struct daemon *daemon, struct node *node) +static void peer_disable_channels(struct daemon *daemon, const struct node *node) { /* If this peer had a channel with us, mark it disabled. */ struct chan_map_iter i; - struct chan *c; + const struct chan *c; + + for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { + int direction; + if (!local_direction(daemon->rstate, c, &direction)) + continue; + local_disable_chan(daemon, c, direction); + } +} + +/*~ This cancels the soft-disables when the peer reconnects. */ +static void peer_enable_channels(struct daemon *daemon, const struct node *node) +{ + /* If this peer had a channel with us, mark it disabled. */ + struct chan_map_iter i; + const struct chan *c; for (c = first_chan(node, &i); c; c = next_chan(node, &i)) { - if (node_id_eq(&other_node(node, c)->id, &daemon->id)) - local_disable_chan(daemon->rstate, c); + int direction; + if (!local_direction(daemon->rstate, c, &direction)) + continue; + local_enable_chan(daemon, c, direction); } } @@ -267,10 +284,10 @@ static u8 *handle_channel_update_msg(struct peer *peer, const u8 *msg) static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg) { struct short_channel_id scid; - struct local_chan *local_chan; struct chan *chan; const u8 *update; struct routing_state *rstate = peer->daemon->rstate; + int direction; if (!fromwire_gossipd_get_update(msg, &scid)) { status_broken("peer %s sent bad gossip_get_update %s", @@ -280,8 +297,8 @@ static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg) } /* It's possible that the channel has just closed (though v. unlikely) */ - local_chan = local_chan_map_get(&rstate->local_chan_map, &scid); - if (!local_chan) { + chan = get_channel(rstate, &scid); + if (!chan) { status_unusual("peer %s scid %s: unknown channel", type_to_string(tmpctx, struct node_id, &peer->id), type_to_string(tmpctx, struct short_channel_id, @@ -290,18 +307,24 @@ static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg) goto out; } - chan = local_chan->chan; - /* Since we're going to send it out, make sure it's up-to-date. */ - refresh_local_channel(peer->daemon, local_chan, false); + local_channel_update_latest(peer->daemon, chan); + + if (!local_direction(rstate, chan, &direction)) { + status_peer_broken(&peer->id, "Chan %s is not local?", + type_to_string(tmpctx, struct short_channel_id, + &scid)); + update = NULL; + goto out; + } /* It's possible this is zero, if we've never sent a channel_update * for that channel. */ - if (!is_halfchan_defined(&chan->half[local_chan->direction])) + if (!is_halfchan_defined(&chan->half[direction])) update = NULL; else update = gossip_store_get(tmpctx, rstate->gs, - chan->half[local_chan->direction].bcast.index); + chan->half[direction].bcast.index); out: status_peer_debug(&peer->id, "schanid %s: %s update", type_to_string(tmpctx, struct short_channel_id, &scid), @@ -808,6 +831,7 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, const u8 *msg) { struct peer *peer = tal(conn, struct peer); + struct node *node; int fds[2]; int gossip_store_fd; struct gossip_state *gs; @@ -869,6 +893,10 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, /* Free peer if conn closed (destroy_peer closes conn if peer freed) */ tal_steal(peer->dc, peer); + node = get_node(daemon->rstate, &peer->id); + if (node) + peer_enable_channels(daemon, node); + /* This sends the initial timestamp filter. */ seeker_setup_peer_gossip(daemon->seeker, peer); @@ -967,23 +995,6 @@ static struct io_plan *connectd_req(struct io_conn *conn, return io_close(conn); } -/*~ This is our 13-day timer callback for refreshing our channels. This - * was added to the spec because people abandoned their channels without - * closing them. */ -static void gossip_send_keepalive_update(struct daemon *daemon, - struct local_chan *local_chan) -{ - status_debug("Sending keepalive channel_update for %s/%u", - type_to_string(tmpctx, struct short_channel_id, - &local_chan->chan->scid), - local_chan->direction); - - /* As a side-effect, this will create an update which matches the - * local_disabled state */ - refresh_local_channel(daemon, local_chan, true); -} - - /* BOLT #7: * * A node: @@ -1016,11 +1027,13 @@ static void gossip_refresh_network(struct daemon *daemon) struct chan *c; for (c = first_chan(n, &i); c; c = next_chan(n, &i)) { - struct local_chan *local_chan; struct half_chan *hc; + int direction; + + if (!local_direction(daemon->rstate, c, &direction)) + continue; - local_chan = is_local_chan(daemon->rstate, c); - hc = &c->half[local_chan->direction]; + hc = &c->half[direction]; if (!is_halfchan_defined(hc)) { /* Connection is not announced yet, so don't even @@ -1033,12 +1046,12 @@ static void gossip_refresh_network(struct daemon *daemon) continue; } - if (is_chan_local_disabled(daemon->rstate, c)) { - /* Only send keepalives for active connections */ - continue; - } - - gossip_send_keepalive_update(daemon, local_chan); + status_debug("Sending keepalive channel_update" + " for %s/%u", + type_to_string(tmpctx, + struct short_channel_id, + &c->scid), direction); + refresh_local_channel(daemon, c, direction); } } @@ -1060,7 +1073,7 @@ static void gossip_disable_local_channels(struct daemon *daemon) return; for (c = first_chan(local_node, &i); c; c = next_chan(local_node, &i)) - local_disable_chan(daemon->rstate, c); + local_disable_chan(daemon, c, half_chan_idx(local_node, c)); } struct peer *random_peer(struct daemon *daemon, @@ -1244,24 +1257,34 @@ static struct io_plan *get_stripped_cupdate(struct io_conn *conn, struct daemon *daemon, const u8 *msg) { struct short_channel_id scid; - struct local_chan *local_chan; + struct chan *chan; const u8 *stripped_update; if (!fromwire_gossipd_get_stripped_cupdate(msg, &scid)) master_badmsg(WIRE_GOSSIPD_GET_STRIPPED_CUPDATE, msg); - local_chan = local_chan_map_get(&daemon->rstate->local_chan_map, &scid); - if (!local_chan) { + chan = get_channel(daemon->rstate, &scid); + if (!chan) { status_debug("Failed to resolve local channel %s", type_to_string(tmpctx, struct short_channel_id, &scid)); stripped_update = NULL; } else { + int direction; const struct half_chan *hc; + if (!local_direction(daemon->rstate, chan, &direction)) { + status_broken("%s is a non-local channel!", + type_to_string(tmpctx, + struct short_channel_id, + &scid)); + stripped_update = NULL; + goto out; + } + /* Since we're going to use it, make sure it's up-to-date. */ - refresh_local_channel(daemon, local_chan, false); + local_channel_update_latest(daemon, chan); - hc = &local_chan->chan->half[local_chan->direction]; + hc = &chan->half[direction]; if (is_halfchan_defined(hc)) { const u8 *update; @@ -1272,6 +1295,8 @@ static struct io_plan *get_stripped_cupdate(struct io_conn *conn, } else stripped_update = NULL; } + +out: daemon_conn_send(daemon->master, take(towire_gossipd_get_stripped_cupdate_reply(NULL, stripped_update))); @@ -1423,8 +1448,18 @@ static struct io_plan *handle_local_channel_close(struct io_conn *conn, master_badmsg(WIRE_GOSSIPD_LOCAL_CHANNEL_CLOSE, msg); chan = get_channel(rstate, &scid); - if (chan) - local_disable_chan(rstate, chan); + if (chan) { + int direction; + + if (!local_direction(rstate, chan, &direction)) { + status_broken("Non-local channel close %s", + type_to_string(tmpctx, + struct short_channel_id, + &scid)); + } else { + local_disable_chan(daemon, chan, direction); + } + } return daemon_conn_read_next(conn, daemon->master); } @@ -1522,6 +1557,7 @@ int main(int argc, char *argv[]) daemon->node_announce_timer = NULL; daemon->current_blockheight = 0; /* i.e. unknown */ daemon->rates = NULL; + list_head_init(&daemon->deferred_updates); /* Tell the ecdh() function how to talk to hsmd */ ecdh_hsmd_setup(HSM_FD, status_failed); diff --git a/gossipd/gossipd.h b/gossipd/gossipd.h index fe2082c74b26..af1d435ae3e7 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -60,6 +60,9 @@ struct daemon { /* The channel lease rates we're advertising */ const struct lease_rates *rates; + + /* Any of our channel_updates we're deferring. */ + struct list_head deferred_updates; }; struct range_query_reply { diff --git a/gossipd/routing.c b/gossipd/routing.c index 560e1423932d..58b1d5c789b8 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -198,7 +198,6 @@ static void destroy_routing_state(struct routing_state *rstate) /* Free up our htables */ pending_cannouncement_map_clear(&rstate->pending_cannouncements); - local_chan_map_clear(&rstate->local_chan_map); } /* We don't check this when loading from the gossip_store: that would break @@ -226,7 +225,6 @@ static void memleak_help_routing_tables(struct htable *memtable, memleak_remove_htable(memtable, &rstate->nodes->raw); memleak_remove_htable(memtable, &rstate->pending_node_map->raw); memleak_remove_htable(memtable, &rstate->pending_cannouncements.raw); - memleak_remove_htable(memtable, &rstate->local_chan_map.raw); memleak_remove_uintmap(memtable, &rstate->unupdated_chanmap); for (n = node_map_first(rstate->nodes, &nit); @@ -295,7 +293,6 @@ struct routing_state *new_routing_state(const tal_t *ctx, uintmap_init(&rstate->chanmap); uintmap_init(&rstate->unupdated_chanmap); - local_chan_map_init(&rstate->local_chan_map); rstate->num_txout_failures = 0; uintmap_init(&rstate->txout_failures); uintmap_init(&rstate->txout_failures_old); @@ -524,36 +521,6 @@ static void bad_gossip_order(const u8 *msg, details); } -static void destroy_local_chan(struct local_chan *local_chan, - struct routing_state *rstate) -{ - if (!local_chan_map_del(&rstate->local_chan_map, local_chan)) - abort(); -} - -static void maybe_add_local_chan(struct routing_state *rstate, - struct chan *chan) -{ - int direction; - struct local_chan *local_chan; - - if (node_id_eq(&chan->nodes[0]->id, &rstate->local_id)) - direction = 0; - else if (node_id_eq(&chan->nodes[1]->id, &rstate->local_id)) - direction = 1; - else - return; - - local_chan = tal(chan, struct local_chan); - local_chan->chan = chan; - local_chan->direction = direction; - local_chan->local_disabled = false; - local_chan->channel_update_timer = NULL; - - local_chan_map_add(&rstate->local_chan_map, local_chan); - tal_add_destructor2(local_chan, destroy_local_chan, rstate); -} - struct chan *new_chan(struct routing_state *rstate, const struct short_channel_id *scid, const struct node_id *id1, @@ -595,8 +562,6 @@ struct chan *new_chan(struct routing_state *rstate, uintmap_add(&rstate->chanmap, scid->u64, chan); - /* Initialize shadow structure if it's local */ - maybe_add_local_chan(rstate, chan); return chan; } diff --git a/gossipd/routing.h b/gossipd/routing.h index 1a8a08d0cde0..e33d6306116b 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -94,22 +94,6 @@ static inline bool chan_eq_scid(const struct chan *c, HTABLE_DEFINE_TYPE(struct chan, chan_map_scid, hash_scid, chan_eq_scid, chan_map); -/* Container for local channel pointers. */ -static inline const struct short_channel_id *local_chan_map_scid(const struct local_chan *local_chan) -{ - return &local_chan->chan->scid; -} - -static inline bool local_chan_eq_scid(const struct local_chan *local_chan, - const struct short_channel_id *scid) -{ - return short_channel_id_eq(scid, &local_chan->chan->scid); -} - -HTABLE_DEFINE_TYPE(struct local_chan, - local_chan_map_scid, hash_scid, local_chan_eq_scid, - local_chan_map); - /* For a small number of channels (by far the most common) we use a simple * array, with empty buckets NULL. For larger, we use a proper hash table, * with the extra allocation that implies. */ @@ -191,33 +175,13 @@ HTABLE_DEFINE_TYPE(struct pending_cannouncement, panding_cannouncement_map_scid, struct pending_node_map; struct unupdated_channel; -/* Fast versions: if you know n is one end of the channel */ -static inline struct node *other_node(const struct node *n, - const struct chan *chan) +/* If you know n is one end of the channel, get index of src == n */ +static inline int half_chan_idx(const struct node *n, const struct chan *chan) { int idx = (chan->nodes[1] == n); assert(chan->nodes[0] == n || chan->nodes[1] == n); - return chan->nodes[!idx]; -} - -/* If you know n is one end of the channel, get connection src == n */ -static inline struct half_chan *half_chan_from(const struct node *n, - struct chan *chan) -{ - int idx = (chan->nodes[1] == n); - - assert(chan->nodes[0] == n || chan->nodes[1] == n); - return &chan->half[idx]; -} - -/* If you know n is one end of the channel, get index dst == n */ -static inline int half_chan_to(const struct node *n, const struct chan *chan) -{ - int idx = (chan->nodes[1] == n); - - assert(chan->nodes[0] == n || chan->nodes[1] == n); - return !idx; + return idx; } struct routing_state { @@ -255,9 +219,6 @@ struct routing_state { UINTMAP(bool) txout_failures, txout_failures_old; struct oneshot *txout_failure_timer; - /* A map of local channels by short_channel_ids */ - struct local_chan_map local_chan_map; - /* Highest timestamp of gossip we accepted (before now) */ u32 last_timestamp; @@ -427,41 +388,11 @@ bool routing_add_private_channel(struct routing_state *rstate, */ struct timeabs gossip_time_now(const struct routing_state *rstate); -static inline struct local_chan *is_local_chan(struct routing_state *rstate, - const struct chan *chan) -{ - return local_chan_map_get(&rstate->local_chan_map, &chan->scid); -} - /* Would we ratelimit a channel_update with this timestamp? */ bool would_ratelimit_cupdate(struct routing_state *rstate, const struct half_chan *hc, u32 timestamp); -/* Because we can have millions of channels, and we only want a local_disable - * flag on ones connected to us, we keep a separate hashtable for that flag. - */ -static inline bool is_chan_local_disabled(struct routing_state *rstate, - const struct chan *chan) -{ - struct local_chan *local_chan = is_local_chan(rstate, chan); - return local_chan && local_chan->local_disabled; -} - -static inline void local_disable_chan(struct routing_state *rstate, - const struct chan *chan) -{ - struct local_chan *local_chan = is_local_chan(rstate, chan); - local_chan->local_disabled = true; -} - -static inline void local_enable_chan(struct routing_state *rstate, - const struct chan *chan) -{ - struct local_chan *local_chan = is_local_chan(rstate, chan); - local_chan->local_disabled = false; -} - /* Remove channel from store: announcement and any updates. */ void remove_channel_from_store(struct routing_state *rstate, struct chan *chan); diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 473554f3f720..b7bfd6a6896f 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -203,6 +203,15 @@ void json_object_end(struct json_stream *js UNNEEDED) /* Generated stub for json_object_start */ void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) { fprintf(stderr, "json_object_start called!\n"); abort(); } +/* Generated stub for local_channel_update_latest */ +bool local_channel_update_latest(struct daemon *daemon UNNEEDED, struct chan *chan UNNEEDED) +{ fprintf(stderr, "local_channel_update_latest called!\n"); abort(); } +/* Generated stub for local_disable_chan */ +void local_disable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) +{ fprintf(stderr, "local_disable_chan called!\n"); abort(); } +/* Generated stub for local_enable_chan */ +void local_enable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) +{ fprintf(stderr, "local_enable_chan called!\n"); abort(); } /* Generated stub for master_badmsg */ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) { fprintf(stderr, "master_badmsg called!\n"); abort(); } @@ -258,8 +267,7 @@ void query_unknown_node(struct seeker *seeker UNNEEDED, struct peer *peer UNNEED { fprintf(stderr, "query_unknown_node called!\n"); abort(); } /* Generated stub for refresh_local_channel */ void refresh_local_channel(struct daemon *daemon UNNEEDED, - struct local_chan *local_chan UNNEEDED, - bool even_if_identical UNNEEDED) + struct chan *chan UNNEEDED, int direction UNNEEDED) { fprintf(stderr, "refresh_local_channel called!\n"); abort(); } /* Generated stub for remove_channel_from_store */ void remove_channel_from_store(struct routing_state *rstate UNNEEDED, From 63265edca0c5c18b804ec5c98ec4ec53f2e8ad72 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:36:54 +1030 Subject: [PATCH 12/51] gossipd: make request handlers return void. They all returned the next io_plan, but it was always the same. Signed-off-by: Rusty Russell --- gossipd/gossipd.c | 112 ++++++++++++------------------- gossipd/queries.c | 5 +- gossipd/queries.h | 4 +- gossipd/test/run-onion_message.c | 5 +- 4 files changed, 48 insertions(+), 78 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 098fe652f345..f1c57b9e8c1f 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -523,8 +523,7 @@ static u8 *handle_obs2_onion_message(struct peer *peer, const u8 *msg) return NULL; } -static struct io_plan *onionmsg_req(struct io_conn *conn, struct daemon *daemon, - const u8 *msg) +static void onionmsg_req(struct daemon *daemon, const u8 *msg) { struct node_id id; u8 *onionmsg; @@ -546,7 +545,6 @@ static struct io_plan *onionmsg_req(struct io_conn *conn, struct daemon *daemon, omsg = towire_onion_message(NULL, &blinding, onionmsg); queue_peer_msg(peer, take(omsg)); } - return daemon_conn_read_next(conn, daemon->master); } /* Peer sends an onion msg. */ @@ -1099,9 +1097,7 @@ struct peer *random_peer(struct daemon *daemon, } /*~ Parse init message from lightningd: starts the daemon properly. */ -static struct io_plan *gossip_init(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void gossip_init(struct daemon *daemon, const u8 *msg) { u32 *dev_gossip_time; bool dev_fast_gossip, dev_fast_gossip_prune; @@ -1159,12 +1155,9 @@ static struct io_plan *gossip_init(struct io_conn *conn, /* OK, we are ready. */ daemon_conn_send(daemon->master, take(towire_gossipd_init_reply(NULL))); - return daemon_conn_read_next(conn, daemon->master); } -static struct io_plan *new_blockheight(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void new_blockheight(struct daemon *daemon, const u8 *msg) { if (!fromwire_gossipd_new_blockheight(msg, &daemon->current_blockheight)) master_badmsg(WIRE_GOSSIPD_NEW_BLOCKHEIGHT, msg); @@ -1185,27 +1178,20 @@ static struct io_plan *new_blockheight(struct io_conn *conn, tal_arr_remove(&daemon->deferred_txouts, i); i--; } - - return daemon_conn_read_next(conn, daemon->master); } #if DEVELOPER /* Another testing hack */ -static struct io_plan *dev_gossip_suppress(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void dev_gossip_suppress(struct daemon *daemon, const u8 *msg) { if (!fromwire_gossipd_dev_suppress(msg)) master_badmsg(WIRE_GOSSIPD_DEV_SUPPRESS, msg); status_unusual("Suppressing all gossip"); dev_suppress_gossip = true; - return daemon_conn_read_next(conn, daemon->master); } -static struct io_plan *dev_gossip_memleak(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void dev_gossip_memleak(struct daemon *daemon, const u8 *msg) { struct htable *memtable; bool found_leak; @@ -1219,24 +1205,18 @@ static struct io_plan *dev_gossip_memleak(struct io_conn *conn, daemon_conn_send(daemon->master, take(towire_gossipd_dev_memleak_reply(NULL, found_leak))); - return daemon_conn_read_next(conn, daemon->master); } -static struct io_plan *dev_compact_store(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void dev_compact_store(struct daemon *daemon, const u8 *msg) { bool done = gossip_store_compact(daemon->rstate->gs); daemon_conn_send(daemon->master, take(towire_gossipd_dev_compact_store_reply(NULL, done))); - return daemon_conn_read_next(conn, daemon->master); } -static struct io_plan *dev_gossip_set_time(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void dev_gossip_set_time(struct daemon *daemon, const u8 *msg) { u32 time; @@ -1246,15 +1226,12 @@ static struct io_plan *dev_gossip_set_time(struct io_conn *conn, daemon->rstate->gossip_time = tal(daemon->rstate, struct timeabs); daemon->rstate->gossip_time->ts.tv_sec = time; daemon->rstate->gossip_time->ts.tv_nsec = 0; - - return daemon_conn_read_next(conn, daemon->master); } #endif /* DEVELOPER */ /*~ lightningd: so, get me the latest update for this local channel, * so I can include it in an error message. */ -static struct io_plan *get_stripped_cupdate(struct io_conn *conn, - struct daemon *daemon, const u8 *msg) +static void get_stripped_cupdate(struct daemon *daemon, const u8 *msg) { struct short_channel_id scid; struct chan *chan; @@ -1300,13 +1277,11 @@ static struct io_plan *get_stripped_cupdate(struct io_conn *conn, daemon_conn_send(daemon->master, take(towire_gossipd_get_stripped_cupdate_reply(NULL, stripped_update))); - return daemon_conn_read_next(conn, daemon->master); } /*~ We queue incoming channel_announcement pending confirmation from lightningd * that it really is an unspent output. Here's its reply. */ -static struct io_plan *handle_txout_reply(struct io_conn *conn, - struct daemon *daemon, const u8 *msg) +static void handle_txout_reply(struct daemon *daemon, const u8 *msg) { struct short_channel_id scid; u8 *outscript; @@ -1326,16 +1301,12 @@ static struct io_plan *handle_txout_reply(struct io_conn *conn, /* Anywhere we might have announced a channel, we check if it's time to * announce ourselves (ie. if we just announced our own first channel) */ maybe_send_own_node_announce(daemon, false); - - return daemon_conn_read_next(conn, daemon->master); } /*~ lightningd tells us when about a gossip message directly, when told to by * the addgossip RPC call. That's usually used when a plugin gets an update * returned in an payment error. */ -static struct io_plan *inject_gossip(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void inject_gossip(struct daemon *daemon, const u8 *msg) { u8 *goss; const u8 *errmsg; @@ -1374,12 +1345,9 @@ static struct io_plan *inject_gossip(struct io_conn *conn, err_extracted: daemon_conn_send(daemon->master, take(towire_gossipd_addgossip_reply(NULL, err))); - return daemon_conn_read_next(conn, daemon->master); } -static struct io_plan *handle_new_lease_rates(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void handle_new_lease_rates(struct daemon *daemon, const u8 *msg) { struct lease_rates *rates = tal(daemon, struct lease_rates); @@ -1394,15 +1362,11 @@ static struct io_plan *handle_new_lease_rates(struct io_conn *conn, /* Send the update over to the peer */ maybe_send_own_node_announce(daemon, false); - - return daemon_conn_read_next(conn, daemon->master); } /*~ This is where lightningd tells us that a channel's funding transaction has * been spent. */ -static struct io_plan *handle_outpoint_spent(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void handle_outpoint_spent(struct daemon *daemon, const u8 *msg) { struct short_channel_id scid; struct chan *chan; @@ -1424,8 +1388,6 @@ static struct io_plan *handle_outpoint_spent(struct io_conn *conn, * the channel */ free_chan(rstate, chan); } - - return daemon_conn_read_next(conn, daemon->master); } /*~ This is sent by lightningd when it kicks off 'closingd': we disable it @@ -1437,9 +1399,7 @@ static struct io_plan *handle_outpoint_spent(struct io_conn *conn, * channels. This does not send out updates since that's triggered by the peer * connection closing. */ -static struct io_plan *handle_local_channel_close(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +static void handle_local_channel_close(struct daemon *daemon, const u8 *msg) { struct short_channel_id scid; struct chan *chan; @@ -1460,7 +1420,6 @@ static struct io_plan *handle_local_channel_close(struct io_conn *conn, local_disable_chan(daemon, chan, direction); } } - return daemon_conn_read_next(conn, daemon->master); } /*~ This routine handles all the commands from lightningd. */ @@ -1472,40 +1431,53 @@ static struct io_plan *recv_req(struct io_conn *conn, switch (t) { case WIRE_GOSSIPD_INIT: - return gossip_init(conn, daemon, msg); + gossip_init(daemon, msg); + goto done; case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE: - return get_stripped_cupdate(conn, daemon, msg); + get_stripped_cupdate(daemon, msg); + goto done; case WIRE_GOSSIPD_GET_TXOUT_REPLY: - return handle_txout_reply(conn, daemon, msg); + handle_txout_reply(daemon, msg); + goto done; case WIRE_GOSSIPD_OUTPOINT_SPENT: - return handle_outpoint_spent(conn, daemon, msg); + handle_outpoint_spent(daemon, msg); + goto done; case WIRE_GOSSIPD_LOCAL_CHANNEL_CLOSE: - return handle_local_channel_close(conn, daemon, msg); + handle_local_channel_close(daemon, msg); + goto done; case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: - return new_blockheight(conn, daemon, msg); + new_blockheight(daemon, msg); + goto done; case WIRE_GOSSIPD_ADDGOSSIP: - return inject_gossip(conn, daemon, msg); + inject_gossip(daemon, msg); + goto done; case WIRE_GOSSIPD_NEW_LEASE_RATES: - return handle_new_lease_rates(conn, daemon, msg); + handle_new_lease_rates(daemon, msg); + goto done; #if DEVELOPER case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: - return dev_set_max_scids_encode_size(conn, daemon, msg); + dev_set_max_scids_encode_size(daemon, msg); + goto done; case WIRE_GOSSIPD_DEV_SUPPRESS: - return dev_gossip_suppress(conn, daemon, msg); + dev_gossip_suppress(daemon, msg); + goto done; case WIRE_GOSSIPD_DEV_MEMLEAK: - return dev_gossip_memleak(conn, daemon, msg); + dev_gossip_memleak(daemon, msg); + goto done; case WIRE_GOSSIPD_DEV_COMPACT_STORE: - return dev_compact_store(conn, daemon, msg); + dev_compact_store(daemon, msg); + goto done; case WIRE_GOSSIPD_DEV_SET_TIME: - return dev_gossip_set_time(conn, daemon, msg); + dev_gossip_set_time(daemon, msg); + goto done; #else case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: case WIRE_GOSSIPD_DEV_SUPPRESS: @@ -1516,7 +1488,8 @@ static struct io_plan *recv_req(struct io_conn *conn, #endif /* !DEVELOPER */ case WIRE_GOSSIPD_SEND_ONIONMSG: - return onionmsg_req(conn, daemon, msg); + onionmsg_req(daemon, msg); + goto done; /* We send these, we don't receive them */ case WIRE_GOSSIPD_INIT_REPLY: @@ -1532,6 +1505,9 @@ static struct io_plan *recv_req(struct io_conn *conn, /* Master shouldn't give bad requests. */ status_failed(STATUS_FAIL_MASTER_IO, "%i: %s", t, tal_hex(tmpctx, msg)); + +done: + return daemon_conn_read_next(conn, daemon->master); } /* This is called when lightningd closes its connection to us. We simply diff --git a/gossipd/queries.c b/gossipd/queries.c index b46a683b9a8e..ccd8e2dc6cca 100644 --- a/gossipd/queries.c +++ b/gossipd/queries.c @@ -1163,15 +1163,12 @@ bool query_channel_range(struct daemon *daemon, #if DEVELOPER /* This is a testing hack to allow us to artificially lower the maximum bytes * of short_channel_ids we'll encode, using dev_set_max_scids_encode_size. */ -struct io_plan *dev_set_max_scids_encode_size(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +void dev_set_max_scids_encode_size(struct daemon *daemon, const u8 *msg) { if (!fromwire_gossipd_dev_set_max_scids_encode_size(msg, &dev_max_encoding_bytes)) master_badmsg(WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE, msg); status_debug("Set max_scids_encode_bytes to %u", dev_max_encoding_bytes); - return daemon_conn_read_next(conn, daemon->master); } #endif /* DEVELOPER */ diff --git a/gossipd/queries.h b/gossipd/queries.h index 67fbca0c30ee..14ea121ae64e 100644 --- a/gossipd/queries.h +++ b/gossipd/queries.h @@ -62,9 +62,7 @@ struct io_plan *dev_query_channel_range(struct io_conn *conn, /* This is a testing hack to allow us to artificially lower the maximum bytes * of short_channel_ids we'll encode, using dev_set_max_scids_encode_size. */ -struct io_plan *dev_set_max_scids_encode_size(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg); +void dev_set_max_scids_encode_size(struct daemon *daemon, const u8 *msg); #endif /* DEVELOPER */ #endif /* LIGHTNING_GOSSIPD_QUERIES_H */ diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index b7bfd6a6896f..1a4cfd59eb9d 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -18,9 +18,8 @@ int unused_main(int argc, char *argv[]); bool dev_suppress_gossip; /* Generated stub for dev_set_max_scids_encode_size */ -struct io_plan *dev_set_max_scids_encode_size(struct io_conn *conn UNNEEDED, - struct daemon *daemon UNNEEDED, - const u8 *msg UNNEEDED) +void dev_set_max_scids_encode_size(struct daemon *daemon UNNEEDED, + const u8 *msg UNNEEDED) { fprintf(stderr, "dev_set_max_scids_encode_size called!\n"); abort(); } /* Generated stub for dump_memleak */ bool dump_memleak(struct htable *memtable UNNEEDED, From 65beadd77882b95d04d2ed071418eb3e629d798c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:37:54 +1030 Subject: [PATCH 13/51] connectd: rename struct peer in peer_exchange_initmsg to early_peer. We want to have a real (persistent) struct peer eventually. Signed-off-by: Rusty Russell --- connectd/peer_exchange_initmsg.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index d960a83d0587..8110f5a2960f 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -10,7 +10,7 @@ #include /* Temporary structure for us to read peer message in */ -struct peer { +struct early_peer { struct daemon *daemon; /* The ID of the peer */ @@ -38,10 +38,10 @@ static bool contains_common_chain(struct bitcoin_blkid *chains) } /* Here in case we need to read another message. */ -static struct io_plan *read_init(struct io_conn *conn, struct peer *peer); +static struct io_plan *read_init(struct io_conn *conn, struct early_peer *peer); static struct io_plan *peer_init_received(struct io_conn *conn, - struct peer *peer) + struct early_peer *peer) { u8 *msg = cryptomsg_decrypt_body(tmpctx, &peer->cs, peer->msg); u8 *globalfeatures, *features; @@ -89,6 +89,9 @@ static struct io_plan *peer_init_received(struct io_conn *conn, * window where it was: combine the two. */ features = featurebits_or(tmpctx, take(features), globalfeatures); + /* We can dispose of peer after next call. */ + tal_steal(tmpctx, peer); + /* Usually return io_close_taken_fd, but may wait for old peer to * be disconnected if it's a reconnect. */ return peer_connected(conn, peer->daemon, &peer->id, @@ -98,7 +101,7 @@ static struct io_plan *peer_init_received(struct io_conn *conn, } static struct io_plan *peer_init_hdr_received(struct io_conn *conn, - struct peer *peer) + struct early_peer *peer) { u16 len; @@ -111,7 +114,7 @@ static struct io_plan *peer_init_hdr_received(struct io_conn *conn, peer_init_received, peer); } -static struct io_plan *read_init(struct io_conn *conn, struct peer *peer) +static struct io_plan *read_init(struct io_conn *conn, struct early_peer *peer) { /* Free our sent init msg. */ tal_free(peer->msg); @@ -128,14 +131,14 @@ static struct io_plan *read_init(struct io_conn *conn, struct peer *peer) #if DEVELOPER static struct io_plan *peer_write_postclose(struct io_conn *conn, - struct peer *peer) + struct early_peer *peer) { dev_sabotage_fd(io_conn_fd(conn), true); return read_init(conn, peer); } static struct io_plan *peer_write_post_sabotage(struct io_conn *conn, - struct peer *peer) + struct early_peer *peer) { dev_sabotage_fd(io_conn_fd(conn), false); return read_init(conn, peer); @@ -151,8 +154,8 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, bool incoming) { /* If conn is closed, forget peer */ - struct peer *peer = tal(conn, struct peer); - struct io_plan *(*next)(struct io_conn *, struct peer *); + struct early_peer *peer = tal(conn, struct early_peer); + struct io_plan *(*next)(struct io_conn *, struct early_peer *); struct tlv_init_tlvs *tlvs; peer->daemon = daemon; From f28c3f1bcbbdffab7cdcf8bb01e501cd4f9b1126 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:38:54 +1030 Subject: [PATCH 14/51] connectd: keep timeout timer around so we can disable it. connectd will be keeping the conn open, so it needs to free this "conn_timeout" timer. Pass it through, so we can do that. Signed-off-by: Rusty Russell --- connectd/connectd.c | 26 +++++++++++++--------- connectd/handshake.c | 15 ++++++++++++- connectd/handshake.h | 23 ++++++++++++------- connectd/peer_exchange_initmsg.c | 5 +++++ connectd/peer_exchange_initmsg.h | 2 ++ connectd/test/run-initiator-success.c | 3 ++- connectd/test/run-responder-success.c | 3 ++- devtools/gossipwith.c | 4 +++- gossipd/test/run-check_node_announcement.c | 6 ----- gossipd/test/run-crc32_of_update.c | 10 --------- gossipd/test/run-extended-info.c | 4 ---- 11 files changed, 58 insertions(+), 43 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 12adfdc97310..c2482df8261d 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -525,13 +525,14 @@ static struct io_plan *handshake_in_success(struct io_conn *conn, const struct pubkey *id_key, const struct wireaddr_internal *addr, struct crypto_state *cs, + struct oneshot *timeout, 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, true); + cs, &id, addr, timeout, true); } /*~ If the timer goes off, we simply free everything, which hangs up. */ @@ -591,11 +592,12 @@ static struct io_plan *conn_in(struct io_conn *conn, struct conn_in *conn_in_arg) { struct daemon *daemon = conn_in_arg->daemon; + struct oneshot *timeout; - /* If they don't complete handshake in reasonable time, hang up */ - notleak(new_reltimer(&daemon->timers, conn, - time_from_sec(daemon->timeout_secs), - conn_timeout, conn)); + /* If they don't complete handshake in reasonable time, we hang up */ + timeout = new_reltimer(&daemon->timers, conn, + time_from_sec(daemon->timeout_secs), + conn_timeout, conn); /*~ The crypto handshake differs depending on whether you received or * initiated the socket connection, so there are two entry points. @@ -603,7 +605,7 @@ static struct io_plan *conn_in(struct io_conn *conn, * code from thinking `conn` (which we don't keep a pointer to) is * leaked */ return responder_handshake(notleak(conn), &daemon->mykey, - &conn_in_arg->addr, + &conn_in_arg->addr, timeout, handshake_in_success, daemon); } @@ -723,6 +725,7 @@ static struct io_plan *handshake_out_success(struct io_conn *conn, const struct pubkey *key, const struct wireaddr_internal *addr, struct crypto_state *cs, + struct oneshot *timeout, struct connecting *connect) { struct node_id id; @@ -732,12 +735,13 @@ 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, false); + cs, &id, addr, timeout, false); } struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect) { struct pubkey outkey; + struct oneshot *timeout; /* This shouldn't happen: lightningd should not give invalid ids! */ if (!pubkey_from_node_id(&outkey, &connect->id)) { @@ -748,15 +752,15 @@ struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect) } /* If they don't complete handshake in reasonable time, hang up */ - notleak(new_reltimer(&connect->daemon->timers, conn, - time_from_sec(connect->daemon->timeout_secs), - conn_timeout, conn)); + timeout = new_reltimer(&connect->daemon->timers, conn, + time_from_sec(connect->daemon->timeout_secs), + conn_timeout, conn); status_peer_debug(&connect->id, "Connected out, starting crypto"); connect->connstate = "Cryptographic handshake"; return initiator_handshake(conn, &connect->daemon->mykey, &outkey, &connect->addrs[connect->addrnum], - handshake_out_success, connect); + timeout, handshake_out_success, connect); } /*~ When we've exhausted all addresses without success, we come here. diff --git a/connectd/handshake.c b/connectd/handshake.c index 768b4a2a6a6b..1097f6f3d033 100644 --- a/connectd/handshake.c +++ b/connectd/handshake.c @@ -173,11 +173,15 @@ struct handshake { /* Are we initiator or responder. */ enum bolt8_side side; + /* Timeout timer if we take too long. */ + struct oneshot *timeout; + /* Function to call once handshake complete. */ struct io_plan *(*cb)(struct io_conn *conn, const struct pubkey *their_id, const struct wireaddr_internal *wireaddr, struct crypto_state *cs, + struct oneshot *timeout, void *cbarg); void *cbarg; }; @@ -348,10 +352,12 @@ static struct io_plan *handshake_succeeded(struct io_conn *conn, const struct pubkey *their_id, const struct wireaddr_internal *addr, struct crypto_state *cs, + struct oneshot *timeout, void *cbarg); void *cbarg; struct pubkey their_id; struct wireaddr_internal addr; + struct oneshot *timeout; /* BOLT #8: * @@ -377,9 +383,10 @@ static struct io_plan *handshake_succeeded(struct io_conn *conn, cbarg = h->cbarg; their_id = h->their_id; addr = h->addr; + timeout = h->timeout; tal_free(h); - return cb(conn, &their_id, &addr, &cs, cbarg); + return cb(conn, &their_id, &addr, &cs, timeout, cbarg); } static struct handshake *new_handshake(const tal_t *ctx, @@ -956,10 +963,12 @@ static struct io_plan *act_one_responder(struct io_conn *conn, struct io_plan *responder_handshake_(struct io_conn *conn, const struct pubkey *my_id, const struct wireaddr_internal *addr, + struct oneshot *timeout, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, const struct wireaddr_internal *, struct crypto_state *, + struct oneshot *, void *cbarg), void *cbarg) { @@ -970,6 +979,7 @@ struct io_plan *responder_handshake_(struct io_conn *conn, h->addr = *addr; h->cbarg = cbarg; h->cb = cb; + h->timeout = timeout; return act_one_responder(conn, h); } @@ -978,10 +988,12 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, const struct pubkey *my_id, const struct pubkey *their_id, const struct wireaddr_internal *addr, + struct oneshot *timeout, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, const struct wireaddr_internal *, struct crypto_state *, + struct oneshot *timeout, void *cbarg), void *cbarg) { @@ -993,6 +1005,7 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, h->addr = *addr; h->cbarg = cbarg; h->cb = cb; + h->timeout = timeout; return act_one_initiator(conn, h); } diff --git a/connectd/handshake.h b/connectd/handshake.h index 733178bee205..facb7f203250 100644 --- a/connectd/handshake.h +++ b/connectd/handshake.h @@ -6,15 +6,17 @@ struct crypto_state; struct io_conn; struct wireaddr_internal; struct pubkey; +struct oneshot; -#define initiator_handshake(conn, my_id, their_id, addr, cb, cbarg) \ - initiator_handshake_((conn), (my_id), (their_id), (addr), \ +#define initiator_handshake(conn, my_id, their_id, addr, timeout, cb, cbarg) \ + initiator_handshake_((conn), (my_id), (their_id), (addr), (timeout), \ typesafe_cb_preargs(struct io_plan *, void *, \ (cb), (cbarg), \ struct io_conn *, \ const struct pubkey *, \ - const struct wireaddr_internal *, \ - struct crypto_state *), \ + const struct wireaddr_internal *, \ + struct crypto_state *, \ + struct oneshot *), \ (cbarg)) @@ -22,31 +24,36 @@ struct io_plan *initiator_handshake_(struct io_conn *conn, const struct pubkey *my_id, const struct pubkey *their_id, const struct wireaddr_internal *addr, + struct oneshot *timeout, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, const struct wireaddr_internal *, struct crypto_state *, + struct oneshot *timeout, void *cbarg), void *cbarg); -#define responder_handshake(conn, my_id, addr, cb, cbarg) \ - responder_handshake_((conn), (my_id), (addr), \ +#define responder_handshake(conn, my_id, addr, timeout, cb, cbarg) \ + responder_handshake_((conn), (my_id), (addr), (timeout), \ typesafe_cb_preargs(struct io_plan *, void *, \ (cb), (cbarg), \ struct io_conn *, \ const struct pubkey *, \ - const struct wireaddr_internal *, \ - struct crypto_state *), \ + const struct wireaddr_internal *, \ + struct crypto_state *, \ + struct oneshot *), \ (cbarg)) struct io_plan *responder_handshake_(struct io_conn *conn, const struct pubkey *my_id, const struct wireaddr_internal *addr, + struct oneshot *timeout, struct io_plan *(*cb)(struct io_conn *, const struct pubkey *, const struct wireaddr_internal *, struct crypto_state *, + struct oneshot *, void *cbarg), void *cbarg); #endif /* LIGHTNING_CONNECTD_HANDSHAKE_H */ diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index 8110f5a2960f..8106ab92697d 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -151,6 +152,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, const struct crypto_state *cs, const struct node_id *id, const struct wireaddr_internal *addr, + struct oneshot *timeout, bool incoming) { /* If conn is closed, forget peer */ @@ -164,6 +166,9 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, peer->cs = *cs; peer->incoming = incoming; + /* Attach timer to early peer, so it gets freed with it. */ + notleak(tal_steal(peer, timeout)); + /* BOLT #1: * * The sending node: diff --git a/connectd/peer_exchange_initmsg.h b/connectd/peer_exchange_initmsg.h index 6a3c8a24397d..eb654aaa73c0 100644 --- a/connectd/peer_exchange_initmsg.h +++ b/connectd/peer_exchange_initmsg.h @@ -8,6 +8,7 @@ struct daemon; struct io_conn; struct node_id; struct wireaddr_internal; +struct oneshot; /* If successful, calls peer_connected() */ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, @@ -16,6 +17,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, const struct crypto_state *cs, const struct node_id *id, const struct wireaddr_internal *addr, + struct oneshot *timeout, 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 27bb98bc9e03..73e35875f5ce 100644 --- a/connectd/test/run-initiator-success.c +++ b/connectd/test/run-initiator-success.c @@ -278,6 +278,7 @@ static struct io_plan *success(struct io_conn *conn UNUSED, const struct pubkey *them, const struct wireaddr_internal *addr UNUSED, struct crypto_state *cs, + struct oneshot *timeout UNUSED, void *unused UNUSED) { assert(pubkey_eq(them, &rs_pub)); @@ -320,7 +321,7 @@ int main(int argc, char *argv[]) dummy.itype = ADDR_INTERNAL_WIREADDR; dummy.u.wireaddr.addrlen = 0; - initiator_handshake((void *)tmpctx, &ls_pub, &rs_pub, &dummy, success, NULL); + initiator_handshake((void *)tmpctx, &ls_pub, &rs_pub, &dummy, NULL, success, NULL); /* Should not exit! */ abort(); } diff --git a/connectd/test/run-responder-success.c b/connectd/test/run-responder-success.c index 1bf317e3f328..b5de1da5a9e7 100644 --- a/connectd/test/run-responder-success.c +++ b/connectd/test/run-responder-success.c @@ -277,6 +277,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, void *unused UNUSED) { assert(secret_eq_str(&cs->sk, expect_sk)); @@ -314,7 +315,7 @@ int main(int argc, char *argv[]) dummy.itype = ADDR_INTERNAL_WIREADDR; dummy.u.wireaddr.addrlen = 0; - responder_handshake((void *)tmpctx, &ls_pub, &dummy, success, NULL); + responder_handshake((void *)tmpctx, &ls_pub, &dummy, NULL, success, NULL); /* Should not exit! */ abort(); } diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index 0e2093e6764c..66956ca662d3 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -144,6 +144,7 @@ static struct io_plan *handshake_success(struct io_conn *conn, const struct pubkey *them, const struct wireaddr_internal *addr, struct crypto_state *orig_cs, + struct oneshot *timer, char **args) { u8 *msg; @@ -351,7 +352,8 @@ int main(int argc, char *argv[]) if (connect(conn->fd, ai->ai_addr, ai->ai_addrlen) != 0) err(1, "Connecting to %s", at+1); - initiator_handshake(conn, &us, &them, &addr, handshake_success, argv+2); + initiator_handshake(conn, &us, &them, &addr, NULL, + handshake_success, argv+2); exit(0); } diff --git a/gossipd/test/run-check_node_announcement.c b/gossipd/test/run-check_node_announcement.c index ca982558b22f..95b2bdc1930e 100644 --- a/gossipd/test/run-check_node_announcement.c +++ b/gossipd/test/run-check_node_announcement.c @@ -84,15 +84,9 @@ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, struct timerel expire UNNEEDED, void (*cb)(void *) UNNEEDED, void *arg UNNEEDED) { fprintf(stderr, "new_reltimer_ 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 queue_peer_msg */ void queue_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) { fprintf(stderr, "queue_peer_msg called!\n"); abort(); } -/* Generated stub for reltimer_arg */ -void *reltimer_arg(struct oneshot *t UNNEEDED) -{ fprintf(stderr, "reltimer_arg called!\n"); abort(); } /* Generated stub for status_failed */ void status_failed(enum status_failreason code UNNEEDED, const char *fmt UNNEEDED, ...) diff --git a/gossipd/test/run-crc32_of_update.c b/gossipd/test/run-crc32_of_update.c index 87e6094b2aaa..3b7595f16a84 100644 --- a/gossipd/test/run-crc32_of_update.c +++ b/gossipd/test/run-crc32_of_update.c @@ -28,10 +28,6 @@ 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_read_next */ -struct io_plan *daemon_conn_read_next(struct io_conn *conn UNNEEDED, - struct daemon_conn *dc UNNEEDED) -{ fprintf(stderr, "daemon_conn_read_next called!\n"); abort(); } /* Generated stub for daemon_conn_wake */ void daemon_conn_wake(struct daemon_conn *dc UNNEEDED) { fprintf(stderr, "daemon_conn_wake called!\n"); abort(); } @@ -117,9 +113,6 @@ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, struct timerel expire UNNEEDED, void (*cb)(void *) UNNEEDED, void *arg UNNEEDED) { fprintf(stderr, "new_reltimer_ 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 peer *peer UNNEEDED, size_t amount UNNEEDED) { fprintf(stderr, "peer_supplied_good_gossip called!\n"); abort(); } @@ -130,9 +123,6 @@ void queue_peer_from_store(struct peer *peer UNNEEDED, /* Generated stub for queue_peer_msg */ void queue_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) { fprintf(stderr, "queue_peer_msg called!\n"); abort(); } -/* Generated stub for reltimer_arg */ -void *reltimer_arg(struct oneshot *t UNNEEDED) -{ fprintf(stderr, "reltimer_arg called!\n"); abort(); } /* Generated stub for status_failed */ void status_failed(enum status_failreason code UNNEEDED, const char *fmt UNNEEDED, ...) diff --git a/gossipd/test/run-extended-info.c b/gossipd/test/run-extended-info.c index bf0d460a82ed..8e5ad79cd38c 100644 --- a/gossipd/test/run-extended-info.c +++ b/gossipd/test/run-extended-info.c @@ -33,10 +33,6 @@ 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_read_next */ -struct io_plan *daemon_conn_read_next(struct io_conn *conn UNNEEDED, - struct daemon_conn *dc UNNEEDED) -{ fprintf(stderr, "daemon_conn_read_next called!\n"); abort(); } /* Generated stub for daemon_conn_wake */ void daemon_conn_wake(struct daemon_conn *dc UNNEEDED) { fprintf(stderr, "daemon_conn_wake called!\n"); abort(); } From 769b368783744a1cb89b5b3a897f9cd8a4670a8d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:39:54 +1030 Subject: [PATCH 15/51] connectd: maintain connection with peer, shuffle data. Instead of passing the incoming socket to lightningd for the subdaemon, create a new one and simply shuffle data between them, keeping connectd in the loop. For the moment, we don't decrypt at all, just shuffle. This means our buffer code is kind of a hack, but that goes away once we start actually decrypting and understanding message boundaries. Signed-off-by: Rusty Russell --- connectd/Makefile | 1 + connectd/connectd.c | 177 +++++++++++++++++++++--------------- connectd/multiplex.c | 209 +++++++++++++++++++++++++++++++++++++++++++ connectd/multiplex.h | 41 +++++++++ 4 files changed, 356 insertions(+), 72 deletions(-) create mode 100644 connectd/multiplex.c create mode 100644 connectd/multiplex.h diff --git a/connectd/Makefile b/connectd/Makefile index 76cb7079f7ce..343a3624c10f 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -5,6 +5,7 @@ CONNECTD_HEADERS := connectd/connectd_wiregen.h \ connectd/connectd.h \ connectd/peer_exchange_initmsg.h \ connectd/handshake.h \ + connectd/multiplex.h \ connectd/netaddress.h \ connectd/tor_autoservice.h \ connectd/tor.h diff --git a/connectd/connectd.c b/connectd/connectd.c index c2482df8261d..c538118628a0 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -59,13 +60,14 @@ #define INITIAL_WAIT_SECONDS 1 #define MAX_WAIT_SECONDS 300 -/*~ We keep a hash table (ccan/htable) of public keys, which tells us what - * peers are already connected. The HTABLE_DEFINE_TYPE() macro needs a - * keyof() function to extract the key. For this simple use case, that's the - * identity function: */ -static const struct node_id *node_id_keyof(const struct node_id *pc) +/*~ We keep a hash table (ccan/htable) of peers, which tells us what peers are + * already connected (by peer->id). */ + +/*~ The HTABLE_DEFINE_TYPE() macro needs a keyof() function to extract the key: + */ +static const struct node_id *peer_keyof(const struct peer *peer) { - return pc; + return &peer->id; } /*~ We also need to define a hashing function. siphash24 is a fast yet @@ -79,12 +81,19 @@ static size_t node_id_hash(const struct node_id *id) return siphash24(siphash_seed(), id->k, sizeof(id->k)); } -/*~ This defines 'struct node_set' which contains 'struct node_id' pointers. */ -HTABLE_DEFINE_TYPE(struct node_id, - node_id_keyof, +/*~ We also define an equality function: is this element equal to this key? */ +static bool peer_eq_node_id(const struct peer *peer, + const struct node_id *id) +{ + return node_id_eq(&peer->id, id); +} + +/*~ This defines 'struct peer_htable' which contains 'struct peer' pointers. */ +HTABLE_DEFINE_TYPE(struct peer, + peer_keyof, node_id_hash, - node_id_eq, - node_set); + peer_eq_node_id, + peer_htable); /*~ This is the global state, like `struct lightningd *ld` in lightningd. */ struct daemon { @@ -100,7 +109,7 @@ struct daemon { /* Peers that we've handed to `lightningd`, which it hasn't told us * have disconnected. */ - struct node_set peers; + struct peer_htable peers; /* Peers we are trying to reach */ struct list_head connecting; @@ -414,7 +423,7 @@ static struct io_plan *peer_reconnected(struct io_conn *conn, /*~ ccan/io supports waiting on an address: in this case, the key in * the peer set. When someone calls `io_wake()` on that address, it * will call retry_peer_connected above. */ - return io_wait(conn, node_set_get(&daemon->peers, id), + return io_wait(conn, peer_htable_get(&daemon->peers, id), /*~ The notleak() wrapper is a DEVELOPER-mode hack so * that our memory leak detection doesn't consider 'pr' * (which is not referenced from our code) to be a @@ -422,6 +431,49 @@ static struct io_plan *peer_reconnected(struct io_conn *conn, retry_peer_connected, notleak(pr)); } +/*~ When we free a peer, we remove it from the daemon's hashtable */ +static void destroy_peer(struct peer *peer, struct daemon *daemon) +{ + peer_htable_del(&daemon->peers, peer); +} + +/*~ This is where we create a new peer. */ +static struct peer *new_peer(struct daemon *daemon, + const struct node_id *id, + const struct crypto_state *cs, + const u8 *their_features, + struct io_conn *conn STEALS, + int *fd_for_subd) +{ + struct peer *peer = tal(daemon, struct peer); + + peer->id = *id; + peer->pps = new_per_peer_state(peer, cs); + peer->final_msg = NULL; + peer->subd_in = NULL; + peer->peer_in = NULL; + peer->sent_to_subd = NULL; + peer->sent_to_peer = NULL; + peer->peer_outq = msg_queue_new(peer); + peer->subd_outq = msg_queue_new(peer); + + /* Aim for connection to shuffle data back and forth: sets up + * peer->to_subd */ + if (!multiplex_subd_setup(peer, fd_for_subd)) + return tal_free(peer); + + /* If gossipd can't give us a file descriptor, we give up connecting. */ + if (!get_gossipfds(daemon, id, their_features, peer->pps)) { + close(*fd_for_subd); + return tal_free(peer); + } + + peer->to_peer = tal_steal(peer, conn); + peer_htable_add(&daemon->peers, peer); + tal_add_destructor2(peer, destroy_peer, daemon); + return peer; +} + /*~ Note the lack of static: this is called by peer_exchange_initmsg.c once the * INIT messages are exchanged, and also by the retry code above. */ struct io_plan *peer_connected(struct io_conn *conn, @@ -433,11 +485,13 @@ struct io_plan *peer_connected(struct io_conn *conn, bool incoming) { u8 *msg; - struct per_peer_state *pps; + struct peer *peer; int unsup; size_t depender, missing; + int subd_fd; - if (node_set_get(&daemon->peers, id)) + peer = peer_htable_get(&daemon->peers, id); + if (peer) return peer_reconnected(conn, daemon, id, addr, cs, their_features, incoming); @@ -487,35 +541,28 @@ struct io_plan *peer_connected(struct io_conn *conn, conn, find_connecting(daemon, id)->conn); /* This contains the per-peer state info; gossipd fills in pps->gs */ - pps = new_per_peer_state(tmpctx, cs); - - /* If gossipd can't give us a file descriptor, we give up connecting. */ - if (!get_gossipfds(daemon, id, their_features, pps)) + peer = new_peer(daemon, id, cs, their_features, conn, &subd_fd); + /* Only takes over conn if it succeeds. */ + if (!peer) return io_close(conn); /* Create message to tell master peer has connected. */ msg = towire_connectd_peer_connected(NULL, id, addr, incoming, - pps, their_features); + peer->pps, their_features); /*~ daemon_conn is a message queue for inter-daemon communication: we * queue up the `connect_peer_connected` message to tell lightningd * we have connected, and give the peer and gossip fds. */ daemon_conn_send(daemon->master, take(msg)); - /* 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, pps->gossip_fd); - daemon_conn_send_fd(daemon->master, pps->gossip_store_fd); + daemon_conn_send_fd(daemon->master, subd_fd); + daemon_conn_send_fd(daemon->master, peer->pps->gossip_fd); + daemon_conn_send_fd(daemon->master, peer->pps->gossip_store_fd); /* Don't try to close these on freeing. */ - pps->gossip_store_fd = pps->gossip_fd = -1; + peer->pps->gossip_store_fd = peer->pps->gossip_fd = -1; - /*~ Finally, we add it to the set of pubkeys: tal_dup will handle - * take() args for us, by simply tal_steal()ing it. */ - node_set_add(&daemon->peers, tal_dup(daemon, struct node_id, id)); - - /*~ We want to free the connection, but not close the fd (which is - * queued to go to lightningd), so use this variation on io_close: */ - return io_close_taken_fd(conn); + /*~ Now we set up this connection to read/write from subd */ + return multiplex_peer_setup(conn, peer); } /*~ handshake.c's handles setting up the crypto state once we get a connection @@ -1774,14 +1821,14 @@ static void add_gossip_addrs(struct wireaddr_internal **addrs, static void try_connect_peer(struct daemon *daemon, const struct node_id *id, u32 seconds_waited, - struct wireaddr_internal *addrhint) + struct wireaddr_internal *addrhint STEALS) { struct wireaddr_internal *addrs; bool use_proxy = daemon->always_use_proxy; struct connecting *connect; /* Already done? May happen with timer. */ - if (node_set_get(&daemon->peers, id)) + if (peer_htable_get(&daemon->peers, id)) return; /* If we're trying to connect it right now, that's OK. */ @@ -1874,23 +1921,24 @@ static void connect_to_peer(struct daemon *daemon, const u8 *msg) /* A peer is gone: clean things up. */ static void cleanup_dead_peer(struct daemon *daemon, const struct node_id *id) { - struct node_id *node; + struct peer *peer; /* We should stay in sync with lightningd at all times. */ - node = node_set_get(&daemon->peers, id); - if (!node) + peer = peer_htable_get(&daemon->peers, id); + if (!peer) status_failed(STATUS_FAIL_INTERNAL_ERROR, "peer_disconnected unknown peer: %s", type_to_string(tmpctx, struct node_id, id)); - node_set_del(&daemon->peers, node); status_peer_debug(id, "disconnect"); /* Wake up in case there's a reconnecting peer waiting in io_wait. */ - io_wake(node); + io_wake(peer); /* Note: deleting from a htable (a-la node_set_del) does not free it: - * htable doesn't assume it's a tal object at all. */ - tal_free(node); + * htable doesn't assume it's a tal object at all. That's why we have + * a destructor attached to peer (called destroy_peer by + * convention). */ + tal_free(peer); } /* lightningd tells us a peer has disconnected. */ @@ -1904,40 +1952,20 @@ static void peer_disconnected(struct daemon *daemon, const u8 *msg) cleanup_dead_peer(daemon, &id); } -/* lightningd tells us to send a final (usually error) message to peer, then - * disconnect. */ -struct final_msg_data { - struct daemon *daemon; - struct node_id id; -}; - -static void destroy_final_msg_data(struct final_msg_data *f) -{ - cleanup_dead_peer(f->daemon, &f->id); -} - -static struct io_plan *send_final_msg(struct io_conn *conn, u8 *msg) -{ - return io_write(conn, msg, tal_bytelen(msg), io_close_cb, NULL); -} - /* lightningd tells us to send a msg and disconnect. */ static void peer_final_msg(struct io_conn *conn, struct daemon *daemon, const u8 *msg) { + struct peer *peer; struct per_peer_state *pps; - struct final_msg_data *f = tal(NULL, struct final_msg_data); + struct node_id id; u8 *finalmsg; int fds[3]; - f->daemon = daemon; /* pps is allocated off f, so fds are closed when f freed. */ - if (!fromwire_connectd_peer_final_msg(f, msg, &f->id, &pps, &finalmsg)) + if (!fromwire_connectd_peer_final_msg(tmpctx, msg, &id, &pps, &finalmsg)) master_badmsg(WIRE_CONNECTD_PEER_FINAL_MSG, msg); - /* When f is freed, we want to mark node as dead. */ - tal_add_destructor(f, destroy_final_msg_data); - /* Get the fds for this peer. */ io_fd_block(io_conn_fd(conn), true); for (size_t i = 0; i < ARRAY_SIZE(fds); i++) { @@ -1949,16 +1977,20 @@ static void peer_final_msg(struct io_conn *conn, } io_fd_block(io_conn_fd(conn), false); + /* Close fd to ourselves. */ + close(fds[0]); + /* We put peer fd into conn, but pps needs to free the rest */ per_peer_state_set_fds(pps, -1, fds[1], fds[2]); - /* Log and encrypt message for peer. */ - status_peer_io(LOG_IO_OUT, &f->id, finalmsg); - finalmsg = cryptomsg_encrypt_msg(f, &pps->cs, take(finalmsg)); - - /* Organize io loop to write out that message, it will free f - * once closed */ - tal_steal(io_new_conn(daemon, fds[0], send_final_msg, finalmsg), f); + /* This can happen if peer hung up on us. */ + peer = peer_htable_get(&daemon->peers, &id); + if (peer) { + /* Log and encrypt message for peer. */ + status_peer_io(LOG_IO_OUT, &id, finalmsg); + finalmsg = cryptomsg_encrypt_msg(NULL, &pps->cs, take(finalmsg)); + multiplex_final_msg(peer, take(finalmsg)); + } } #if DEVELOPER @@ -1971,6 +2003,7 @@ static void dev_connect_memleak(struct daemon *daemon, const u8 *msg) /* Now delete daemon and those which it has pointers to. */ memleak_remove_region(memtable, daemon, sizeof(daemon)); + memleak_remove_htable(memtable, &daemon->peers.raw); found_leak = dump_memleak(memtable, memleak_status_broken); daemon_conn_send(daemon->master, @@ -2064,7 +2097,7 @@ int main(int argc, char *argv[]) /* Allocate and set up our simple top-level structure. */ daemon = tal(NULL, struct daemon); - node_set_init(&daemon->peers); + peer_htable_init(&daemon->peers); memleak_add_helper(daemon, memleak_daemon_cb); list_head_init(&daemon->connecting); daemon->listen_fds = tal_arr(daemon, struct listen_fd, 0); diff --git a/connectd/multiplex.c b/connectd/multiplex.c new file mode 100644 index 000000000000..e55f2ee0ee7f --- /dev/null +++ b/connectd/multiplex.c @@ -0,0 +1,209 @@ +/*~ This contains all the code to shuffle data between socket to the peer + * itself, and the subdaemons. */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* These four function handle subd->peer */ +static struct io_plan *after_final_msg(struct io_conn *peer_conn, + struct peer *peer) +{ + /* io_close will want to free this itself! */ + assert(peer->to_peer == peer_conn); + tal_steal(NULL, peer_conn); + tal_free(peer); + return io_close(peer_conn); +} + +static struct io_plan *write_to_peer(struct io_conn *peer_conn, + struct peer *peer) +{ + assert(peer->to_peer == peer_conn); + + /* Free last sent one (if any) */ + tal_free(peer->sent_to_peer); + + /* Pop tail of send queue */ + peer->sent_to_peer = msg_dequeue(peer->peer_outq); + + /* Nothing to send? */ + if (!peer->sent_to_peer) { + /* Send final once subd is not longer connected */ + if (peer->final_msg && !peer->to_subd) { + return io_write(peer_conn, + peer->final_msg, + tal_bytelen(peer->final_msg), + after_final_msg, peer); + } + /* Tell them to read again, */ + io_wake(&peer->subd_in); + + /* Wait for them to wake us */ + return msg_queue_wait(peer_conn, peer->peer_outq, + write_to_peer, peer); + } + + return io_write(peer_conn, + peer->sent_to_peer, + tal_bytelen(peer->sent_to_peer), + write_to_peer, peer); +} + +static struct io_plan *read_from_subd(struct io_conn *subd_conn, + struct peer *peer); +static struct io_plan *read_from_subd_done(struct io_conn *subd_conn, + struct peer *peer) +{ + size_t len = ((size_t *)peer->subd_in)[1023]; + assert(peer->to_subd == subd_conn); + + /* Trim to length */ + tal_resize(&peer->subd_in, len); + + /* Tell them to write. */ + msg_enqueue(peer->peer_outq, take(peer->subd_in)); + peer->subd_in = NULL; + /* Wait for them to wake us */ + return io_wait(subd_conn, &peer->subd_in, read_from_subd, peer); +} + +static struct io_plan *read_from_subd(struct io_conn *subd_conn, + struct peer *peer) +{ + /* We stash the length at the end */ + size_t *buf = tal_arr(peer, size_t, 1024); + assert(peer->to_subd == subd_conn); + + peer->subd_in = (u8 *)buf; + return io_read_partial(subd_conn, peer->subd_in, + sizeof(size_t) * 1023, + &buf[1023], + read_from_subd_done, peer); +} + +/* These four function handle peer->subd */ +static struct io_plan *write_to_subd(struct io_conn *subd_conn, + struct peer *peer) +{ + assert(peer->to_subd == subd_conn); + + /* Free last sent one (if any) */ + tal_free(peer->sent_to_subd); + + /* Pop tail of send queue */ + peer->sent_to_subd = msg_dequeue(peer->subd_outq); + + /* Nothing to send? */ + if (!peer->sent_to_subd) { + /* Tell them to read again, */ + io_wake(&peer->peer_in); + + /* Wait for them to wake us */ + return msg_queue_wait(subd_conn, peer->subd_outq, + write_to_subd, peer); + } + + return io_write(subd_conn, + peer->sent_to_subd, + tal_bytelen(peer->sent_to_subd), + write_to_subd, peer); +} + +static struct io_plan *read_from_peer(struct io_conn *peer_conn, + struct peer *peer); +static struct io_plan *read_from_peer_done(struct io_conn *peer_conn, + struct peer *peer) +{ + size_t len = ((size_t *)peer->peer_in)[1023]; + assert(peer->to_peer == peer_conn); + + /* Trim to length */ + tal_resize(&peer->peer_in, len); + + /* Tell them to write. */ + msg_enqueue(peer->subd_outq, take(peer->peer_in)); + peer->peer_in = NULL; + /* Wait for them to wake us */ + return io_wait(peer_conn, &peer->peer_in, read_from_peer, peer); +} + +static struct io_plan *read_from_peer(struct io_conn *peer_conn, + struct peer *peer) +{ + /* We stash the length at the end */ + size_t *buf = tal_arr(peer, size_t, 1024); + assert(peer->to_peer == peer_conn); + + peer->peer_in = (u8 *)buf; + return io_read_partial(peer_conn, peer->peer_in, + sizeof(size_t) * 1023, + &buf[1023], + read_from_peer_done, peer); +} + +static struct io_plan *subd_conn_init(struct io_conn *subd_conn, struct peer *peer) +{ + peer->to_subd = subd_conn; + return io_duplex(subd_conn, + read_from_subd(subd_conn, peer), + write_to_subd(subd_conn, peer)); +} + +static void destroy_subd_conn(struct io_conn *subd_conn, struct peer *peer) +{ + assert(subd_conn == peer->to_subd); + peer->to_subd = NULL; + /* In case they were waiting for this to send final_msg */ + if (peer->final_msg) + msg_wake(peer->peer_outq); +} + +bool multiplex_subd_setup(struct peer *peer, int *fd_for_subd) +{ + int fds[2]; + + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) { + status_broken("Failed to create socketpair: %s", + strerror(errno)); + return false; + } + peer->to_subd = io_new_conn(peer, fds[0], subd_conn_init, peer); + tal_add_destructor2(peer->to_subd, destroy_subd_conn, peer); + *fd_for_subd = fds[1]; + return true; +} + +static void destroy_peer_conn(struct io_conn *peer_conn, struct peer *peer) +{ + assert(peer->to_peer == peer_conn); + peer->to_peer = NULL; + + /* Close internal connections if not already. */ + if (peer->to_subd) + io_close(peer->to_subd); +} + +struct io_plan *multiplex_peer_setup(struct io_conn *peer_conn, + struct peer *peer) +{ + /*~ If conn closes, we close the subd connections and wait for + * lightningd to tell us to close with the peer */ + tal_add_destructor2(peer_conn, destroy_peer_conn, peer); + + return io_duplex(peer_conn, + read_from_peer(peer_conn, peer), + write_to_peer(peer_conn, peer)); +} + +void multiplex_final_msg(struct peer *peer, const u8 *final_msg TAKES) +{ + peer->final_msg = tal_dup_talarr(peer, u8, final_msg); + if (!peer->to_subd) + io_wake(peer->peer_outq); +} diff --git a/connectd/multiplex.h b/connectd/multiplex.h new file mode 100644 index 000000000000..84be1f008b19 --- /dev/null +++ b/connectd/multiplex.h @@ -0,0 +1,41 @@ +#ifndef LIGHTNING_CONNECTD_MULTIPLEX_H +#define LIGHTNING_CONNECTD_MULTIPLEX_H +#include "config.h" +#include +#include +#include + +struct peer { + struct node_id id; + struct per_peer_state *pps; + + /* Connection to the peer */ + struct io_conn *to_peer; + + /* Connection to the subdaemon */ + struct io_conn *to_subd; + + /* Final message to send to peer (and hangup) */ + u8 *final_msg; + + /* Input buffers. */ + u8 *subd_in, *peer_in; + + /* Output buffers. */ + struct msg_queue *subd_outq, *peer_outq; + + /* Sent buffers (for freeing after sending) */ + const u8 *sent_to_subd, *sent_to_peer; +}; + +/* Set up peer->to_subd; sets fd_for_subd to pass to lightningd. */ +bool multiplex_subd_setup(struct peer *peer, int *fd_for_subd); + +/* Take over peer_conn as peer->to_peer */ +struct io_plan *multiplex_peer_setup(struct io_conn *peer_conn, + struct peer *peer); + +/* Send this message to peer and disconnect. */ +void multiplex_final_msg(struct peer *peer, + const u8 *final_msg TAKES); +#endif /* LIGHTNING_CONNECTD_MULTIPLEX_H */ From c40ac7c4dff8fa74481b7202f5eff2d158024235 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:40:54 +1030 Subject: [PATCH 16/51] gossipwith: create our own internal sync_crypto functions. This avoids changes to crypto_sync which are coming in next patch. Signed-off-by: Rusty Russell --- devtools/Makefile | 2 +- devtools/gossipwith.c | 86 ++++++++++++++++++++++++++----------------- 2 files changed, 54 insertions(+), 34 deletions(-) diff --git a/devtools/Makefile b/devtools/Makefile index b4c23f03ac56..e61f928f1161 100644 --- a/devtools/Makefile +++ b/devtools/Makefile @@ -70,7 +70,7 @@ devtools/onion: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS devtools/blindedpath: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) common/blinding.o $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/blindedpath.o common/onion.o common/onionreply.o common/sphinx.o -devtools/gossipwith: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o wire/peer$(EXP)_wiregen.o devtools/gossipwith.o common/cryptomsg.o common/cryptomsg.o common/crypto_sync.o +devtools/gossipwith: $(DEVTOOLS_COMMON_OBJS) $(JSMN_OBJS) $(CCAN_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o wire/peer$(EXP)_wiregen.o devtools/gossipwith.o common/cryptomsg.o common/cryptomsg.o $(DEVTOOLS_OBJS) $(DEVTOOLS_TOOL_OBJS): wire/wire.h diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index 66956ca662d3..3e7f0481a9fd 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -9,12 +9,12 @@ #include #include #include -#include -#include +#include #include #include #include #include +#include #include #include #include @@ -69,23 +69,6 @@ void status_fmt(enum log_level level, { } -#if DEVELOPER -void dev_sabotage_fd(int fd, bool close_fd) -{ - abort(); -} - -void dev_blackhole_fd(int fd) -{ - abort(); -} - -enum dev_disconnect dev_disconnect(int pkt_type) -{ - return DEV_DISCONNECT_NORMAL; -} -#endif - static char *opt_set_network(const char *arg, void *unused) { assert(arg != NULL); @@ -102,11 +85,6 @@ static void opt_show_network(char buf[OPT_SHOW_LEN], const void *unused) snprintf(buf, OPT_SHOW_LEN, "%s", chainparams->network_name); } -void peer_failed_connection_lost(void) -{ - exit(0); -} - void ecdh(const struct pubkey *point, struct secret *ss) { if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey, @@ -140,18 +118,60 @@ static struct io_plan *simple_read(struct io_conn *conn, return next(conn, next_arg); } +static void sync_crypto_write(int peer_fd, struct crypto_state *cs, const void *msg TAKES) +{ + u8 *enc; + + enc = cryptomsg_encrypt_msg(NULL, cs, msg); + + if (!write_all(peer_fd, enc, tal_count(enc))) + exit(1); + tal_free(enc); +} + +static u8 *sync_crypto_read(const tal_t *ctx, int peer_fd, struct crypto_state *cs) +{ + u8 hdr[18], *enc, *dec; + u16 len; + + if (!read_all(peer_fd, hdr, sizeof(hdr))) { + status_debug("Failed reading header: %s", strerror(errno)); + exit(0); + } + + if (!cryptomsg_decrypt_header(cs, hdr, &len)) { + status_debug("Failed hdr decrypt with rn=%"PRIu64, + cs->rn-1); + exit(1); + } + + enc = tal_arr(ctx, u8, len + 16); + if (!read_all(peer_fd, enc, tal_count(enc))) { + status_debug("Failed reading body: %s", strerror(errno)); + exit(1); + } + + dec = cryptomsg_decrypt_body(ctx, cs, enc); + tal_free(enc); + if (!dec) + exit(1); + else + status_peer_io(LOG_IO_IN, NULL, dec); + + return dec; +} + static struct io_plan *handshake_success(struct io_conn *conn, const struct pubkey *them, const struct wireaddr_internal *addr, - struct crypto_state *orig_cs, + struct crypto_state *cs, struct oneshot *timer, char **args) { u8 *msg; - struct per_peer_state *pps = new_per_peer_state(conn, orig_cs); + int peer_fd = io_conn_fd(conn); struct pollfd pollfd[2]; - pps->peer_fd = io_conn_fd(conn); if (initial_sync) set_feature_bit(&features, OPTIONAL_FEATURE(OPT_INITIAL_ROUTING_SYNC)); @@ -165,9 +185,9 @@ static struct io_plan *handshake_success(struct io_conn *conn, } msg = towire_init(NULL, NULL, features, tlvs); - sync_crypto_write(pps, take(msg)); + sync_crypto_write(peer_fd, cs, take(msg)); /* Ignore their init message. */ - tal_free(sync_crypto_read(NULL, pps)); + tal_free(sync_crypto_read(NULL, peer_fd, cs)); tal_free(tlvs); } @@ -176,14 +196,14 @@ static struct io_plan *handshake_success(struct io_conn *conn, else pollfd[0].fd = -1; pollfd[0].events = POLLIN; - pollfd[1].fd = pps->peer_fd; + pollfd[1].fd = peer_fd; pollfd[1].events = POLLIN; while (*args) { u8 *m = tal_hexdata(NULL, *args, strlen(*args)); if (!m) errx(1, "Invalid hexdata '%s'", *args); - sync_crypto_write(pps, take(m)); + sync_crypto_write(peer_fd, cs, take(m)); args++; } @@ -204,10 +224,10 @@ static struct io_plan *handshake_success(struct io_conn *conn, if (!read_all(STDIN_FILENO, msg, tal_bytelen(msg))) err(1, "Only read partial message"); - sync_crypto_write(pps, take(msg)); + sync_crypto_write(peer_fd, cs, take(msg)); } } else if (pollfd[1].revents & POLLIN) { - msg = sync_crypto_read(NULL, pps); + msg = sync_crypto_read(NULL, peer_fd, cs); if (!msg) err(1, "Reading msg"); if (hex) { From a2271cdb7072649e08bdae8a0747792febf4920e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:41:54 +1030 Subject: [PATCH 17/51] connectd: do decryption for peers. We temporarily hack to sync_crypto_write/sync_crypto_read functions to not do any crypto, and do it all in connectd. Signed-off-by: Rusty Russell --- common/crypto_sync.c | 34 ++--------- connectd/connectd.c | 2 - connectd/multiplex.c | 142 +++++++++++++++++++++++++------------------ connectd/multiplex.h | 8 ++- wire/wire_io.h | 2 +- 5 files changed, 95 insertions(+), 93 deletions(-) diff --git a/common/crypto_sync.c b/common/crypto_sync.c index 29d8cd92e89f..58dc8b2a06be 100644 --- a/common/crypto_sync.c +++ b/common/crypto_sync.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) { @@ -19,10 +21,8 @@ void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) bool post_sabotage = false, post_close; int type = fromwire_peektype(msg); #endif - u8 *enc; status_peer_io(LOG_IO_OUT, NULL, msg); - enc = cryptomsg_encrypt_msg(NULL, &pps->cs, msg); #if DEVELOPER switch (dev_disconnect(type)) { @@ -44,9 +44,8 @@ void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) break; } #endif - if (!write_all(pps->peer_fd, enc, tal_count(enc))) + if (!wire_sync_write(pps->peer_fd, msg)) peer_failed_connection_lost(); - tal_free(enc); #if DEVELOPER if (post_sabotage) @@ -101,32 +100,11 @@ void sync_crypto_write_no_delay(struct per_peer_state *pps, u8 *sync_crypto_read(const tal_t *ctx, struct per_peer_state *pps) { - u8 hdr[18], *enc, *dec; - u16 len; - - if (!read_all(pps->peer_fd, hdr, sizeof(hdr))) { - status_debug("Failed reading header: %s", strerror(errno)); - peer_failed_connection_lost(); - } - - if (!cryptomsg_decrypt_header(&pps->cs, hdr, &len)) { - status_debug("Failed hdr decrypt with rn=%"PRIu64, - pps->cs.rn-1); - peer_failed_connection_lost(); - } - - enc = tal_arr(ctx, u8, len + 16); - if (!read_all(pps->peer_fd, enc, tal_count(enc))) { - status_debug("Failed reading body: %s", strerror(errno)); - peer_failed_connection_lost(); - } - - dec = cryptomsg_decrypt_body(ctx, &pps->cs, enc); - tal_free(enc); + u8 *dec = wire_sync_read(ctx, pps->peer_fd); if (!dec) peer_failed_connection_lost(); - else - status_peer_io(LOG_IO_IN, NULL, dec); + + status_peer_io(LOG_IO_IN, NULL, dec); return dec; } diff --git a/connectd/connectd.c b/connectd/connectd.c index c538118628a0..2dc053923cde 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -452,7 +452,6 @@ static struct peer *new_peer(struct daemon *daemon, peer->final_msg = NULL; peer->subd_in = NULL; peer->peer_in = NULL; - peer->sent_to_subd = NULL; peer->sent_to_peer = NULL; peer->peer_outq = msg_queue_new(peer); peer->subd_outq = msg_queue_new(peer); @@ -1988,7 +1987,6 @@ static void peer_final_msg(struct io_conn *conn, if (peer) { /* Log and encrypt message for peer. */ status_peer_io(LOG_IO_OUT, &id, finalmsg); - finalmsg = cryptomsg_encrypt_msg(NULL, &pps->cs, take(finalmsg)); multiplex_final_msg(peer, take(finalmsg)); } } diff --git a/connectd/multiplex.c b/connectd/multiplex.c index e55f2ee0ee7f..fb623c1921ff 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -3,12 +3,20 @@ #include "config.h" #include #include +#include +#include #include #include #include #include #include #include +#include + +void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) +{ + msg_enqueue(peer->peer_outq, msg); +} /* These four function handle subd->peer */ static struct io_plan *after_final_msg(struct io_conn *peer_conn, @@ -21,25 +29,39 @@ static struct io_plan *after_final_msg(struct io_conn *peer_conn, return io_close(peer_conn); } +static struct io_plan *encrypt_and_send(struct peer *peer, + const u8 *msg TAKES, + struct io_plan *(*next) + (struct io_conn *peer_conn, + struct peer *peer)) +{ + /* We free this and the encrypted version in next write_to_peer */ + peer->sent_to_peer = cryptomsg_encrypt_msg(peer, &peer->pps->cs, msg); + return io_write(peer->to_peer, + peer->sent_to_peer, + tal_bytelen(peer->sent_to_peer), + next, peer); +} + static struct io_plan *write_to_peer(struct io_conn *peer_conn, struct peer *peer) { + const u8 *msg; assert(peer->to_peer == peer_conn); /* Free last sent one (if any) */ - tal_free(peer->sent_to_peer); + peer->sent_to_peer = tal_free(peer->sent_to_peer); /* Pop tail of send queue */ - peer->sent_to_peer = msg_dequeue(peer->peer_outq); + msg = msg_dequeue(peer->peer_outq); /* Nothing to send? */ - if (!peer->sent_to_peer) { + if (!msg) { /* Send final once subd is not longer connected */ if (peer->final_msg && !peer->to_subd) { - return io_write(peer_conn, - peer->final_msg, - tal_bytelen(peer->final_msg), - after_final_msg, peer); + return encrypt_and_send(peer, + peer->final_msg, + after_final_msg); } /* Tell them to read again, */ io_wake(&peer->subd_in); @@ -49,10 +71,7 @@ static struct io_plan *write_to_peer(struct io_conn *peer_conn, write_to_peer, peer); } - return io_write(peer_conn, - peer->sent_to_peer, - tal_bytelen(peer->sent_to_peer), - write_to_peer, peer); + return encrypt_and_send(peer, take(msg), write_to_peer); } static struct io_plan *read_from_subd(struct io_conn *subd_conn, @@ -60,15 +79,10 @@ static struct io_plan *read_from_subd(struct io_conn *subd_conn, static struct io_plan *read_from_subd_done(struct io_conn *subd_conn, struct peer *peer) { - size_t len = ((size_t *)peer->subd_in)[1023]; - assert(peer->to_subd == subd_conn); - - /* Trim to length */ - tal_resize(&peer->subd_in, len); - - /* Tell them to write. */ - msg_enqueue(peer->peer_outq, take(peer->subd_in)); + /* Tell them to encrypt & write. */ + queue_peer_msg(peer, take(peer->subd_in)); peer->subd_in = NULL; + /* Wait for them to wake us */ return io_wait(subd_conn, &peer->subd_in, read_from_subd, peer); } @@ -76,32 +90,23 @@ static struct io_plan *read_from_subd_done(struct io_conn *subd_conn, static struct io_plan *read_from_subd(struct io_conn *subd_conn, struct peer *peer) { - /* We stash the length at the end */ - size_t *buf = tal_arr(peer, size_t, 1024); - assert(peer->to_subd == subd_conn); - - peer->subd_in = (u8 *)buf; - return io_read_partial(subd_conn, peer->subd_in, - sizeof(size_t) * 1023, - &buf[1023], - read_from_subd_done, peer); + return io_read_wire(subd_conn, peer, &peer->subd_in, + read_from_subd_done, peer); } /* These four function handle peer->subd */ static struct io_plan *write_to_subd(struct io_conn *subd_conn, struct peer *peer) { + const u8 *msg; assert(peer->to_subd == subd_conn); - /* Free last sent one (if any) */ - tal_free(peer->sent_to_subd); - /* Pop tail of send queue */ - peer->sent_to_subd = msg_dequeue(peer->subd_outq); + msg = msg_dequeue(peer->subd_outq); /* Nothing to send? */ - if (!peer->sent_to_subd) { - /* Tell them to read again, */ + if (!msg) { + /* Tell them to read again. */ io_wake(&peer->peer_in); /* Wait for them to wake us */ @@ -109,42 +114,59 @@ static struct io_plan *write_to_subd(struct io_conn *subd_conn, write_to_subd, peer); } - return io_write(subd_conn, - peer->sent_to_subd, - tal_bytelen(peer->sent_to_subd), - write_to_subd, peer); + return io_write_wire(subd_conn, take(msg), write_to_subd, peer); } -static struct io_plan *read_from_peer(struct io_conn *peer_conn, - struct peer *peer); -static struct io_plan *read_from_peer_done(struct io_conn *peer_conn, +static struct io_plan *read_hdr_from_peer(struct io_conn *peer_conn, + struct peer *peer); +static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, + struct peer *peer) +{ + u8 *decrypted; + + decrypted = cryptomsg_decrypt_body(NULL, &peer->pps->cs, + peer->peer_in); + if (!decrypted) + return io_close(peer_conn); + tal_free(peer->peer_in); + + /* Tell them to write. */ + msg_enqueue(peer->subd_outq, take(decrypted)); + + /* Wait for them to wake us */ + return io_wait(peer_conn, &peer->peer_in, read_hdr_from_peer, peer); +} + +static struct io_plan *read_body_from_peer(struct io_conn *peer_conn, struct peer *peer) { - size_t len = ((size_t *)peer->peer_in)[1023]; - assert(peer->to_peer == peer_conn); + u16 len; - /* Trim to length */ - tal_resize(&peer->peer_in, len); + if (!cryptomsg_decrypt_header(&peer->pps->cs, peer->peer_in, &len)) + return io_close(peer_conn); - /* Tell them to write. */ - msg_enqueue(peer->subd_outq, take(peer->peer_in)); - peer->peer_in = NULL; - /* Wait for them to wake us */ - return io_wait(peer_conn, &peer->peer_in, read_from_peer, peer); + tal_resize(&peer->peer_in, (u32)len + CRYPTOMSG_BODY_OVERHEAD); + return io_read(peer_conn, peer->peer_in, tal_count(peer->peer_in), + read_body_from_peer_done, peer); } -static struct io_plan *read_from_peer(struct io_conn *peer_conn, - struct peer *peer) +static struct io_plan *read_hdr_from_peer(struct io_conn *peer_conn, + struct peer *peer) { - /* We stash the length at the end */ - size_t *buf = tal_arr(peer, size_t, 1024); assert(peer->to_peer == peer_conn); - peer->peer_in = (u8 *)buf; - return io_read_partial(peer_conn, peer->peer_in, - sizeof(size_t) * 1023, - &buf[1023], - read_from_peer_done, peer); + /* BOLT #8: + * + * ### Receiving and Decrypting Messages + * + * In order to decrypt the _next_ message in the network + * stream, the following steps are completed: + * + * 1. Read _exactly_ 18 bytes from the network buffer. + */ + peer->peer_in = tal_arr(peer, u8, CRYPTOMSG_HDR_SIZE); + return io_read(peer_conn, peer->peer_in, CRYPTOMSG_HDR_SIZE, + read_body_from_peer, peer); } static struct io_plan *subd_conn_init(struct io_conn *subd_conn, struct peer *peer) @@ -197,7 +219,7 @@ struct io_plan *multiplex_peer_setup(struct io_conn *peer_conn, tal_add_destructor2(peer_conn, destroy_peer_conn, peer); return io_duplex(peer_conn, - read_from_peer(peer_conn, peer), + read_hdr_from_peer(peer_conn, peer), write_to_peer(peer_conn, peer)); } diff --git a/connectd/multiplex.h b/connectd/multiplex.h index 84be1f008b19..e96982bf8322 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -24,8 +24,8 @@ struct peer { /* Output buffers. */ struct msg_queue *subd_outq, *peer_outq; - /* Sent buffers (for freeing after sending) */ - const u8 *sent_to_subd, *sent_to_peer; + /* Peer sent buffer (for freeing after sending) */ + const u8 *sent_to_peer; }; /* Set up peer->to_subd; sets fd_for_subd to pass to lightningd. */ @@ -38,4 +38,8 @@ struct io_plan *multiplex_peer_setup(struct io_conn *peer_conn, /* Send this message to peer and disconnect. */ void multiplex_final_msg(struct peer *peer, const u8 *final_msg TAKES); + +/* Inject a message into the output stream */ +void queue_peer_msg(struct peer *peer, const u8 *msg TAKES); + #endif /* LIGHTNING_CONNECTD_MULTIPLEX_H */ diff --git a/wire/wire_io.h b/wire/wire_io.h index fd6d773c349e..3dd7e55a1194 100644 --- a/wire/wire_io.h +++ b/wire/wire_io.h @@ -27,7 +27,7 @@ struct io_plan *io_read_wire_(struct io_conn *conn, /* Write message from data (tal_count(data) gives length). data can be take() */ struct io_plan *io_write_wire_(struct io_conn *conn, - const u8 *data, + const u8 *data TAKES, struct io_plan *(*next)(struct io_conn *, void *), void *next_arg); From bc4eff88876f912b84661826e94227b422f0deb2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 15 Dec 2021 12:42:54 +1030 Subject: [PATCH 18/51] peer_io: replace crypto_sync in daemons, use normal wire messages. Now connectd is doing the crypto, we can use normal wire io. We create helper functions to clearly differentiate between "peer" comms and intra-daemon comms though. Signed-off-by: Rusty Russell --- channeld/Makefile | 6 +-- channeld/channeld.c | 52 +++++++++++------------ closingd/Makefile | 8 ++-- closingd/closingd.c | 4 +- common/Makefile | 14 +++---- common/crypto_sync.h | 19 --------- common/peer_failed.c | 4 +- common/{crypto_sync.c => peer_io.c} | 11 +++-- common/peer_io.h | 18 ++++++++ common/read_peer_msg.c | 20 ++++----- openingd/Makefile | 10 ++--- openingd/dualopend.c | 64 ++++++++++++++--------------- openingd/openingd.c | 28 ++++++------- 13 files changed, 128 insertions(+), 130 deletions(-) delete mode 100644 common/crypto_sync.h rename common/{crypto_sync.c => peer_io.c} (89%) create mode 100644 common/peer_io.h diff --git a/channeld/Makefile b/channeld/Makefile index 6f26ef416219..4b660bb64325 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -41,7 +41,6 @@ CHANNELD_COMMON_OBJS := \ common/channel_id.o \ common/channel_type.o \ common/crypto_state.o \ - common/crypto_sync.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ @@ -50,9 +49,10 @@ CHANNELD_COMMON_OBJS := \ common/ecdh_hsmd.o \ common/features.o \ common/fee_states.o \ - common/status_wiregen.o \ - common/peer_status_wiregen.o \ common/gossip_rcvd_filter.o \ + common/peer_io.o \ + common/peer_status_wiregen.o \ + common/status_wiregen.o \ common/gossip_store.o \ common/hmac.o \ common/htlc_state.o \ diff --git a/channeld/channeld.c b/channeld/channeld.c index de1a4741bf59..86d5f015b656 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -270,7 +270,7 @@ static void maybe_send_stfu(struct peer *peer) if (!peer->stfu_sent[LOCAL] && !pending_updates(peer->channel, LOCAL, false)) { u8 *msg = towire_stfu(NULL, &peer->channel_id, peer->stfu_initiator == LOCAL); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); peer->stfu_sent[LOCAL] = true; } @@ -517,7 +517,7 @@ static void send_announcement_signatures(struct peer *peer) NULL, &peer->channel_id, &peer->short_channel_ids[LOCAL], &peer->announcement_node_sigs[LOCAL], &peer->announcement_bitcoin_sigs[LOCAL]); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } /* Tentatively create a channel_announcement, possibly with invalid @@ -971,7 +971,7 @@ static void maybe_send_shutdown(struct peer *peer) msg = towire_shutdown(NULL, &peer->channel_id, peer->final_scriptpubkey, tlvs); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); peer->send_shutdown = false; peer->shutdown_sent[LOCAL] = true; billboard_update(peer); @@ -1124,7 +1124,7 @@ static void send_ping(struct peer *peer) exit(0); } - sync_crypto_write_no_delay(peer->pps, take(make_ping(NULL, 1, 0))); + peer_write_no_delay(peer->pps, take(make_ping(NULL, 1, 0))); peer->expecting_pong = PONG_EXPECTED_PROBING; set_ping_timer(peer); } @@ -1326,7 +1326,7 @@ static void send_commit(struct peer *peer) msg = towire_update_fee(NULL, &peer->channel_id, feerate_target); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } } @@ -1342,7 +1342,7 @@ static void send_commit(struct peer *peer) &peer->channel_id, our_blockheight); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } } @@ -1416,7 +1416,7 @@ static void send_commit(struct peer *peer) msg = towire_commitment_signed(NULL, &peer->channel_id, &commit_sig.s, raw_sigs(tmpctx, htlc_sigs)); - sync_crypto_write_no_delay(peer->pps, take(msg)); + peer_write_no_delay(peer->pps, take(msg)); maybe_send_shutdown(peer); @@ -1584,7 +1584,7 @@ static void send_revocation(struct peer *peer, WIRE_CHANNELD_GOT_COMMITSIG_REPLY); /* Now we can finally send revoke_and_ack to peer */ - sync_crypto_write_no_delay(peer->pps, take(msg)); + peer_write_no_delay(peer->pps, take(msg)); } static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) @@ -2361,7 +2361,7 @@ static void resend_revoke(struct peer *peer) struct pubkey point; /* Current commit is peer->next_index[LOCAL]-1, revoke prior */ u8 *msg = make_revocation_msg(peer, peer->next_index[LOCAL]-2, &point); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } static void send_fail_or_fulfill(struct peer *peer, const struct htlc *h) @@ -2387,7 +2387,7 @@ static void send_fail_or_fulfill(struct peer *peer, const struct htlc *h) peer_failed_warn(peer->pps, &peer->channel_id, "HTLC %"PRIu64" state %s not failed/fulfilled", h->id, htlc_state_name(h->state)); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } static int cmp_changed_htlc_id(const struct changed_htlc *a, @@ -2490,7 +2490,7 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) , tlvs #endif ); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } } @@ -2498,12 +2498,12 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) if (peer->channel->opener == LOCAL) { msg = towire_update_fee(NULL, &peer->channel_id, channel_feerate(peer->channel, REMOTE)); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); if (peer->channel->lease_expiry > 0) { msg = towire_update_blockheight(NULL, &peer->channel_id, channel_blockheight(peer->channel, REMOTE)); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } } @@ -2517,7 +2517,7 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) msg = towire_commitment_signed(NULL, &peer->channel_id, &commit_sig.s, raw_sigs(tmpctx, htlc_sigs)); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); /* If we have already received the revocation for the previous, the * other side shouldn't be asking for a retransmit! */ @@ -2899,7 +2899,7 @@ static void peer_reconnect(struct peer *peer, ); } - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); peer_billboard(false, "Sent reestablish, waiting for theirs"); bool soft_error = peer->funding_locked[REMOTE] @@ -2917,7 +2917,7 @@ static void peer_reconnect(struct peer *peer, * before we've reestablished channel). */ do { clean_tmpctx(); - msg = sync_crypto_read(tmpctx, peer->pps); + msg = peer_read(tmpctx, peer->pps); } while (channeld_handle_custommsg(msg) || handle_peer_gossip_or_error(peer->pps, &peer->channel_id, soft_error, msg) || @@ -3003,7 +3003,7 @@ static void peer_reconnect(struct peer *peer, msg = towire_funding_locked(NULL, &peer->channel_id, &peer->next_local_per_commit); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } /* Note: next_index is the index of the current commit we're working @@ -3305,7 +3305,7 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) msg = towire_funding_locked(NULL, &peer->channel_id, &peer->next_local_per_commit); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); peer->funding_locked[LOCAL] = true; } @@ -3371,7 +3371,7 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) , tlvs #endif ); - sync_crypto_write(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); start_commit_timer(peer); /* Tell the master. */ msg = towire_channeld_offer_htlc_reply(NULL, peer->htlc_id, @@ -3604,7 +3604,7 @@ static void handle_send_error(struct peer *peer, const u8 *msg) if (!fromwire_channeld_send_error(msg, msg, &reason)) master_badmsg(WIRE_CHANNELD_SEND_ERROR, msg); status_debug("Send error reason: %s", reason); - sync_crypto_write(peer->pps, + peer_write(peer->pps, take(towire_errorfmt(NULL, &peer->channel_id, "%s", reason))); @@ -3632,7 +3632,7 @@ static void handle_send_ping(struct peer *peer, const u8 *msg) if (tal_count(ping) > 65535) status_failed(STATUS_FAIL_MASTER_IO, "Oversize ping"); - sync_crypto_write_no_delay(peer->pps, take(ping)); + peer_write_no_delay(peer->pps, take(ping)); /* Since we're doing this manually, kill and restart timer. */ status_debug("sending ping expecting %sresponse", @@ -3714,7 +3714,7 @@ static void channeld_send_custommsg(struct peer *peer, const u8 *msg) u8 *inner; if (!fromwire_custommsg_out(tmpctx, msg, &inner)) master_badmsg(WIRE_CUSTOMMSG_OUT, msg); - sync_crypto_write(peer->pps, take(inner)); + peer_write(peer->pps, take(inner)); } static void req_in(struct peer *peer, const u8 *msg) @@ -4012,7 +4012,7 @@ static void init_channel(struct peer *peer) /* If we have a messages to send, send them immediately */ if (fwd_msg) - sync_crypto_write(peer->pps, take(fwd_msg)); + peer_write(peer->pps, take(fwd_msg)); /* Reenable channel */ channel_announcement_negotiate(peer); @@ -4025,7 +4025,7 @@ 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)); + peer_write(peer->pps, take(msg)); } int main(int argc, char *argv[]) @@ -4146,7 +4146,7 @@ int main(int argc, char *argv[]) req_in(peer, msg); } else if (FD_ISSET(peer->pps->peer_fd, &rfds)) { /* This could take forever, but who cares? */ - msg = sync_crypto_read(tmpctx, peer->pps); + msg = peer_read(tmpctx, peer->pps); peer_in(peer, msg); } else if (FD_ISSET(peer->pps->gossip_fd, &rfds)) { msg = wire_sync_read(tmpctx, peer->pps->gossip_fd); diff --git a/closingd/Makefile b/closingd/Makefile index 6fca67f75303..d641d78574a6 100644 --- a/closingd/Makefile +++ b/closingd/Makefile @@ -27,14 +27,11 @@ CLOSINGD_COMMON_OBJS := \ common/channel_id.o \ common/close_tx.o \ common/crypto_state.o \ - common/crypto_sync.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ - common/dev_disconnect.o \ common/derive_basepoints.o \ - common/peer_status_wiregen.o \ - common/status_wiregen.o \ + common/dev_disconnect.o \ common/gossip_rcvd_filter.o \ common/gossip_store.o \ common/htlc_wire.o \ @@ -45,11 +42,14 @@ CLOSINGD_COMMON_OBJS := \ common/onionreply.o \ common/peer_billboard.o \ common/peer_failed.o \ + common/peer_io.o \ + common/peer_status_wiregen.o \ common/per_peer_state.o \ common/permute_tx.o \ common/ping.o \ common/psbt_open.o \ common/pseudorand.o \ + common/status_wiregen.o \ common/read_peer_msg.o \ common/setup.o \ common/socket_close.o \ diff --git a/closingd/closingd.c b/closingd/closingd.c index b3f54e3b7dfb..84dc438b5d8b 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -6,12 +6,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -214,7 +214,7 @@ static void send_offer(struct per_peer_state *pps, msg = towire_closing_signed(NULL, channel_id, fee_to_offer, &our_sig.s, close_tlvs); - sync_crypto_write(pps, take(msg)); + peer_write(pps, take(msg)); } static void tell_master_their_offer(const struct bitcoin_signature *their_sig, diff --git a/common/Makefile b/common/Makefile index 2f5368ad6f6a..d4f9ae8d372a 100644 --- a/common/Makefile +++ b/common/Makefile @@ -9,8 +9,8 @@ COMMON_SRC_NOGEN := \ common/bigsize.c \ common/billboard.c \ common/bip32.c \ - common/blinding.c \ common/blindedpath.c \ + common/blinding.c \ common/blockheight_states.c \ common/bolt11.c \ common/bolt11_json.c \ @@ -19,11 +19,10 @@ COMMON_SRC_NOGEN := \ common/channel_config.c \ common/channel_id.c \ common/channel_type.c \ - common/coin_mvt.c \ common/close_tx.c \ + common/coin_mvt.c \ common/configdir.c \ common/crypto_state.c \ - common/crypto_sync.c \ common/cryptomsg.c \ common/daemon.c \ common/daemon_conn.c \ @@ -38,6 +37,7 @@ COMMON_SRC_NOGEN := \ common/fp16.c \ common/gossip_rcvd_filter.c \ common/gossip_store.c \ + common/gossmap.c \ common/hash_u5.c \ common/hmac.c \ common/hsm_encryption.c \ @@ -54,7 +54,6 @@ COMMON_SRC_NOGEN := \ common/json_tok.c \ common/key_derive.c \ common/keyset.c \ - common/gossmap.c \ common/lease_rates.c \ common/memleak.c \ common/msg_queue.c \ @@ -62,15 +61,16 @@ COMMON_SRC_NOGEN := \ common/onion.c \ common/onionreply.c \ common/param.c \ - common/penalty_base.c \ - common/per_peer_state.c \ common/peer_billboard.c \ common/peer_failed.c \ + common/peer_io.c \ + common/penalty_base.c \ + common/per_peer_state.c \ common/permute_tx.c \ common/ping.c \ + common/private_channel_announcement.c \ common/psbt_internal.c \ common/psbt_open.c \ - common/private_channel_announcement.c \ common/pseudorand.c \ common/random_select.c \ common/read_peer_msg.c \ diff --git a/common/crypto_sync.h b/common/crypto_sync.h deleted file mode 100644 index 29816289d9df..000000000000 --- a/common/crypto_sync.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef LIGHTNING_COMMON_CRYPTO_SYNC_H -#define LIGHTNING_COMMON_CRYPTO_SYNC_H -#include "config.h" -#include -#include - -struct per_peer_state; - -/* Exits with peer_failed_connection_lost() if write fails. */ -void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES); - -/* Same, but disabled nagle for this message. */ -void sync_crypto_write_no_delay(struct per_peer_state *pps, - const void *msg TAKES); - -/* Exits with peer_failed_connection_lost() if can't read packet. */ -u8 *sync_crypto_read(const tal_t *ctx, struct per_peer_state *pps); - -#endif /* LIGHTNING_COMMON_CRYPTO_SYNC_H */ diff --git a/common/peer_failed.c b/common/peer_failed.c index 97ec96cfab31..909161b650c3 100644 --- a/common/peer_failed.c +++ b/common/peer_failed.c @@ -2,9 +2,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -38,7 +38,7 @@ peer_failed(struct per_peer_state *pps, } else { msg = towire_errorfmt(desc, channel_id, "%s", desc); } - sync_crypto_write(pps, msg); + peer_write(pps, msg); /* Tell master the error so it can re-xmit. */ msg = towire_status_peer_error(NULL, channel_id, diff --git a/common/crypto_sync.c b/common/peer_io.c similarity index 89% rename from common/crypto_sync.c rename to common/peer_io.c index 58dc8b2a06be..43b9a027e18f 100644 --- a/common/crypto_sync.c +++ b/common/peer_io.c @@ -1,9 +1,9 @@ #include "config.h" #include -#include #include #include #include +#include #include #include #include @@ -15,7 +15,7 @@ #include #include -void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) +void peer_write(struct per_peer_state *pps, const void *msg TAKES) { #if DEVELOPER bool post_sabotage = false, post_close; @@ -64,8 +64,7 @@ void sync_crypto_write(struct per_peer_state *pps, const void *msg TAKES) * afterwards. Even if this is wrong on other non-Linux platforms, it * only means one extra packet. */ -void sync_crypto_write_no_delay(struct per_peer_state *pps, - const void *msg TAKES) +void peer_write_no_delay(struct per_peer_state *pps, const void *msg TAKES) { int val; int opt; @@ -92,13 +91,13 @@ void sync_crypto_write_no_delay(struct per_peer_state *pps, complained = true; } } - sync_crypto_write(pps, msg); + peer_write(pps, msg); val = 0; setsockopt(pps->peer_fd, IPPROTO_TCP, opt, &val, sizeof(val)); } -u8 *sync_crypto_read(const tal_t *ctx, struct per_peer_state *pps) +u8 *peer_read(const tal_t *ctx, struct per_peer_state *pps) { u8 *dec = wire_sync_read(ctx, pps->peer_fd); if (!dec) diff --git a/common/peer_io.h b/common/peer_io.h new file mode 100644 index 000000000000..0ca6670acde1 --- /dev/null +++ b/common/peer_io.h @@ -0,0 +1,18 @@ +#ifndef LIGHTNING_COMMON_PEER_IO_H +#define LIGHTNING_COMMON_PEER_IO_H +#include "config.h" +#include +#include + +struct per_peer_state; + +/* Exits with peer_failed_connection_lost() if write fails. */ +void peer_write(struct per_peer_state *pps, const void *msg TAKES); + +/* Same, but disabled nagle for this message. */ +void peer_write_no_delay(struct per_peer_state *pps, const void *msg TAKES); + +/* Exits with peer_failed_connection_lost() if can't read packet. */ +u8 *peer_read(const tal_t *ctx, struct per_peer_state *pps); + +#endif /* LIGHTNING_COMMON_PEER_IO_H */ diff --git a/common/read_peer_msg.c b/common/read_peer_msg.c index f40c15c46829..a1c0405e49a4 100644 --- a/common/read_peer_msg.c +++ b/common/read_peer_msg.c @@ -1,10 +1,10 @@ #include "config.h" #include #include -#include #include #include #include +#include #include #include #include @@ -49,7 +49,7 @@ u8 *peer_or_gossip_sync_read(const tal_t *ctx, } if (FD_ISSET(pps->peer_fd, &readfds)) { - msg = sync_crypto_read(ctx, pps); + msg = peer_read(ctx, pps); *from_gossipd = false; return msg; } @@ -121,10 +121,10 @@ void handle_gossip_msg(struct per_peer_state *pps, const u8 *msg TAKES) /* Gossipd can send us gossip messages, OR warnings */ if (fromwire_peektype(gossip) == WIRE_WARNING) { - sync_crypto_write(pps, gossip); + peer_write(pps, gossip); peer_failed_connection_lost(); } else { - sync_crypto_write(pps, gossip); + peer_write(pps, gossip); } } @@ -141,11 +141,11 @@ bool handle_timestamp_filter(struct per_peer_state *pps, const u8 *msg TAKES) } if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain_hash)) { - sync_crypto_write(pps, - take(towire_warningfmt(NULL, NULL, - "gossip_timestamp_filter" - " for bad chain: %s", - tal_hex(tmpctx, take(msg))))); + peer_write(pps, + take(towire_warningfmt(NULL, NULL, + "gossip_timestamp_filter" + " for bad chain: %s", + tal_hex(tmpctx, take(msg))))); return true; } @@ -181,7 +181,7 @@ bool handle_peer_gossip_or_error(struct per_peer_state *pps, return true; else if (check_ping_make_pong(NULL, msg, &pong)) { if (pong) - sync_crypto_write(pps, take(pong)); + peer_write(pps, take(pong)); return true; } else if (is_msg_for_gossipd(msg)) { if (is_msg_gossip_broadcast(msg)) diff --git a/openingd/Makefile b/openingd/Makefile index 091f51ca1790..0ff843e47a7f 100644 --- a/openingd/Makefile +++ b/openingd/Makefile @@ -42,7 +42,6 @@ OPENINGD_COMMON_OBJS := \ common/channel_id.o \ common/channel_type.o \ common/crypto_state.o \ - common/crypto_sync.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ @@ -50,8 +49,6 @@ OPENINGD_COMMON_OBJS := \ common/dev_disconnect.o \ common/features.o \ common/fee_states.o \ - common/status_wiregen.o \ - common/peer_status_wiregen.o \ common/gossip_rcvd_filter.o \ common/gossip_store.o \ common/htlc_state.o \ @@ -65,10 +62,12 @@ OPENINGD_COMMON_OBJS := \ common/msg_queue.o \ common/node_id.o \ common/onionreply.o \ - common/penalty_base.o \ - common/per_peer_state.o \ common/peer_billboard.o \ common/peer_failed.o \ + common/peer_io.o \ + common/peer_status_wiregen.o \ + common/penalty_base.o \ + common/per_peer_state.o \ common/permute_tx.o \ common/ping.o \ common/psbt_internal.o \ @@ -79,6 +78,7 @@ OPENINGD_COMMON_OBJS := \ common/shutdown_scriptpubkey.o \ common/status.o \ common/status_wire.o \ + common/status_wiregen.o \ common/subdaemon.o \ common/type_to_string.o \ common/utils.o \ diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 7711f6224da2..d6c4fa4fb952 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -28,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -392,7 +392,7 @@ static void send_shutdown(struct state *state, const u8 *final_scriptpubkey) /* FIXME: send wrong_funding */ msg = towire_shutdown(NULL, &state->channel_id, final_scriptpubkey, NULL); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); state->shutdown_sent[LOCAL] = true; } @@ -898,7 +898,7 @@ static void dualopend_send_custommsg(struct state *state, const u8 *msg) u8 *inner; if (!fromwire_custommsg_out(tmpctx, msg, &inner)) master_badmsg(WIRE_CUSTOMMSG_OUT, msg); - sync_crypto_write(state->pps, take(inner)); + peer_write(state->pps, take(inner)); } static u8 *psbt_to_tx_sigs_msg(const tal_t *ctx, @@ -1037,7 +1037,7 @@ static void handle_send_tx_sigs(struct state *state, const u8 *msg) /* Send our sigs to peer */ msg = psbt_to_tx_sigs_msg(tmpctx, state, tx_state->psbt); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); /* Notify lightningd that we've sent sigs */ wire_sync_write(REQ_FD, take(towire_dualopend_tx_sigs_sent(NULL))); @@ -1109,7 +1109,7 @@ static bool send_next(struct state *state, } sendmsg: - sync_crypto_write(state->pps, msg); + peer_write(state->pps, msg); return !finished; } @@ -1242,10 +1242,10 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) peer_wire_name(fromwire_peektype(msg)), type_to_string(tmpctx, struct channel_id, &actual)); - sync_crypto_write(state->pps, - take(towire_errorfmt(NULL, &actual, - "Multiple channels" - " unsupported"))); + peer_write(state->pps, + take(towire_errorfmt(NULL, &actual, + "Multiple channels" + " unsupported"))); tal_free(msg); continue; } @@ -1971,10 +1971,10 @@ static u8 *accepter_commits(struct state *state, master_badmsg(WIRE_DUALOPEND_SEND_TX_SIGS, msg); /* Send our commitment sigs over now */ - sync_crypto_write(state->pps, - take(towire_commitment_signed(NULL, - &state->channel_id, - &local_sig.s, NULL))); + peer_write(state->pps, + take(towire_commitment_signed(NULL, + &state->channel_id, + &local_sig.s, NULL))); return msg; } @@ -2331,7 +2331,7 @@ static void accepter_start(struct state *state, const u8 *oc2_msg) &state->our_points.revocation, &state->their_points.revocation); - sync_crypto_write(state->pps, msg); + peer_write(state->pps, msg); peer_billboard(false, "channel open: accept sent, waiting for reply"); /* This is unused in this flow. We re-use @@ -2534,7 +2534,7 @@ static u8 *opener_commits(struct state *state, msg = towire_commitment_signed(tmpctx, &state->channel_id, &local_sig.s, NULL); - sync_crypto_write(state->pps, msg); + peer_write(state->pps, msg); peer_billboard(false, "channel open: commitment sent, waiting for reply"); /* Wait for the peer to send us our commitment tx signature */ @@ -2735,7 +2735,7 @@ static void opener_start(struct state *state, u8 *msg) state->channel_flags, open_tlv); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); /* This is usually a very transient state... */ peer_billboard(false, "channel open: offered, waiting for" @@ -3153,7 +3153,7 @@ static void rbf_local_start(struct state *state, u8 *msg) tx_state->tx_locktime, tx_state->feerate_per_kw_funding); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); /* ... since their reply should be immediate. */ msg = opening_negotiate_msg(tmpctx, state); @@ -3362,7 +3362,7 @@ static void rbf_remote_start(struct state *state, const u8 *rbf_msg) state->our_role == TX_INITIATOR ? tx_state->opener_funding : tx_state->accepter_funding); - sync_crypto_write(state->pps, msg); + peer_write(state->pps, msg); peer_billboard(false, "channel rbf: ack sent, waiting for reply"); /* We merge with RBF's we've initiated now */ @@ -3396,7 +3396,7 @@ static void send_funding_locked(struct state *state) msg = towire_funding_locked(NULL, &state->channel_id, &next_local_per_commit); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); state->funding_locked[LOCAL] = true; billboard_update(state); @@ -3442,7 +3442,7 @@ 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)); + peer_write(state->pps, take(msg)); } /* Try to handle a custommsg Returns true if it was a custom message and has @@ -3552,7 +3552,7 @@ static void do_reconnect_dance(struct state *state) , tlvs #endif ); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); peer_billboard(false, "Sent reestablish, waiting for theirs"); bool soft_error = state->funding_locked[REMOTE] @@ -3563,7 +3563,7 @@ static void do_reconnect_dance(struct state *state) * before we've reestablished channel). */ do { clean_tmpctx(); - msg = sync_crypto_read(tmpctx, state->pps); + msg = peer_read(tmpctx, state->pps); } while (dualopend_handle_custommsg(msg) || handle_peer_gossip_or_error(state->pps, &state->channel_id, @@ -3618,7 +3618,7 @@ static void do_reconnect_dance(struct state *state) if (psbt_side_finalized(tx_state->psbt, state->our_role) && !state->funding_locked[REMOTE]) { msg = psbt_to_tx_sigs_msg(NULL, state, tx_state->psbt); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); } if (state->funding_locked[LOCAL]) { @@ -3703,7 +3703,7 @@ static u8 *handle_master_in(struct state *state) * surprise. */ static u8 *handle_peer_in(struct state *state) { - u8 *msg = sync_crypto_read(tmpctx, state->pps); + u8 *msg = peer_read(tmpctx, state->pps); enum peer_wire t = fromwire_peektype(msg); struct channel_id channel_id; @@ -3786,14 +3786,14 @@ static u8 *handle_peer_in(struct state *state) &state->channel_id, false, msg)) return NULL; - sync_crypto_write(state->pps, - take(towire_warningfmt(NULL, - extract_channel_id(msg, - &channel_id) ? - &channel_id : NULL, - "Unexpected message %s: %s", - peer_wire_name(t), - tal_hex(tmpctx, msg)))); + peer_write(state->pps, + take(towire_warningfmt(NULL, + extract_channel_id(msg, + &channel_id) ? + &channel_id : NULL, + "Unexpected message %s: %s", + peer_wire_name(t), + tal_hex(tmpctx, msg)))); /* FIXME: We don't actually want master to try to send an * error, since peer is transient. This is a hack. diff --git a/openingd/openingd.c b/openingd/openingd.c index fede6c8119d6..72471da3f6c5 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -21,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -150,7 +150,7 @@ static void negotiation_failed(struct state *state, bool am_opener, msg = towire_errorfmt(NULL, &state->channel_id, "You gave bad parameters: %s", errmsg); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); negotiation_aborted(state, am_opener, errmsg); } @@ -257,10 +257,10 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, peer_wire_name(fromwire_peektype(msg)), type_to_string(tmpctx, struct channel_id, &actual)); - sync_crypto_write(state->pps, - take(towire_errorfmt(NULL, &actual, - "Multiple channels" - " unsupported"))); + peer_write(state->pps, + take(towire_errorfmt(NULL, &actual, + "Multiple channels" + " unsupported"))); tal_free(msg); continue; } @@ -396,7 +396,7 @@ static u8 *funder_channel_start(struct state *state, u8 channel_flags) &state->first_per_commitment_point[LOCAL], channel_flags, open_tlvs); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); /* This is usually a very transient state... */ peer_billboard(false, @@ -640,7 +640,7 @@ static bool funder_finalize_channel_setup(struct state *state, &state->funding.txid, state->funding.n, &sig->s); - sync_crypto_write(state->pps, msg); + peer_write(state->pps, msg); /* BOLT #2: * @@ -1050,7 +1050,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &state->first_per_commitment_point[LOCAL], accept_tlvs); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); peer_billboard(false, "Incoming channel: accepted, now waiting for them to create funding tx"); @@ -1258,7 +1258,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) * surprise. */ static u8 *handle_peer_in(struct state *state) { - u8 *msg = sync_crypto_read(tmpctx, state->pps); + u8 *msg = peer_read(tmpctx, state->pps); enum peer_wire t = fromwire_peektype(msg); struct channel_id channel_id; bool extracted; @@ -1289,7 +1289,7 @@ static u8 *handle_peer_in(struct state *state) &channel_id, msg, state->pps); } - sync_crypto_write(state->pps, + peer_write(state->pps, take(towire_warningfmt(NULL, extracted ? &channel_id : NULL, "Unexpected message %s: %s", @@ -1349,7 +1349,7 @@ static void openingd_send_custommsg(struct state *state, const u8 *msg) u8 *inner; if (!fromwire_custommsg_out(tmpctx, msg, &inner)) master_badmsg(WIRE_CUSTOMMSG_OUT, msg); - sync_crypto_write(state->pps, take(inner)); + peer_write(state->pps, take(inner)); } /* Standard lightningd-fd-is-ready-to-read demux code. Again, we could hang @@ -1393,7 +1393,7 @@ static u8 *handle_master_in(struct state *state) master_badmsg(WIRE_OPENINGD_FUNDER_CANCEL, msg); msg = towire_errorfmt(NULL, &state->channel_id, "Channel open canceled by us"); - sync_crypto_write(state->pps, take(msg)); + peer_write(state->pps, take(msg)); negotiation_aborted(state, true, "Channel open canceled by RPC"); return NULL; case WIRE_OPENINGD_DEV_MEMLEAK: @@ -1432,7 +1432,7 @@ 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)); + peer_write(state->pps, take(msg)); } int main(int argc, char *argv[]) From 22ecac7909849847503107efdb479e0cd2d94186 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:41:54 +1030 Subject: [PATCH 19/51] per_peer_state: remove struct crypto_state Now that connectd does the crypto, no need to hand around crypto_state. Signed-off-by: Rusty Russell --- channeld/Makefile | 1 - closingd/Makefile | 1 - common/Makefile | 2 +- common/crypto_state.c | 23 ----------------------- common/crypto_state.h | 3 --- common/per_peer_state.c | 9 ++------- common/per_peer_state.h | 6 +----- connectd/Makefile | 1 - connectd/connectd.c | 25 ++++++++++++++----------- connectd/multiplex.c | 6 +++--- connectd/multiplex.h | 4 +++- devtools/Makefile | 1 - gossipd/Makefile | 1 - lightningd/Makefile | 1 - openingd/Makefile | 1 - 15 files changed, 24 insertions(+), 61 deletions(-) delete mode 100644 common/crypto_state.c diff --git a/channeld/Makefile b/channeld/Makefile index 4b660bb64325..54b783856fba 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -40,7 +40,6 @@ CHANNELD_COMMON_OBJS := \ common/channel_config.o \ common/channel_id.o \ common/channel_type.o \ - common/crypto_state.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/closingd/Makefile b/closingd/Makefile index d641d78574a6..c9fc0570ce2e 100644 --- a/closingd/Makefile +++ b/closingd/Makefile @@ -26,7 +26,6 @@ CLOSINGD_COMMON_OBJS := \ common/bip32.o \ common/channel_id.o \ common/close_tx.o \ - common/crypto_state.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/common/Makefile b/common/Makefile index d4f9ae8d372a..9c8dbfe39893 100644 --- a/common/Makefile +++ b/common/Makefile @@ -22,7 +22,6 @@ COMMON_SRC_NOGEN := \ common/close_tx.c \ common/coin_mvt.c \ common/configdir.c \ - common/crypto_state.c \ common/cryptomsg.c \ common/daemon.c \ common/daemon_conn.c \ @@ -97,6 +96,7 @@ COMMON_SRC_GEN := common/status_wiregen.c common/peer_status_wiregen.c COMMON_HEADERS_NOGEN := $(COMMON_SRC_NOGEN:.c=.h) \ common/closing_fee.h \ + common/crypto_state.h \ common/ecdh.h \ common/errcode.h \ common/gossip_constants.h \ diff --git a/common/crypto_state.c b/common/crypto_state.c deleted file mode 100644 index d592ddfd3500..000000000000 --- a/common/crypto_state.c +++ /dev/null @@ -1,23 +0,0 @@ -#include "config.h" -#include -#include - -void towire_crypto_state(u8 **ptr, const struct crypto_state *cs) -{ - towire_u64(ptr, cs->rn); - towire_u64(ptr, cs->sn); - towire_secret(ptr, &cs->sk); - towire_secret(ptr, &cs->rk); - towire_secret(ptr, &cs->s_ck); - towire_secret(ptr, &cs->r_ck); -} - -void fromwire_crypto_state(const u8 **ptr, size_t *max, struct crypto_state *cs) -{ - cs->rn = fromwire_u64(ptr, max); - cs->sn = fromwire_u64(ptr, max); - fromwire_secret(ptr, max, &cs->sk); - fromwire_secret(ptr, max, &cs->rk); - fromwire_secret(ptr, max, &cs->s_ck); - fromwire_secret(ptr, max, &cs->r_ck); -} diff --git a/common/crypto_state.h b/common/crypto_state.h index c2fa658c8ce5..8a2674719961 100644 --- a/common/crypto_state.h +++ b/common/crypto_state.h @@ -12,7 +12,4 @@ struct crypto_state { struct secret s_ck, r_ck; }; -void towire_crypto_state(u8 **pptr, const struct crypto_state *cs); -void fromwire_crypto_state(const u8 **ptr, size_t *max, struct crypto_state *cs); - #endif /* LIGHTNING_COMMON_CRYPTO_STATE_H */ diff --git a/common/per_peer_state.c b/common/per_peer_state.c index 18b2472ff173..de11384e272e 100644 --- a/common/per_peer_state.c +++ b/common/per_peer_state.c @@ -19,12 +19,10 @@ static void destroy_per_peer_state(struct per_peer_state *pps) close(pps->gossip_store_fd); } -struct per_peer_state *new_per_peer_state(const tal_t *ctx, - const struct crypto_state *cs) +struct per_peer_state *new_per_peer_state(const tal_t *ctx) { struct per_peer_state *pps = tal(ctx, struct per_peer_state); - pps->cs = *cs; pps->gs = NULL; pps->peer_fd = pps->gossip_fd = pps->gossip_store_fd = -1; pps->grf = new_gossip_rcvd_filter(pps); @@ -69,7 +67,6 @@ void fromwire_gossip_state(const u8 **cursor, size_t *max, void towire_per_peer_state(u8 **pptr, const struct per_peer_state *pps) { - towire_crypto_state(pptr, &pps->cs); towire_bool(pptr, pps->gs != NULL); if (pps->gs) towire_gossip_state(pptr, pps->gs); @@ -89,11 +86,9 @@ 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, const u8 **cursor, size_t *max) { - struct crypto_state cs; struct per_peer_state *pps; - fromwire_crypto_state(cursor, max, &cs); - pps = new_per_peer_state(ctx, &cs); + pps = new_per_peer_state(ctx); if (fromwire_bool(cursor, max)) { pps->gs = tal(pps, struct gossip_state); fromwire_gossip_state(cursor, max, pps->gs); diff --git a/common/per_peer_state.h b/common/per_peer_state.h index 45bd1f172a82..e5e3b914cb6f 100644 --- a/common/per_peer_state.h +++ b/common/per_peer_state.h @@ -15,9 +15,6 @@ struct gossip_state { /* Things we hand between daemons to talk to peers. */ struct per_peer_state { - /* Cryptographic state needed to exchange messages with the peer (as - * featured in BOLT #8) */ - struct crypto_state cs; /* NULL if it's not initialized yet */ struct gossip_state *gs; /* Cache of msgs we have received, to avoid re-xmitting from store */ @@ -28,8 +25,7 @@ struct per_peer_state { /* Allocate a new per-peer state and add destructor to close fds if set; * sets fds to -1 and ->gs to NULL.. */ -struct per_peer_state *new_per_peer_state(const tal_t *ctx, - const struct crypto_state *cs); +struct per_peer_state *new_per_peer_state(const tal_t *ctx); /* Initialize the fds (must be -1 previous) */ void per_peer_state_set_fds(struct per_peer_state *pps, diff --git a/connectd/Makefile b/connectd/Makefile index 343a3624c10f..a6de259850f3 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -42,7 +42,6 @@ CONNECTD_COMMON_OBJS := \ common/bigsize.o \ common/bip32.o \ common/channel_id.o \ - common/crypto_state.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/connectd/connectd.c b/connectd/connectd.c index 2dc053923cde..fdbdefa26981 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -448,7 +448,7 @@ static struct peer *new_peer(struct daemon *daemon, struct peer *peer = tal(daemon, struct peer); peer->id = *id; - peer->pps = new_per_peer_state(peer, cs); + peer->cs = *cs; peer->final_msg = NULL; peer->subd_in = NULL; peer->peer_in = NULL; @@ -461,12 +461,6 @@ static struct peer *new_peer(struct daemon *daemon, if (!multiplex_subd_setup(peer, fd_for_subd)) return tal_free(peer); - /* If gossipd can't give us a file descriptor, we give up connecting. */ - if (!get_gossipfds(daemon, id, their_features, peer->pps)) { - close(*fd_for_subd); - return tal_free(peer); - } - peer->to_peer = tal_steal(peer, conn); peer_htable_add(&daemon->peers, peer); tal_add_destructor2(peer, destroy_peer, daemon); @@ -488,6 +482,7 @@ struct io_plan *peer_connected(struct io_conn *conn, int unsup; size_t depender, missing; int subd_fd; + struct per_peer_state *pps; peer = peer_htable_get(&daemon->peers, id); if (peer) @@ -545,20 +540,28 @@ struct io_plan *peer_connected(struct io_conn *conn, if (!peer) return io_close(conn); + pps = new_per_peer_state(tmpctx); + + /* If gossipd can't give us a file descriptor, we give up connecting. */ + if (!get_gossipfds(daemon, id, their_features, pps)) { + close(subd_fd); + return tal_free(peer); + } + /* Create message to tell master peer has connected. */ msg = towire_connectd_peer_connected(NULL, id, addr, incoming, - peer->pps, their_features); + pps, their_features); /*~ daemon_conn is a message queue for inter-daemon communication: we * queue up the `connect_peer_connected` message to tell lightningd * we have connected, and give the peer and gossip fds. */ daemon_conn_send(daemon->master, take(msg)); daemon_conn_send_fd(daemon->master, subd_fd); - daemon_conn_send_fd(daemon->master, peer->pps->gossip_fd); - daemon_conn_send_fd(daemon->master, peer->pps->gossip_store_fd); + daemon_conn_send_fd(daemon->master, pps->gossip_fd); + daemon_conn_send_fd(daemon->master, pps->gossip_store_fd); /* Don't try to close these on freeing. */ - peer->pps->gossip_store_fd = peer->pps->gossip_fd = -1; + pps->gossip_store_fd = pps->gossip_fd = -1; /*~ Now we set up this connection to read/write from subd */ return multiplex_peer_setup(conn, peer); diff --git a/connectd/multiplex.c b/connectd/multiplex.c index fb623c1921ff..d55c34e4fab5 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -36,7 +36,7 @@ static struct io_plan *encrypt_and_send(struct peer *peer, struct peer *peer)) { /* We free this and the encrypted version in next write_to_peer */ - peer->sent_to_peer = cryptomsg_encrypt_msg(peer, &peer->pps->cs, msg); + peer->sent_to_peer = cryptomsg_encrypt_msg(peer, &peer->cs, msg); return io_write(peer->to_peer, peer->sent_to_peer, tal_bytelen(peer->sent_to_peer), @@ -124,7 +124,7 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, { u8 *decrypted; - decrypted = cryptomsg_decrypt_body(NULL, &peer->pps->cs, + decrypted = cryptomsg_decrypt_body(NULL, &peer->cs, peer->peer_in); if (!decrypted) return io_close(peer_conn); @@ -142,7 +142,7 @@ static struct io_plan *read_body_from_peer(struct io_conn *peer_conn, { u16 len; - if (!cryptomsg_decrypt_header(&peer->pps->cs, peer->peer_in, &len)) + if (!cryptomsg_decrypt_header(&peer->cs, peer->peer_in, &len)) return io_close(peer_conn); tal_resize(&peer->peer_in, (u32)len + CRYPTOMSG_BODY_OVERHEAD); diff --git a/connectd/multiplex.h b/connectd/multiplex.h index e96982bf8322..12ccfa082de4 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -2,12 +2,14 @@ #define LIGHTNING_CONNECTD_MULTIPLEX_H #include "config.h" #include +#include #include #include struct peer { struct node_id id; - struct per_peer_state *pps; + /* Counters and keys for symmetric crypto */ + struct crypto_state cs; /* Connection to the peer */ struct io_conn *to_peer; diff --git a/devtools/Makefile b/devtools/Makefile index e61f928f1161..5498db4684ce 100644 --- a/devtools/Makefile +++ b/devtools/Makefile @@ -21,7 +21,6 @@ DEVTOOLS_COMMON_OBJS := \ common/bolt11.o \ common/blockheight_states.o \ common/channel_id.o \ - common/crypto_state.o \ common/decode_array.o \ common/features.o \ common/fee_states.o \ diff --git a/gossipd/Makefile b/gossipd/Makefile index f31acfe92c0c..13c8eada0abb 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -37,7 +37,6 @@ GOSSIPD_COMMON_OBJS := \ common/blinding.o \ common/blindedpath.o \ common/channel_id.o \ - common/crypto_state.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ diff --git a/lightningd/Makefile b/lightningd/Makefile index 2cdb6b0d00b7..24c57250ae19 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -81,7 +81,6 @@ LIGHTNINGD_COMMON_OBJS := \ common/channel_type.o \ common/coin_mvt.o \ common/configdir.o \ - common/crypto_state.o \ common/daemon.o \ common/derive_basepoints.o \ common/ecdh_hsmd.o \ diff --git a/openingd/Makefile b/openingd/Makefile index 0ff843e47a7f..6cbf12546fd7 100644 --- a/openingd/Makefile +++ b/openingd/Makefile @@ -41,7 +41,6 @@ OPENINGD_COMMON_OBJS := \ common/channel_config.o \ common/channel_id.o \ common/channel_type.o \ - common/crypto_state.o \ common/cryptomsg.o \ common/daemon.o \ common/daemon_conn.o \ From ff26d89f48b772dc77ea21ec5da33a9480e949e7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:09 +1030 Subject: [PATCH 20/51] connectd: do dev_disconnect logic. As connectd handles more packets itself, or diverts them to/from gossipd, it's the only place we can implement the dev_disconnect logic. Signed-off-by: Rusty Russell --- channeld/Makefile | 1 - channeld/channeld.c | 1 - closingd/Makefile | 1 - common/dev_disconnect.c | 8 ++++--- common/dev_disconnect.h | 4 +++- common/peer_io.c | 31 -------------------------- common/subdaemon.c | 10 --------- connectd/connectd.c | 9 +++++++- connectd/connectd_wire.csv | 2 ++ connectd/multiplex.c | 38 ++++++++++++++++++++++++++++++++ connectd/peer_exchange_initmsg.c | 2 +- hsmd/hsmd.c | 4 ---- lightningd/connect_control.c | 11 +++++++-- lightningd/subd.c | 14 +++--------- onchaind/Makefile | 1 - openingd/Makefile | 1 - tests/test_gossip.py | 3 ++- 17 files changed, 71 insertions(+), 70 deletions(-) diff --git a/channeld/Makefile b/channeld/Makefile index 54b783856fba..2c9e89d758e2 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -44,7 +44,6 @@ CHANNELD_COMMON_OBJS := \ common/daemon.o \ common/daemon_conn.o \ common/derive_basepoints.o \ - common/dev_disconnect.o \ common/ecdh_hsmd.o \ common/features.o \ common/fee_states.o \ diff --git a/channeld/channeld.c b/channeld/channeld.c index 86d5f015b656..63f161ace784 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/closingd/Makefile b/closingd/Makefile index c9fc0570ce2e..53c732399c07 100644 --- a/closingd/Makefile +++ b/closingd/Makefile @@ -30,7 +30,6 @@ CLOSINGD_COMMON_OBJS := \ common/daemon.o \ common/daemon_conn.o \ common/derive_basepoints.o \ - common/dev_disconnect.o \ common/gossip_rcvd_filter.o \ common/gossip_store.o \ common/htlc_wire.o \ diff --git a/common/dev_disconnect.c b/common/dev_disconnect.c index 0dd088290541..608b2f7a842c 100644 --- a/common/dev_disconnect.c +++ b/common/dev_disconnect.c @@ -51,7 +51,7 @@ void dev_disconnect_init(int fd) dev_disconnect_fd = fd; } -enum dev_disconnect dev_disconnect(int pkt_type) +enum dev_disconnect dev_disconnect(const struct node_id *id, int pkt_type) { if (dev_disconnect_fd == -1) return DEV_DISCONNECT_NORMAL; @@ -59,7 +59,8 @@ enum dev_disconnect dev_disconnect(int pkt_type) if (!dev_disconnect_count) next_dev_disconnect(); - if (!streq(peer_wire_name(pkt_type), dev_disconnect_line+1)) + if (!dev_disconnect_line[0] + || !streq(peer_wire_name(pkt_type), dev_disconnect_line+1)) return DEV_DISCONNECT_NORMAL; if (--dev_disconnect_count != 0) { @@ -70,7 +71,8 @@ enum dev_disconnect dev_disconnect(int pkt_type) err(1, "lseek failure"); } - status_debug("dev_disconnect: %s", dev_disconnect_line); + status_peer_debug(id, "dev_disconnect: %s (%s)", dev_disconnect_line, + peer_wire_name(pkt_type)); return dev_disconnect_line[0]; } diff --git a/common/dev_disconnect.h b/common/dev_disconnect.h index 0f4ae524a4f3..e1351478dcae 100644 --- a/common/dev_disconnect.h +++ b/common/dev_disconnect.h @@ -4,6 +4,8 @@ #include #if DEVELOPER +struct node_id; + enum dev_disconnect { /* Do nothing. */ DEV_DISCONNECT_NORMAL = '=', @@ -18,7 +20,7 @@ enum dev_disconnect { }; /* Force a close fd before or after a certain packet type */ -enum dev_disconnect dev_disconnect(int pkt_type); +enum dev_disconnect dev_disconnect(const struct node_id *id, int pkt_type); /* Make next write on fd fail as if they'd disconnected. */ void dev_sabotage_fd(int fd, bool close_fd); diff --git a/common/peer_io.c b/common/peer_io.c index 43b9a027e18f..995920fd5c78 100644 --- a/common/peer_io.c +++ b/common/peer_io.c @@ -1,7 +1,6 @@ #include "config.h" #include #include -#include #include #include #include @@ -17,40 +16,10 @@ void peer_write(struct per_peer_state *pps, const void *msg TAKES) { -#if DEVELOPER - bool post_sabotage = false, post_close; - int type = fromwire_peektype(msg); -#endif - status_peer_io(LOG_IO_OUT, NULL, msg); -#if DEVELOPER - switch (dev_disconnect(type)) { - case DEV_DISCONNECT_BEFORE: - dev_sabotage_fd(pps->peer_fd, true); - peer_failed_connection_lost(); - case DEV_DISCONNECT_AFTER: - post_sabotage = true; - post_close = true; - break; - case DEV_DISCONNECT_BLACKHOLE: - dev_blackhole_fd(pps->peer_fd); - break; - case DEV_DISCONNECT_NORMAL: - break; - case DEV_DISCONNECT_DISABLE_AFTER: - post_sabotage = true; - post_close = false; - break; - } -#endif if (!wire_sync_write(pps->peer_fd, msg)) peer_failed_connection_lost(); - -#if DEVELOPER - if (post_sabotage) - dev_sabotage_fd(pps->peer_fd, post_close); -#endif } /* We're happy for the kernel to batch update and gossip messages, but a diff --git a/common/subdaemon.c b/common/subdaemon.c index 6ed2e443815a..523a4e3ac3b1 100644 --- a/common/subdaemon.c +++ b/common/subdaemon.c @@ -1,5 +1,4 @@ #include "config.h" -#include #include #include #include @@ -33,14 +32,5 @@ void subdaemon_setup(int argc, char *argv[]) daemon_maybe_debug(argv); -#if DEVELOPER - for (int i = 1; i < argc; i++) { - if (strstarts(argv[i], "--dev-disconnect=")) { - dev_disconnect_init(atoi(argv[i] - + strlen("--dev-disconnect="))); - } - } -#endif - daemon_setup(argv[0], status_backtrace_print, status_backtrace_exit); } diff --git a/connectd/connectd.c b/connectd/connectd.c index fdbdefa26981..3789ec1283fc 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1598,6 +1599,7 @@ static void connect_init(struct daemon *daemon, const u8 *msg) enum addr_listen_announce *proposed_listen_announce; struct wireaddr *announcable; char *tor_password; + bool dev_disconnect; /* Fields which require allocation are allocated off daemon */ if (!fromwire_connectd_init( @@ -1613,7 +1615,8 @@ static void connect_init(struct daemon *daemon, const u8 *msg) &daemon->use_v3_autotor, &daemon->timeout_secs, &daemon->websocket_helper, - &daemon->websocket_port)) { + &daemon->websocket_port, + &dev_disconnect)) { /* This is a helper which prints the type expected and the actual * message, then exits (it should never be called!). */ master_badmsg(WIRE_CONNECTD_INIT, msg); @@ -1657,6 +1660,10 @@ static void connect_init(struct daemon *daemon, const u8 *msg) take(towire_connectd_init_reply(NULL, binding, announcable))); +#if DEVELOPER + if (dev_disconnect) + dev_disconnect_init(5); +#endif } /*~ lightningd tells us to go! */ diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index bddaf972af7e..351f78d31039 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -21,6 +21,8 @@ msgdata,connectd_init,use_v3_autotor,bool, msgdata,connectd_init,timeout_secs,u32, msgdata,connectd_init,websocket_helper,wirestring, msgdata,connectd_init,websocket_port,u16, +# If this is set, then fd 5 is dev_disconnect_fd. +msgdata,connectd_init,dev_disconnect,bool, # Connectd->master, here are the addresses I bound, can announce. msgtype,connectd_init_reply,2100 diff --git a/connectd/multiplex.c b/connectd/multiplex.c index d55c34e4fab5..c855243e6fc6 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,7 @@ #include #include #include +#include #include void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) @@ -29,12 +31,48 @@ static struct io_plan *after_final_msg(struct io_conn *peer_conn, return io_close(peer_conn); } +#if DEVELOPER +static struct io_plan *write_to_peer(struct io_conn *peer_conn, + struct peer *peer); + +static struct io_plan *dev_leave_hanging(struct io_conn *peer_conn, + struct peer *peer) +{ + /* We don't tell the peer we're disconnecting, but from now on + * our writes go nowhere, and there's nothing to read. */ + dev_sabotage_fd(io_conn_fd(peer_conn), false); + return write_to_peer(peer_conn, peer); +} +#endif /* DEVELOPER */ + static struct io_plan *encrypt_and_send(struct peer *peer, const u8 *msg TAKES, struct io_plan *(*next) (struct io_conn *peer_conn, struct peer *peer)) { +#if DEVELOPER + int type = fromwire_peektype(msg); + + switch (dev_disconnect(&peer->id, type)) { + case DEV_DISCONNECT_BEFORE: + if (taken(msg)) + tal_free(msg); + return io_close(peer->to_peer); + case DEV_DISCONNECT_AFTER: + next = (void *)io_close_cb; + break; + case DEV_DISCONNECT_BLACKHOLE: + dev_blackhole_fd(io_conn_fd(peer->to_peer)); + break; + case DEV_DISCONNECT_NORMAL: + break; + case DEV_DISCONNECT_DISABLE_AFTER: + next = dev_leave_hanging; + break; + } +#endif + /* We free this and the encrypted version in next write_to_peer */ peer->sent_to_peer = cryptomsg_encrypt_msg(peer, &peer->cs, msg); return io_write(peer->to_peer, diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index 8106ab92697d..aa6aa0da8f88 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -208,7 +208,7 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, next = read_init; #if DEVELOPER - switch (dev_disconnect(WIRE_INIT)) { + switch (dev_disconnect(&peer->id, WIRE_INIT)) { case DEV_DISCONNECT_BEFORE: dev_sabotage_fd(io_conn_fd(conn), true); break; diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 96c76ef4e8a3..77a09622341d 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -97,10 +97,6 @@ static bool is_lightningd(const struct client *client) return client == dbid_zero_clients[0]; } -/* FIXME: This is used by debug.c. Doesn't apply to us, but lets us link. */ -extern void dev_disconnect_init(int fd); -void dev_disconnect_init(int fd UNUSED) { } - /* Pre-declare this, due to mutual recursion */ static struct io_plan *handle_client(struct io_conn *conn, struct client *c); diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index a01366d5a1a8..e6bb2909266c 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -363,7 +363,13 @@ int connectd_init(struct lightningd *ld) ld->connectd = new_global_subd(ld, "lightning_connectd", connectd_wire_name, connectd_msg, - take(&hsmfd), take(&fds[1]), NULL); + take(&hsmfd), take(&fds[1]), +#if DEVELOPER + /* Not take(): we share it */ + ld->dev_disconnect_fd >= 0 ? + &ld->dev_disconnect_fd : NULL, +#endif + NULL); if (!ld->connectd) err(1, "Could not subdaemon connectd"); @@ -388,7 +394,8 @@ int connectd_init(struct lightningd *ld) ld->config.use_v3_autotor, ld->config.connection_timeout_secs, websocket_helper_path, - ld->websocket_port); + ld->websocket_port, + IFDEV(ld->dev_disconnect_fd >= 0, false)); subd_req(ld->connectd, ld->connectd, take(msg), -1, 0, connect_init_done, NULL); diff --git a/lightningd/subd.c b/lightningd/subd.c index a42849b48805..0bb9afd8a9c7 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -188,7 +188,7 @@ static void close_taken_fds(va_list *ap) /* We use sockets, not pipes, because fds are bidir. */ static int subd(const char *path, const char *name, const char *debug_subdaemon, - int *msgfd, int dev_disconnect_fd, + int *msgfd, bool io_logging, va_list *ap) { @@ -212,7 +212,7 @@ static int subd(const char *path, const char *name, if (childpid == 0) { size_t num_args; - char *args[] = { NULL, NULL, NULL, NULL, NULL }; + char *args[] = { NULL, NULL, NULL, NULL }; int **fds = tal_arr(tmpctx, int *, 3); int stdoutfd = STDOUT_FILENO, stderrfd = STDERR_FILENO; @@ -230,10 +230,6 @@ static int subd(const char *path, const char *name, tal_arr_expand(&fds, fd); } - /* If we have a dev_disconnect_fd, add it after. */ - if (dev_disconnect_fd != -1) - tal_arr_expand(&fds, &dev_disconnect_fd); - /* Finally, the fd to report exec errors on */ tal_arr_expand(&fds, &execfail[1]); @@ -248,8 +244,6 @@ static int subd(const char *path, const char *name, if (io_logging) args[num_args++] = "--log-io"; #if DEVELOPER - if (dev_disconnect_fd != -1) - args[num_args++] = tal_fmt(NULL, "--dev-disconnect=%i", dev_disconnect_fd); if (debug_subdaemon && strends(name, debug_subdaemon)) args[num_args++] = "--debugger"; #endif @@ -700,7 +694,6 @@ static struct subd *new_subd(struct lightningd *ld, struct subd *sd = tal(ld, struct subd); int msg_fd; const char *debug_subd = NULL; - int disconnect_fd = -1; const char *shortname; assert(name != NULL); @@ -720,13 +713,12 @@ static struct subd *new_subd(struct lightningd *ld, #if DEVELOPER debug_subd = ld->dev_debug_subprocess; - disconnect_fd = ld->dev_disconnect_fd; #endif /* DEVELOPER */ const char *path = subdaemon_path(tmpctx, ld, name); sd->pid = subd(path, name, debug_subd, - &msg_fd, disconnect_fd, + &msg_fd, /* We only turn on subdaemon io logging if we're going * to print it: too stressful otherwise! */ log_print_level(sd->log) < LOG_DBG, diff --git a/onchaind/Makefile b/onchaind/Makefile index a57e2bcf9ca2..1da287a5635b 100644 --- a/onchaind/Makefile +++ b/onchaind/Makefile @@ -41,7 +41,6 @@ ONCHAIND_COMMON_OBJS := \ common/daemon.o \ common/daemon_conn.o \ common/derive_basepoints.o \ - common/dev_disconnect.o \ common/status_wiregen.o \ common/htlc_tx.o \ common/htlc_wire.o \ diff --git a/openingd/Makefile b/openingd/Makefile index 6cbf12546fd7..608268399655 100644 --- a/openingd/Makefile +++ b/openingd/Makefile @@ -45,7 +45,6 @@ OPENINGD_COMMON_OBJS := \ common/daemon.o \ common/daemon_conn.o \ common/derive_basepoints.o \ - common/dev_disconnect.o \ common/features.o \ common/fee_states.o \ common/gossip_rcvd_filter.o \ diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 7696b2642490..018989e41493 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -597,7 +597,8 @@ def test_gossip_no_empty_announcements(node_factory, bitcoind): # l3 sends CHANNEL_ANNOUNCEMENT to l2, but not CHANNEL_UDPATE. l1, l2, l3, l4 = node_factory.line_graph(4, opts=[{'log-level': 'io'}, {'log-level': 'io'}, - {'disconnect': ['+WIRE_CHANNEL_ANNOUNCEMENT'], + # Writes to l4 first, then l2 + {'disconnect': ['+WIRE_CHANNEL_ANNOUNCEMENT*2'], 'may_reconnect': True}, {'may_reconnect': True}], fundchannel=False) From 381b62e5c08e521b4355ffbf93f5c9fb6d27261a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:09 +1030 Subject: [PATCH 21/51] connectd: do nagle by packet type. channeld can't do it any more: it's using local sockets. Connectd can do it, and simply does it by type. Signed-off-by: Rusty Russell --- channeld/channeld.c | 8 +++--- common/peer_io.c | 44 ------------------------------- common/peer_io.h | 3 --- connectd/connectd.c | 1 + connectd/multiplex.c | 63 +++++++++++++++++++++++++++++++++++++++++++- connectd/multiplex.h | 3 +++ 6 files changed, 70 insertions(+), 52 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 63f161ace784..b9a660524dc0 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1123,7 +1123,7 @@ static void send_ping(struct peer *peer) exit(0); } - peer_write_no_delay(peer->pps, take(make_ping(NULL, 1, 0))); + peer_write(peer->pps, take(make_ping(NULL, 1, 0))); peer->expecting_pong = PONG_EXPECTED_PROBING; set_ping_timer(peer); } @@ -1415,7 +1415,7 @@ static void send_commit(struct peer *peer) msg = towire_commitment_signed(NULL, &peer->channel_id, &commit_sig.s, raw_sigs(tmpctx, htlc_sigs)); - peer_write_no_delay(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); maybe_send_shutdown(peer); @@ -1583,7 +1583,7 @@ static void send_revocation(struct peer *peer, WIRE_CHANNELD_GOT_COMMITSIG_REPLY); /* Now we can finally send revoke_and_ack to peer */ - peer_write_no_delay(peer->pps, take(msg)); + peer_write(peer->pps, take(msg)); } static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) @@ -3631,7 +3631,7 @@ static void handle_send_ping(struct peer *peer, const u8 *msg) if (tal_count(ping) > 65535) status_failed(STATUS_FAIL_MASTER_IO, "Oversize ping"); - peer_write_no_delay(peer->pps, take(ping)); + peer_write(peer->pps, take(ping)); /* Since we're doing this manually, kill and restart timer. */ status_debug("sending ping expecting %sresponse", diff --git a/common/peer_io.c b/common/peer_io.c index 995920fd5c78..587a14901ba4 100644 --- a/common/peer_io.c +++ b/common/peer_io.c @@ -22,50 +22,6 @@ void peer_write(struct per_peer_state *pps, const void *msg TAKES) peer_failed_connection_lost(); } -/* We're happy for the kernel to batch update and gossip messages, but a - * commitment message, for example, should be instantly sent. There's no - * great way of doing this, unfortunately. - * - * Setting TCP_NODELAY on Linux flushes the socket, which really means - * we'd want to toggle on then off it *after* sending. But Linux has - * TCP_CORK. On FreeBSD, it seems (looking at source) not to, so - * there we'd want to set it before the send, and reenable it - * afterwards. Even if this is wrong on other non-Linux platforms, it - * only means one extra packet. - */ -void peer_write_no_delay(struct per_peer_state *pps, const void *msg TAKES) -{ - int val; - int opt; - const char *optname; - static bool complained = false; - -#ifdef TCP_CORK - opt = TCP_CORK; - optname = "TCP_CORK"; -#elif defined(TCP_NODELAY) - opt = TCP_NODELAY; - optname = "TCP_NODELAY"; -#else -#error "Please report platform with neither TCP_CORK nor TCP_NODELAY?" -#endif - - val = 1; - if (setsockopt(pps->peer_fd, IPPROTO_TCP, opt, &val, sizeof(val)) != 0) { - /* This actually happens in testing, where we blackhole the fd */ - if (!complained) { - status_unusual("setsockopt %s=1: %s", - optname, - strerror(errno)); - complained = true; - } - } - peer_write(pps, msg); - - val = 0; - setsockopt(pps->peer_fd, IPPROTO_TCP, opt, &val, sizeof(val)); -} - u8 *peer_read(const tal_t *ctx, struct per_peer_state *pps) { u8 *dec = wire_sync_read(ctx, pps->peer_fd); diff --git a/common/peer_io.h b/common/peer_io.h index 0ca6670acde1..621e71db35af 100644 --- a/common/peer_io.h +++ b/common/peer_io.h @@ -9,9 +9,6 @@ struct per_peer_state; /* Exits with peer_failed_connection_lost() if write fails. */ void peer_write(struct per_peer_state *pps, const void *msg TAKES); -/* Same, but disabled nagle for this message. */ -void peer_write_no_delay(struct per_peer_state *pps, const void *msg TAKES); - /* Exits with peer_failed_connection_lost() if can't read packet. */ u8 *peer_read(const tal_t *ctx, struct per_peer_state *pps); diff --git a/connectd/connectd.c b/connectd/connectd.c index 3789ec1283fc..2fe0953991a9 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -454,6 +454,7 @@ static struct peer *new_peer(struct daemon *daemon, peer->subd_in = NULL; peer->peer_in = NULL; peer->sent_to_peer = NULL; + peer->urgent = false; peer->peer_outq = msg_queue_new(peer); peer->subd_outq = msg_queue_new(peer); diff --git a/connectd/multiplex.c b/connectd/multiplex.c index c855243e6fc6..25bb6be0c340 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -10,8 +10,11 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -45,15 +48,61 @@ static struct io_plan *dev_leave_hanging(struct io_conn *peer_conn, } #endif /* DEVELOPER */ +/* We're happy for the kernel to batch update and gossip messages, but a + * commitment message, for example, should be instantly sent. There's no + * great way of doing this, unfortunately. + * + * Setting TCP_NODELAY on Linux flushes the socket, which really means + * we'd want to toggle on then off it *after* sending. But Linux has + * TCP_CORK. On FreeBSD, it seems (looking at source) not to, so + * there we'd want to set it before the send, and reenable it + * afterwards. Even if this is wrong on other non-Linux platforms, it + * only means one extra packet. + */ +static void set_urgent_flag(struct peer *peer, bool urgent) +{ + int val; + int opt; + const char *optname; + static bool complained = false; + + if (!urgent && !peer->urgent) + return; + +#ifdef TCP_CORK + opt = TCP_CORK; + optname = "TCP_CORK"; +#elif defined(TCP_NODELAY) + opt = TCP_NODELAY; + optname = "TCP_NODELAY"; +#else +#error "Please report platform with neither TCP_CORK nor TCP_NODELAY?" +#endif + + val = urgent; + if (setsockopt(io_conn_fd(peer->to_peer), + IPPROTO_TCP, opt, &val, sizeof(val)) != 0) { + /* This actually happens in testing, where we blackhole the fd */ + if (!complained) { + status_unusual("setsockopt %s=1: %s", + optname, + strerror(errno)); + complained = true; + } + } + peer->urgent = urgent; +} + + static struct io_plan *encrypt_and_send(struct peer *peer, const u8 *msg TAKES, struct io_plan *(*next) (struct io_conn *peer_conn, struct peer *peer)) { -#if DEVELOPER int type = fromwire_peektype(msg); +#if DEVELOPER switch (dev_disconnect(&peer->id, type)) { case DEV_DISCONNECT_BEFORE: if (taken(msg)) @@ -73,6 +122,14 @@ static struct io_plan *encrypt_and_send(struct peer *peer, } #endif + /* These are critical, and so send without delay. */ + if (type == WIRE_COMMITMENT_SIGNED + || type == WIRE_REVOKE_AND_ACK + || type == WIRE_PING + || type == WIRE_PONG) { + set_urgent_flag(peer, true); + } + /* We free this and the encrypted version in next write_to_peer */ peer->sent_to_peer = cryptomsg_encrypt_msg(peer, &peer->cs, msg); return io_write(peer->to_peer, @@ -101,6 +158,10 @@ static struct io_plan *write_to_peer(struct io_conn *peer_conn, peer->final_msg, after_final_msg); } + + /* Reset urgent flag, if set. */ + set_urgent_flag(peer, false); + /* Tell them to read again, */ io_wake(&peer->subd_in); diff --git a/connectd/multiplex.h b/connectd/multiplex.h index 12ccfa082de4..ccd037939fd0 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -20,6 +20,9 @@ struct peer { /* Final message to send to peer (and hangup) */ u8 *final_msg; + /* When we write something which wants Nagle overridden */ + bool urgent; + /* Input buffers. */ u8 *subd_in, *peer_in; From ff57f6d358c9ab416d0d6985e63121ed1b79fc74 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:09 +1030 Subject: [PATCH 22/51] common: add routine for absolute timeouts (vs. relative). Signed-off-by: Rusty Russell --- common/timeout.c | 19 ++++++++++++++++++- common/timeout.h | 10 +++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/common/timeout.c b/common/timeout.c index d4b4b480f1bf..475733e02a45 100644 --- a/common/timeout.c +++ b/common/timeout.c @@ -31,7 +31,24 @@ struct oneshot *new_reltimer_(struct timers *timers, return t; } -void *reltimer_arg(struct oneshot *t) +struct oneshot *new_abstimer_(struct timers *timers, + const tal_t *ctx, + struct timemono expiry, + void (*cb)(void *), void *arg) +{ + struct oneshot *t = tal(ctx, struct oneshot); + + t->cb = cb; + t->arg = arg; + t->timers = timers; + timer_init(&t->timer); + timer_addmono(timers, &t->timer, expiry); + tal_add_destructor(t, destroy_timer); + + return t; +} + +void *oneshot_arg(struct oneshot *t) { return t->arg; } diff --git a/common/timeout.h b/common/timeout.h index 55b1a4b633ac..0277a072323a 100644 --- a/common/timeout.h +++ b/common/timeout.h @@ -15,8 +15,16 @@ struct oneshot *new_reltimer_(struct timers *timers, new_reltimer_((timers), (ctx), (relexpire), \ typesafe_cb(void, void *, (func), (arg)), (arg)) +struct oneshot *new_abstimer_(struct timers *timers, + const tal_t *ctx, + struct timemono expiry, + void (*cb)(void *), void *arg); +#define new_abstimer(timers, ctx, expiry, func, arg) \ + new_abstimer_((timers), (ctx), (expiry), \ + typesafe_cb(void, void *, (func), (arg)), (arg)) + /* Get timer arg. */ -void *reltimer_arg(struct oneshot *t); +void *oneshot_arg(struct oneshot *t); void timer_expired(struct timer *timer); From 5c7d7b7890649916324f9133fd2828a99b35bb80 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:09 +1030 Subject: [PATCH 23/51] connectd: serve gossip_store file for the peer. We actually intercept the gossip_timestamp_filter, so the gossip_store mechanism inside the per-peer daemon never kicks off for normal connections. The gossipwith tool doesn't set OPT_GOSSIP_QUERIES, so it gets both, but that only effects one place. Signed-off-by: Rusty Russell --- common/gossip_store.c | 112 ++++++++++++----- common/gossip_store.h | 21 ++++ connectd/Makefile | 2 + connectd/connectd.c | 112 +++-------------- connectd/connectd.h | 145 +++++++++++++++++++++- connectd/connectd_wire.csv | 1 + connectd/multiplex.c | 234 +++++++++++++++++++++++++++++++++-- connectd/multiplex.h | 32 +---- lightningd/connect_control.c | 1 + tests/test_gossip.py | 3 +- 10 files changed, 503 insertions(+), 160 deletions(-) diff --git a/common/gossip_store.c b/common/gossip_store.c index bc66cf110811..a2b3cb11e5e2 100644 --- a/common/gossip_store.c +++ b/common/gossip_store.c @@ -44,7 +44,7 @@ void gossip_setup_timestamp_filter(struct per_peer_state *pps, lseek(pps->gossip_store_fd, 1, SEEK_SET); } -static bool timestamp_filter(const struct per_peer_state *pps, u32 timestamp) +static bool timestamp_filter(const struct gossip_state *gs, u32 timestamp) { /* BOLT #7: * @@ -53,8 +53,8 @@ static bool timestamp_filter(const struct per_peer_state *pps, u32 timestamp) * `timestamp_range`. */ /* Note that we turn first_timestamp & timestamp_range into an inclusive range */ - return timestamp >= pps->gs->timestamp_min - && timestamp <= pps->gs->timestamp_max; + return timestamp >= gs->timestamp_min + && timestamp <= gs->timestamp_max; } /* Not all the data we expected was there: rewind file */ @@ -71,8 +71,7 @@ static void failed_read(int fd, int len) lseek(fd, -len, SEEK_CUR); } -static void reopen_gossip_store(struct per_peer_state *pps, - const u8 *msg) +static void reopen_gossip_store(int *gossip_store_fd, const u8 *msg) { u64 equivalent_offset; int newfd; @@ -93,53 +92,59 @@ static void reopen_gossip_store(struct per_peer_state *pps, equivalent_offset); lseek(newfd, equivalent_offset, SEEK_SET); - close(pps->gossip_store_fd); - pps->gossip_store_fd = newfd; + close(*gossip_store_fd); + *gossip_store_fd = newfd; } -u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps) +u8 *gossip_store_iter(const tal_t *ctx, + int *gossip_store_fd, + struct gossip_state *gs, + struct gossip_rcvd_filter *grf, + size_t *off) { u8 *msg = NULL; - /* Don't read until we're initialized. */ - if (!pps->gs) - return NULL; - while (!msg) { struct gossip_hdr hdr; u32 msglen, checksum, timestamp; bool push; int type, r; - r = read(pps->gossip_store_fd, &hdr, sizeof(hdr)); + if (off) + r = pread(*gossip_store_fd, &hdr, sizeof(hdr), *off); + else + r = read(*gossip_store_fd, &hdr, sizeof(hdr)); if (r != sizeof(hdr)) { /* We expect a 0 read here at EOF */ - if (r != 0) - failed_read(pps->gossip_store_fd, r); - per_peer_state_reset_gossip_timer(pps); + if (r != 0 && off) + failed_read(*gossip_store_fd, r); return NULL; } + msglen = be32_to_cpu(hdr.len); + push = (msglen & GOSSIP_STORE_LEN_PUSH_BIT); + msglen &= GOSSIP_STORE_LEN_MASK; + /* Skip any deleted entries. */ if (be32_to_cpu(hdr.len) & GOSSIP_STORE_LEN_DELETED_BIT) { /* Skip over it. */ - lseek(pps->gossip_store_fd, - be32_to_cpu(hdr.len) & GOSSIP_STORE_LEN_MASK, - SEEK_CUR); + if (off) + *off += r + msglen; + else + lseek(*gossip_store_fd, msglen, SEEK_CUR); continue; } - msglen = be32_to_cpu(hdr.len); - push = (msglen & GOSSIP_STORE_LEN_PUSH_BIT); - msglen &= GOSSIP_STORE_LEN_MASK; - checksum = be32_to_cpu(hdr.crc); timestamp = be32_to_cpu(hdr.timestamp); msg = tal_arr(ctx, u8, msglen); - r = read(pps->gossip_store_fd, msg, msglen); + if (off) + r = pread(*gossip_store_fd, msg, msglen, *off + r); + else + r = read(*gossip_store_fd, msg, msglen); if (r != msglen) { - failed_read(pps->gossip_store_fd, r); - per_peer_state_reset_gossip_timer(pps); + if (!off) + failed_read(*gossip_store_fd, r); return NULL; } @@ -147,27 +152,74 @@ u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps) status_failed(STATUS_FAIL_INTERNAL_ERROR, "gossip_store: bad checksum offset %" PRIi64": %s", - (s64)lseek(pps->gossip_store_fd, + off ? (s64)*off : + (s64)lseek(*gossip_store_fd, 0, SEEK_CUR) - msglen, tal_hex(tmpctx, msg)); + /* Definitely processing it now */ + if (off) + *off += sizeof(hdr) + msglen; + /* Don't send back gossip they sent to us! */ - if (gossip_rcvd_filter_del(pps->grf, msg)) { + if (gossip_rcvd_filter_del(grf, msg)) { msg = tal_free(msg); continue; } type = fromwire_peektype(msg); if (type == WIRE_GOSSIP_STORE_ENDED) - reopen_gossip_store(pps, msg); + reopen_gossip_store(gossip_store_fd, msg); /* Ignore gossipd internal messages. */ else if (type != WIRE_CHANNEL_ANNOUNCEMENT && type != WIRE_CHANNEL_UPDATE && type != WIRE_NODE_ANNOUNCEMENT) msg = tal_free(msg); - else if (!push && !timestamp_filter(pps, timestamp)) + else if (!push && !timestamp_filter(gs, timestamp)) msg = tal_free(msg); } return msg; } + +u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps) +{ + u8 *msg; + + /* Don't read until we're initialized. */ + if (!pps->gs) + return NULL; + + /* FIXME: We are only caller using off == NULL */ + msg = gossip_store_iter(ctx, &pps->gossip_store_fd, + pps->gs, pps->grf, NULL); + + if (!msg) + per_peer_state_reset_gossip_timer(pps); + + return msg; +} + +size_t find_gossip_store_end(int gossip_store_fd, size_t off) +{ + /* We cheat and read first two bytes of message too. */ + struct { + struct gossip_hdr hdr; + be16 type; + } buf; + int r; + + while ((r = read(gossip_store_fd, &buf, + sizeof(buf.hdr) + sizeof(buf.type))) + == sizeof(buf.hdr) + sizeof(buf.type)) { + u32 msglen = be32_to_cpu(buf.hdr.len) & GOSSIP_STORE_LEN_MASK; + + /* Don't swallow end marker! */ + if (buf.type == CPU_TO_BE32(WIRE_GOSSIP_STORE_ENDED)) + break; + + off += sizeof(buf.hdr) + msglen; + lseek(gossip_store_fd, off, SEEK_SET); + } + return off; +} diff --git a/common/gossip_store.h b/common/gossip_store.h index b23e99f43cf6..c109c8625817 100644 --- a/common/gossip_store.h +++ b/common/gossip_store.h @@ -6,6 +6,8 @@ #include struct per_peer_state; +struct gossip_state; +struct gossip_rcvd_filter; /** * gossip_store -- On-disk storage related information @@ -43,10 +45,29 @@ struct gossip_hdr { */ u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps); +/** + * Direct store accessor: loads gossip msg from store. + * + * Returns NULL if there are no more gossip msgs. + */ +u8 *gossip_store_iter(const tal_t *ctx, + int *gossip_store_fd, + struct gossip_state *gs, + struct gossip_rcvd_filter *grf, + size_t *off); + /** * Sets up the tiemstamp filter once they told us to set it.( */ void gossip_setup_timestamp_filter(struct per_peer_state *pps, u32 first_timestamp, u32 timestamp_range); + +/** + * Gossipd will be writing to this, and it's not atomic! Safest + * way to find the "end" is to walk through. + * @old_end: 1 if no previous end. + */ +size_t find_gossip_store_end(int gossip_store_fd, size_t old_end); + #endif /* LIGHTNING_COMMON_GOSSIP_STORE_H */ diff --git a/connectd/Makefile b/connectd/Makefile index a6de259850f3..fdf21e23e484 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -50,6 +50,7 @@ CONNECTD_COMMON_OBJS := \ common/ecdh_hsmd.o \ common/features.o \ common/status_wiregen.o \ + common/gossip_store.o \ common/gossip_rcvd_filter.o \ common/key_derive.o \ common/memleak.o \ @@ -71,6 +72,7 @@ CONNECTD_COMMON_OBJS := \ common/wireaddr.o \ common/wire_error.o \ gossipd/gossipd_wiregen.o \ + gossipd/gossip_store_wiregen.o \ wire/onion$(EXP)_wiregen.o lightningd/lightning_connectd: $(CONNECTD_OBJS) $(CONNECTD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(HSMD_CLIENT_OBJS) diff --git a/connectd/connectd.c b/connectd/connectd.c index 2fe0953991a9..f22f21d9937c 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -10,9 +10,7 @@ #include "config.h" #include #include -#include #include -#include #include #include #include @@ -20,9 +18,10 @@ #include #include #include +#include +#include #include #include -#include #include #include #include @@ -61,97 +60,6 @@ #define INITIAL_WAIT_SECONDS 1 #define MAX_WAIT_SECONDS 300 -/*~ We keep a hash table (ccan/htable) of peers, which tells us what peers are - * already connected (by peer->id). */ - -/*~ The HTABLE_DEFINE_TYPE() macro needs a keyof() function to extract the key: - */ -static const struct node_id *peer_keyof(const struct peer *peer) -{ - return &peer->id; -} - -/*~ We also need to define a hashing function. siphash24 is a fast yet - * cryptographic hash in ccan/crypto/siphash24; we might be able to get away - * with a slightly faster hash with fewer guarantees, but it's good hygiene to - * use this unless it's a proven bottleneck. siphash_seed() is a function in - * common/pseudorand which sets up a seed for our hashing; it's different - * every time the program is run. */ -static size_t node_id_hash(const struct node_id *id) -{ - return siphash24(siphash_seed(), id->k, sizeof(id->k)); -} - -/*~ We also define an equality function: is this element equal to this key? */ -static bool peer_eq_node_id(const struct peer *peer, - const struct node_id *id) -{ - return node_id_eq(&peer->id, id); -} - -/*~ This defines 'struct peer_htable' which contains 'struct peer' pointers. */ -HTABLE_DEFINE_TYPE(struct peer, - peer_keyof, - node_id_hash, - peer_eq_node_id, - peer_htable); - -/*~ This is the global state, like `struct lightningd *ld` in lightningd. */ -struct daemon { - /* Who am I? */ - struct node_id id; - - /* pubkey equivalent. */ - struct pubkey mykey; - - /* Base for timeout timers, and how long to wait for init msg */ - struct timers timers; - u32 timeout_secs; - - /* Peers that we've handed to `lightningd`, which it hasn't told us - * have disconnected. */ - struct peer_htable peers; - - /* Peers we are trying to reach */ - struct list_head connecting; - - /* Connection to main daemon. */ - struct daemon_conn *master; - - /* Allow localhost to be considered "public": DEVELOPER-only option, - * but for simplicity we don't #if DEVELOPER-wrap it here. */ - bool dev_allow_localhost; - - /* We support use of a SOCKS5 proxy (e.g. Tor) */ - struct addrinfo *proxyaddr; - - /* They can tell us we must use proxy even for non-Tor addresses. */ - bool always_use_proxy; - - /* There are DNS seeds we can use to look up node addresses as a last - * resort, but doing so leaks our address so can be disabled. */ - bool use_dns; - - /* The address that the broken response returns instead of - * NXDOMAIN. NULL if we have not detected a broken resolver. */ - struct sockaddr *broken_resolver_response; - - /* File descriptors to listen on once we're activated. */ - struct listen_fd *listen_fds; - - /* Allow to define the default behavior of tor services calls*/ - bool use_v3_autotor; - - /* Our features, as lightningd told us */ - struct feature_set *our_features; - - /* Subdaemon to proxy websocket requests. */ - char *websocket_helper; - - /* If non-zero, port to listen for websocket connections. */ - u16 websocket_port; -}; - /* Peers we're trying to reach: we iterate through addrs until we succeed * or fail. */ struct connecting { @@ -448,6 +356,7 @@ static struct peer *new_peer(struct daemon *daemon, { struct peer *peer = tal(daemon, struct peer); + peer->daemon = daemon; peer->id = *id; peer->cs = *cs; peer->final_msg = NULL; @@ -457,6 +366,7 @@ static struct peer *new_peer(struct daemon *daemon, peer->urgent = false; peer->peer_outq = msg_queue_new(peer); peer->subd_outq = msg_queue_new(peer); + peer->grf = new_gossip_rcvd_filter(peer); /* Aim for connection to shuffle data back and forth: sets up * peer->to_subd */ @@ -466,6 +376,8 @@ static struct peer *new_peer(struct daemon *daemon, peer->to_peer = tal_steal(peer, conn); peer_htable_add(&daemon->peers, peer); tal_add_destructor2(peer, destroy_peer, daemon); + + peer->gs = NULL; return peer; } @@ -550,6 +462,9 @@ struct io_plan *peer_connected(struct io_conn *conn, return tal_free(peer); } + /* Get ready for streaming gossip from the store */ + setup_peer_gossip_store(peer, daemon->our_features, their_features); + /* Create message to tell master peer has connected. */ msg = towire_connectd_peer_connected(NULL, id, addr, incoming, pps, their_features); @@ -1600,6 +1515,7 @@ static void connect_init(struct daemon *daemon, const u8 *msg) enum addr_listen_announce *proposed_listen_announce; struct wireaddr *announcable; char *tor_password; + bool dev_fast_gossip; bool dev_disconnect; /* Fields which require allocation are allocated off daemon */ @@ -1617,12 +1533,18 @@ static void connect_init(struct daemon *daemon, const u8 *msg) &daemon->timeout_secs, &daemon->websocket_helper, &daemon->websocket_port, + &dev_fast_gossip, &dev_disconnect)) { /* This is a helper which prints the type expected and the actual * message, then exits (it should never be called!). */ master_badmsg(WIRE_CONNECTD_INIT, msg); } +#if DEVELOPER + /*~ Clearly mark this as a developer-only flag! */ + daemon->dev_fast_gossip = dev_fast_gossip; +#endif + if (!pubkey_from_node_id(&daemon->mykey, &daemon->id)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Invalid id for me %s", @@ -2111,6 +2033,8 @@ int main(int argc, char *argv[]) list_head_init(&daemon->connecting); daemon->listen_fds = tal_arr(daemon, struct listen_fd, 0); timers_init(&daemon->timers, time_mono()); + daemon->gossip_store_fd = -1; + /* stdin == control */ daemon->master = daemon_conn_new(daemon, STDIN_FILENO, recv_req, NULL, daemon); diff --git a/connectd/connectd.h b/connectd/connectd.h index d78fc15c6dbd..09c79bd18e3a 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -2,14 +2,155 @@ #define LIGHTNING_CONNECTD_CONNECTD_H #include "config.h" #include +#include +#include +#include #include +#include +#include struct io_conn; struct connecting; -struct daemon; -struct node_id; struct wireaddr_internal; +/*~ We keep a hash table (ccan/htable) of peers, which tells us what peers are + * already connected (by peer->id). */ +struct peer { + /* Main daemon */ + struct daemon *daemon; + + /* The pubkey of the node */ + struct node_id id; + /* Counters and keys for symmetric crypto */ + struct crypto_state cs; + + /* Connection to the peer */ + struct io_conn *to_peer; + + /* Connection to the subdaemon */ + struct io_conn *to_subd; + + /* Final message to send to peer (and hangup) */ + u8 *final_msg; + + /* When we write something which wants Nagle overridden */ + bool urgent; + + /* Input buffers. */ + u8 *subd_in, *peer_in; + + /* Output buffers. */ + struct msg_queue *subd_outq, *peer_outq; + + /* Peer sent buffer (for freeing after sending) */ + const u8 *sent_to_peer; + + /* Gossip store. */ + struct gossip_state *gs; + /* FIXME: move into gs. */ + struct gossip_rcvd_filter *grf; + size_t gossip_store_off; + + struct oneshot *gossip_timer; +}; + +/*~ The HTABLE_DEFINE_TYPE() macro needs a keyof() function to extract the key: + */ +static const struct node_id *peer_keyof(const struct peer *peer) +{ + return &peer->id; +} + +/*~ We also need to define a hashing function. siphash24 is a fast yet + * cryptographic hash in ccan/crypto/siphash24; we might be able to get away + * with a slightly faster hash with fewer guarantees, but it's good hygiene to + * use this unless it's a proven bottleneck. siphash_seed() is a function in + * common/pseudorand which sets up a seed for our hashing; it's different + * every time the program is run. */ +static size_t node_id_hash(const struct node_id *id) +{ + return siphash24(siphash_seed(), id->k, sizeof(id->k)); +} + +/*~ We also define an equality function: is this element equal to this key? */ +static bool peer_eq_node_id(const struct peer *peer, + const struct node_id *id) +{ + return node_id_eq(&peer->id, id); +} + +/*~ This defines 'struct peer_htable' which contains 'struct peer' pointers. */ +HTABLE_DEFINE_TYPE(struct peer, + peer_keyof, + node_id_hash, + peer_eq_node_id, + peer_htable); + +/*~ This is the global state, like `struct lightningd *ld` in lightningd. */ +struct daemon { + /* Who am I? */ + struct node_id id; + + /* pubkey equivalent. */ + struct pubkey mykey; + + /* Base for timeout timers, and how long to wait for init msg */ + struct timers timers; + u32 timeout_secs; + + /* Peers that we've handed to `lightningd`, which it hasn't told us + * have disconnected. */ + struct peer_htable peers; + + /* Peers we are trying to reach */ + struct list_head connecting; + + /* Connection to main daemon. */ + struct daemon_conn *master; + + /* Allow localhost to be considered "public": DEVELOPER-only option, + * but for simplicity we don't #if DEVELOPER-wrap it here. */ + bool dev_allow_localhost; + + /* We support use of a SOCKS5 proxy (e.g. Tor) */ + struct addrinfo *proxyaddr; + + /* They can tell us we must use proxy even for non-Tor addresses. */ + bool always_use_proxy; + + /* There are DNS seeds we can use to look up node addresses as a last + * resort, but doing so leaks our address so can be disabled. */ + bool use_dns; + + /* The address that the broken response returns instead of + * NXDOMAIN. NULL if we have not detected a broken resolver. */ + struct sockaddr *broken_resolver_response; + + /* File descriptors to listen on once we're activated. */ + struct listen_fd *listen_fds; + + /* Allow to define the default behavior of tor services calls*/ + bool use_v3_autotor; + + /* Our features, as lightningd told us */ + struct feature_set *our_features; + + /* Subdaemon to proxy websocket requests. */ + char *websocket_helper; + + /* If non-zero, port to listen for websocket connections. */ + u16 websocket_port; + + /* The gossip_store */ + int gossip_store_fd; + size_t gossip_store_end; + +#if DEVELOPER + /* Hack to speed up gossip timer */ + bool dev_fast_gossip; +#endif +}; + /* Called by io_tor_connect once it has a connection out. */ struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect); diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index 351f78d31039..bb5d0296f78e 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -21,6 +21,7 @@ msgdata,connectd_init,use_v3_autotor,bool, msgdata,connectd_init,timeout_secs,u32, msgdata,connectd_init,websocket_helper,wirestring, msgdata,connectd_init,websocket_port,u16, +msgdata,connectd_init,dev_fast_gossip,bool, # If this is set, then fd 5 is dev_disconnect_fd. msgdata,connectd_init,dev_disconnect,bool, diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 25bb6be0c340..f77a5e5da7c0 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -2,17 +2,28 @@ * itself, and the subdaemons. */ #include "config.h" #include +#include +#include #include #include #include +#include +#include +#include +#include #include #include +#include #include +#include +#include #include #include +#include #include #include #include +#include #include #include #include @@ -23,6 +34,117 @@ void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) msg_enqueue(peer->peer_outq, msg); } +/* Send warning, close connection to peer */ +static void send_warning(struct peer *peer, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + status_vfmt(LOG_UNUSUAL, &peer->id, fmt, ap); + va_end(ap); + + /* Close locally, send msg as final warning */ + io_close(peer->to_subd); + + va_start(ap, fmt); + peer->final_msg = towire_warningfmtv(peer, NULL, fmt, ap); + va_end(ap); +} + +/* Either for initial setup, or when they ask by timestamp */ +static bool setup_gossip_filter(struct peer *peer, + u32 first_timestamp, + u32 timestamp_range) +{ + bool immediate_sync; + + /* If this is the first filter, we gossip sync immediately. */ + if (!peer->gs) { + peer->gs = tal(peer, struct gossip_state); + peer->gs->next_gossip = time_mono(); + immediate_sync = true; + } else + immediate_sync = false; + + /* BOLT #7: + * + * The receiver: + * - SHOULD send all gossip messages whose `timestamp` is greater or + * equal to `first_timestamp`, and less than `first_timestamp` plus + * `timestamp_range`. + * - MAY wait for the next outgoing gossip flush to send these. + * ... + * - SHOULD restrict future gossip messages to those whose `timestamp` + * is greater or equal to `first_timestamp`, and less than + * `first_timestamp` plus `timestamp_range`. + */ + peer->gs->timestamp_min = first_timestamp; + peer->gs->timestamp_max = first_timestamp + timestamp_range - 1; + /* Make sure we never leave it on an impossible value. */ + if (peer->gs->timestamp_max < peer->gs->timestamp_min) + peer->gs->timestamp_max = UINT32_MAX; + + peer->gossip_store_off = 1; + return immediate_sync; +} + +/* This is called once we need it: otherwise, the gossip_store may not exist, + * since we start at the same time as gossipd itself. */ +static void setup_gossip_store(struct daemon *daemon) +{ + daemon->gossip_store_fd = open(GOSSIP_STORE_FILENAME, O_RDONLY); + if (daemon->gossip_store_fd < 0) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Opening gossip_store %s: %s", + GOSSIP_STORE_FILENAME, strerror(errno)); + /* gossipd will be writing to this, and it's not atomic! Safest + * way to find the "end" is to walk through. */ + daemon->gossip_store_end + = find_gossip_store_end(daemon->gossip_store_fd, 1); +} + +void setup_peer_gossip_store(struct peer *peer, + const struct feature_set *our_features, + const u8 *their_features) +{ + /* Lazy setup */ + if (peer->daemon->gossip_store_fd == -1) + setup_gossip_store(peer->daemon); + + peer->gossip_timer = NULL; + + /* BOLT #7: + * + * A node: + * - if the `gossip_queries` feature is negotiated: + * - MUST NOT relay any gossip messages it did not generate itself, + * unless explicitly requested. + */ + if (feature_negotiated(our_features, their_features, OPT_GOSSIP_QUERIES)) + return; + + setup_gossip_filter(peer, 0, UINT32_MAX); + + /* 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. + */ + if (!feature_offered(their_features, OPT_INITIAL_ROUTING_SYNC)) { + /* During tests, particularly, we find that the gossip_store + * moves fast, so make sure it really does start at the end. */ + peer->gossip_store_off + = find_gossip_store_end(peer->daemon->gossip_store_fd, + peer->daemon->gossip_store_end); + } +} + /* These four function handle subd->peer */ static struct io_plan *after_final_msg(struct io_conn *peer_conn, struct peer *peer) @@ -138,6 +260,94 @@ static struct io_plan *encrypt_and_send(struct peer *peer, next, peer); } +/* FIXME: Put in ccan/time */ +/* Is a before b? */ +static inline bool timemono_before(struct timemono a, struct timemono b) +{ + return time_less_(a.ts, b.ts); +} + +/* Kicks off write_to_peer() to look for more gossip to send from store */ +static void wake_gossip(struct peer *peer) +{ + peer->gossip_timer = NULL; + io_wake(peer->peer_outq); +} + +/* If we are streaming gossip, get something from gossip store */ +static u8 *maybe_from_gossip_store(const tal_t *ctx, struct peer *peer) +{ + u8 *msg; + + /* Not streaming yet? */ + if (!peer->gs) + return NULL; + + /* Still waiting for timer? */ + if (peer->gossip_timer != NULL) + return NULL; + + msg = gossip_store_iter(ctx, &peer->daemon->gossip_store_fd, + peer->gs, peer->grf, &peer->gossip_store_off); + + /* Cache highest valid offset (FIXME: doesn't really work when + * gossip_store gets rewritten!) */ + if (peer->gossip_store_off > peer->daemon->gossip_store_end) + peer->daemon->gossip_store_end = peer->gossip_store_off; + + if (msg) { + status_peer_io(LOG_IO_OUT, &peer->id, msg); + return msg; + } + + /* 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). + */ + /* We do 60 seconds from *start*, not from *now* */ + peer->gs->next_gossip + = timemono_add(time_mono(), + time_from_sec(GOSSIP_FLUSH_INTERVAL( + peer->daemon->dev_fast_gossip))); + peer->gossip_timer = new_abstimer(&peer->daemon->timers, peer, + peer->gs->next_gossip, + wake_gossip, peer); + return NULL; +} + +/* We only handle gossip_timestamp_filter for now */ +static bool handle_message_locally(struct peer *peer, const u8 *msg) +{ + struct bitcoin_blkid chain_hash; + u32 first_timestamp, timestamp_range; + + /* We remember these so we don't rexmit them */ + if (is_msg_gossip_broadcast(msg)) + gossip_rcvd_filter_add(peer->grf, msg); + + if (!fromwire_gossip_timestamp_filter(msg, &chain_hash, + &first_timestamp, + ×tamp_range)) { + return false; + } + + if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain_hash)) { + send_warning(peer, "gossip_timestamp_filter for bad chain: %s", + tal_hex(tmpctx, msg)); + return true; + } + + /* Returns true the first time. */ + if (setup_gossip_filter(peer, first_timestamp, timestamp_range)) + wake_gossip(peer); + return true; +} + static struct io_plan *write_to_peer(struct io_conn *peer_conn, struct peer *peer) { @@ -159,15 +369,19 @@ static struct io_plan *write_to_peer(struct io_conn *peer_conn, after_final_msg); } - /* Reset urgent flag, if set. */ - set_urgent_flag(peer, false); + /* If they want us to send gossip, do so now. */ + msg = maybe_from_gossip_store(NULL, peer); + if (!msg) { + /* Reset urgent flag, if set. */ + set_urgent_flag(peer, false); - /* Tell them to read again, */ - io_wake(&peer->subd_in); + /* Tell them to read again, */ + io_wake(&peer->subd_in); - /* Wait for them to wake us */ - return msg_queue_wait(peer_conn, peer->peer_outq, - write_to_peer, peer); + /* Wait for them to wake us */ + return msg_queue_wait(peer_conn, peer->peer_outq, + write_to_peer, peer); + } } return encrypt_and_send(peer, take(msg), write_to_peer); @@ -229,6 +443,12 @@ static struct io_plan *read_body_from_peer_done(struct io_conn *peer_conn, return io_close(peer_conn); tal_free(peer->peer_in); + /* If we swallow this, just try again. */ + if (handle_message_locally(peer, decrypted)) { + tal_free(decrypted); + return read_hdr_from_peer(peer_conn, peer); + } + /* Tell them to write. */ msg_enqueue(peer->subd_outq, take(decrypted)); diff --git a/connectd/multiplex.h b/connectd/multiplex.h index ccd037939fd0..524e4829966a 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -6,32 +6,9 @@ #include #include -struct peer { - struct node_id id; - /* Counters and keys for symmetric crypto */ - struct crypto_state cs; - - /* Connection to the peer */ - struct io_conn *to_peer; - - /* Connection to the subdaemon */ - struct io_conn *to_subd; - - /* Final message to send to peer (and hangup) */ - u8 *final_msg; - - /* When we write something which wants Nagle overridden */ - bool urgent; - - /* Input buffers. */ - u8 *subd_in, *peer_in; - - /* Output buffers. */ - struct msg_queue *subd_outq, *peer_outq; - - /* Peer sent buffer (for freeing after sending) */ - const u8 *sent_to_peer; -}; +struct peer; +struct io_conn; +struct feature_set; /* Set up peer->to_subd; sets fd_for_subd to pass to lightningd. */ bool multiplex_subd_setup(struct peer *peer, int *fd_for_subd); @@ -47,4 +24,7 @@ void multiplex_final_msg(struct peer *peer, /* Inject a message into the output stream */ void queue_peer_msg(struct peer *peer, const u8 *msg TAKES); +void setup_peer_gossip_store(struct peer *peer, + const struct feature_set *our_features, + const u8 *their_features); #endif /* LIGHTNING_CONNECTD_MULTIPLEX_H */ diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index e6bb2909266c..c7a28589c707 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -395,6 +395,7 @@ int connectd_init(struct lightningd *ld) ld->config.connection_timeout_secs, websocket_helper_path, ld->websocket_port, + IFDEV(ld->dev_fast_gossip, false), IFDEV(ld->dev_disconnect_fd >= 0, false)); subd_req(ld->connectd, ld->connectd, take(msg), -1, 0, diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 018989e41493..49d72a31907e 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1330,7 +1330,8 @@ def test_gossipwith(node_factory): num_msgs += 1 # one channel announcement, two channel_updates, two node announcements. - assert num_msgs == 5 + # FIXME: Currently gets double gossip! + assert num_msgs == 5 * 2 def test_gossip_notices_close(node_factory, bitcoind): From d131293bc0aea823ea92606593fae2203625d7d8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:09 +1030 Subject: [PATCH 24/51] subdaemons: don't stream gossip_store at all. We now let gossipd do it. This also means there's nothing left in 'struct per_peer_state' to send across the wire (the fds are sent separately), so that gets removed from wire messages too. Signed-off-by: Rusty Russell --- channeld/channeld.c | 39 +++------ channeld/channeld_wire.csv | 3 - closingd/closingd.c | 11 ++- closingd/closingd_wire.csv | 3 - common/gossip_store.c | 51 ----------- common/gossip_store.h | 16 ---- common/peer_failed.c | 4 +- common/peer_status_wire.csv | 1 - common/per_peer_state.c | 95 ++------------------- common/per_peer_state.h | 32 +------ common/read_peer_msg.c | 67 +++------------ connectd/connectd.c | 34 +++----- connectd/connectd_gossipd_wire.csv | 7 +- connectd/connectd_wire.csv | 3 - gossipd/gossipd.c | 55 +----------- gossipd/test/run-onion_message.c | 7 +- hsmd/hsmd.c | 3 + lightningd/channel_control.c | 10 +-- lightningd/closing_control.c | 3 - lightningd/connect_control.c | 6 +- lightningd/dual_open_control.c | 21 +++-- lightningd/opening_common.c | 5 +- lightningd/opening_control.c | 30 +++---- lightningd/peer_control.c | 11 +-- lightningd/peer_control.h | 2 +- lightningd/subd.c | 9 +- lightningd/test/run-find_my_abspath.c | 5 +- lightningd/test/run-invoice-select-inchan.c | 9 +- lightningd/test/run-shuffle_fds.c | 5 +- openingd/dualopend.c | 45 +++------- openingd/dualopend_wire.csv | 5 -- openingd/openingd.c | 43 ++-------- openingd/openingd_wire.csv | 6 -- tests/test_gossip.py | 3 +- wallet/test/run-wallet.c | 9 +- 35 files changed, 148 insertions(+), 510 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index b9a660524dc0..2cccbfefb32c 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -45,9 +46,9 @@ #include #include -/* stdin == requests, 3 == peer, 4 = gossip, 5 = gossip_store, 6 = HSM */ +/* stdin == requests, 3 == peer, 4 = gossip, 5 = HSM */ #define MASTER_FD STDIN_FILENO -#define HSM_FD 6 +#define HSM_FD 5 enum pong_expect_type { /* We weren't expecting a ping reply */ @@ -160,6 +161,9 @@ struct peer { #if DEVELOPER /* If set, don't fire commit counter when this hits 0 */ u32 *dev_disable_commit; + + /* If set, send channel_announcement after 1 second, not 30 */ + bool dev_fast_gossip; #endif /* Information used for reestablishment. */ bool last_was_revoke; @@ -638,7 +642,7 @@ static void channel_announcement_negotiate(struct peer *peer) /* Give other nodes time to notice new block. */ notleak(new_reltimer(&peer->timers, peer, - time_from_sec(GOSSIP_ANNOUNCE_DELAY(dev_fast_gossip)), + time_from_sec(GOSSIP_ANNOUNCE_DELAY(peer->dev_fast_gossip)), announce_channel, peer)); } } @@ -980,7 +984,7 @@ static void send_shutdown_complete(struct peer *peer) { /* Now we can tell master shutdown is complete. */ wire_sync_write(MASTER_FD, - take(towire_channeld_shutdown_complete(NULL, peer->pps))); + take(towire_channeld_shutdown_complete(NULL))); per_peer_state_fdpass_send(MASTER_FD, peer->pps); close(MASTER_FD); } @@ -3839,6 +3843,7 @@ static void init_channel(struct peer *peer) u8 *reestablish_only; struct channel_type *channel_type; u32 *dev_disable_commit; /* Always NULL */ + bool dev_fast_gossip; #if !DEVELOPER bool dev_fail_process_onionpacket; /* Ignored */ #endif @@ -3862,7 +3867,6 @@ static void init_channel(struct peer *peer) &peer->feerate_max, &peer->feerate_penalty, &peer->their_commit_sig, - &peer->pps, &funding_pubkey[REMOTE], &points[REMOTE], &peer->remote_per_commit, @@ -3910,6 +3914,7 @@ static void init_channel(struct peer *peer) #if DEVELOPER peer->dev_disable_commit = dev_disable_commit; + peer->dev_fast_gossip = dev_fast_gossip; #endif status_debug("option_static_remotekey = %u, option_anchor_outputs = %u", @@ -3924,8 +3929,9 @@ static void init_channel(struct peer *peer) tal_dup(peer, struct penalty_base, &pbases[i])); tal_free(pbases); - /* stdin == requests, 3 == peer, 4 = gossip, 5 = gossip_store, 6 = HSM */ - per_peer_state_set_fds(peer->pps, 3, 4, 5); + /* stdin == requests, 3 == peer, 4 = gossip */ + peer->pps = new_per_peer_state(peer); + per_peer_state_set_fds(peer->pps, 3, 4); status_debug("init %s: remote_per_commit = %s, old_remote_per_commit = %s" " next_idx_local = %"PRIu64 @@ -4019,14 +4025,6 @@ static void init_channel(struct peer *peer) billboard_update(peer); } -static void try_read_gossip_store(struct peer *peer) -{ - u8 *msg = gossip_store_next(tmpctx, peer->pps); - - if (msg) - peer_write(peer->pps, take(msg)); -} - int main(int argc, char *argv[]) { setup_locale(); @@ -4088,7 +4086,6 @@ int main(int argc, char *argv[]) struct timeval timeout, *tptr; struct timer *expired; const u8 *msg; - struct timerel trel; struct timemono now = time_mono(); /* Free any temporary allocations */ @@ -4120,13 +4117,6 @@ int main(int argc, char *argv[]) tptr = &timeout; } - /* If timer to next gossip is sooner, use that instead. */ - if (time_to_next_gossip(peer->pps, &trel) - && (!tptr || time_less(trel, timeval_to_timerel(*tptr)))) { - timeout = timerel_to_timeval(trel); - tptr = &timeout; - } - if (select(nfds, &rfds, NULL, NULL, tptr) < 0) { /* Signals OK, eg. SIGUSR1 */ if (errno == EINTR) @@ -4154,8 +4144,7 @@ int main(int argc, char *argv[]) if (!msg) peer_failed_connection_lost(); 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. */ diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index f2eca498d7bb..f095b3cb5f61 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -8,7 +8,6 @@ #include #include #include -#include # Begin! (passes gossipd-client fd) msgtype,channeld_init,1000 @@ -28,7 +27,6 @@ msgdata,channeld_init,feerate_min,u32, msgdata,channeld_init,feerate_max,u32, msgdata,channeld_init,feerate_penalty,u32, msgdata,channeld_init,first_commit_sig,bitcoin_signature, -msgdata,channeld_init,per_peer_state,per_peer_state, msgdata,channeld_init,remote_fundingkey,pubkey, msgdata,channeld_init,remote_basepoints,basepoints, msgdata,channeld_init,remote_per_commit,pubkey, @@ -187,7 +185,6 @@ msgdata,channeld_got_shutdown,wrong_funding,?bitcoin_outpoint, # Shutdown is complete, ready for closing negotiation. + peer_fd & gossip_fd. msgtype,channeld_shutdown_complete,1025 -msgdata,channeld_shutdown_complete,per_peer_state,per_peer_state, # Re-enable commit timer. msgtype,channeld_dev_reenable_commit,1026 diff --git a/closingd/closingd.c b/closingd/closingd.c index 84dc438b5d8b..9fb74e4ba899 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -31,9 +31,9 @@ #include #include -/* stdin == requests, 3 == peer, 4 = gossip, 5 = gossip_store, 6 = hsmd */ +/* stdin == requests, 3 == peer, 4 = gossip, 5 = hsmd */ #define REQ_FD STDIN_FILENO -#define HSM_FD 6 +#define HSM_FD 5 static void notify(enum log_level level, const char *fmt, ...) { @@ -897,7 +897,6 @@ int main(int argc, char *argv[]) msg = wire_sync_read(tmpctx, REQ_FD); if (!fromwire_closingd_init(ctx, msg, &chainparams, - &pps, &channel_id, &funding, &funding_sats, @@ -914,12 +913,12 @@ int main(int argc, char *argv[]) &fee_negotiation_step, &fee_negotiation_step_unit, &use_quickclose, - &dev_fast_gossip, &wrong_funding)) master_badmsg(WIRE_CLOSINGD_INIT, msg); - /* stdin == requests, 3 == peer, 4 = gossip, 5 = gossip_store, 6 = hsmd */ - per_peer_state_set_fds(notleak(pps), 3, 4, 5); + /* stdin == requests, 3 == peer, 4 = gossip, 5 = hsmd */ + pps = notleak(new_per_peer_state(ctx)); + per_peer_state_set_fds(pps, 3, 4); funding_wscript = bitcoin_redeem_2of2(ctx, &funding_pubkey[LOCAL], diff --git a/closingd/closingd_wire.csv b/closingd/closingd_wire.csv index a6b066d739a3..94ab71c757e0 100644 --- a/closingd/closingd_wire.csv +++ b/closingd/closingd_wire.csv @@ -2,12 +2,10 @@ #include #include #include -#include #include # Begin! (passes peer fd, gossipd-client fd) msgtype,closingd_init,2001 msgdata,closingd_init,chainparams,chainparams, -msgdata,closingd_init,pps,per_peer_state, msgdata,closingd_init,channel_id,channel_id, msgdata,closingd_init,funding,bitcoin_outpoint, msgdata,closingd_init,funding_satoshi,amount_sat, @@ -28,7 +26,6 @@ msgdata,closingd_init,remote_scriptpubkey,u8,remote_scriptpubkey_len msgdata,closingd_init,fee_negotiation_step,u64, msgdata,closingd_init,fee_negotiation_step_unit,u8, msgdata,closingd_init,use_quickclose,bool, -msgdata,closingd_init,dev_fast_gossip,bool, msgdata,closingd_init,shutdown_wrong_funding,?bitcoin_outpoint, # Message for any commands waiting. diff --git a/common/gossip_store.c b/common/gossip_store.c index a2b3cb11e5e2..191e9d8b6d8c 100644 --- a/common/gossip_store.c +++ b/common/gossip_store.c @@ -11,39 +11,6 @@ #include #include -void gossip_setup_timestamp_filter(struct per_peer_state *pps, - u32 first_timestamp, - u32 timestamp_range) -{ - /* If this is the first filter, we gossip sync immediately. */ - if (!pps->gs) { - pps->gs = tal(pps, struct gossip_state); - pps->gs->next_gossip = time_mono(); - } - - pps->gs->timestamp_min = first_timestamp; - pps->gs->timestamp_max = first_timestamp + timestamp_range - 1; - /* Make sure we never leave it on an impossible value. */ - if (pps->gs->timestamp_max < pps->gs->timestamp_min) - pps->gs->timestamp_max = UINT32_MAX; - - /* BOLT #7: - * - * The receiver: - * - SHOULD send all gossip messages whose `timestamp` is greater or - * equal to `first_timestamp`, and less than `first_timestamp` plus - * `timestamp_range`. - * - MAY wait for the next outgoing gossip flush to send these. - * ... - * - SHOULD restrict future gossip messages to those whose `timestamp` - * is greater or equal to `first_timestamp`, and less than - * `first_timestamp` plus `timestamp_range`. - */ - - /* Restart just after header. */ - lseek(pps->gossip_store_fd, 1, SEEK_SET); -} - static bool timestamp_filter(const struct gossip_state *gs, u32 timestamp) { /* BOLT #7: @@ -182,24 +149,6 @@ u8 *gossip_store_iter(const tal_t *ctx, return msg; } -u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps) -{ - u8 *msg; - - /* Don't read until we're initialized. */ - if (!pps->gs) - return NULL; - - /* FIXME: We are only caller using off == NULL */ - msg = gossip_store_iter(ctx, &pps->gossip_store_fd, - pps->gs, pps->grf, NULL); - - if (!msg) - per_peer_state_reset_gossip_timer(pps); - - return msg; -} - size_t find_gossip_store_end(int gossip_store_fd, size_t off) { /* We cheat and read first two bytes of message too. */ diff --git a/common/gossip_store.h b/common/gossip_store.h index c109c8625817..e1d760860ae6 100644 --- a/common/gossip_store.h +++ b/common/gossip_store.h @@ -5,7 +5,6 @@ #include #include -struct per_peer_state; struct gossip_state; struct gossip_rcvd_filter; @@ -37,14 +36,6 @@ struct gossip_hdr { beint32_t timestamp; /* timestamp of msg. */ }; -/** - * Direct store accessor: loads gossip msg from store. - * - * Returns NULL and resets time_to_next_gossip(pps) if there are no - * more gossip msgs. - */ -u8 *gossip_store_next(const tal_t *ctx, struct per_peer_state *pps); - /** * Direct store accessor: loads gossip msg from store. * @@ -56,13 +47,6 @@ u8 *gossip_store_iter(const tal_t *ctx, struct gossip_rcvd_filter *grf, size_t *off); -/** - * Sets up the tiemstamp filter once they told us to set it.( - */ -void gossip_setup_timestamp_filter(struct per_peer_state *pps, - u32 first_timestamp, - u32 timestamp_range); - /** * Gossipd will be writing to this, and it's not atomic! Safest * way to find the "end" is to walk through. diff --git a/common/peer_failed.c b/common/peer_failed.c index 909161b650c3..e9f5487dafdc 100644 --- a/common/peer_failed.c +++ b/common/peer_failed.c @@ -20,7 +20,6 @@ peer_fatal_continue(const u8 *msg TAKES, const struct per_peer_state *pps) status_send_fd(pps->peer_fd); status_send_fd(pps->gossip_fd); - status_send_fd(pps->gossip_store_fd); exit(0x80 | (reason & 0xFF)); } @@ -44,7 +43,6 @@ peer_failed(struct per_peer_state *pps, msg = towire_status_peer_error(NULL, channel_id, desc, warn, - pps, msg); peer_billboard(true, desc); peer_fatal_continue(take(msg), pps); @@ -87,7 +85,7 @@ void peer_failed_received_errmsg(struct per_peer_state *pps, { u8 *msg; - msg = towire_status_peer_error(NULL, channel_id, desc, warning, pps, + msg = towire_status_peer_error(NULL, channel_id, desc, warning, NULL); peer_billboard(true, "Received %s", desc); peer_fatal_continue(take(msg), pps); diff --git a/common/peer_status_wire.csv b/common/peer_status_wire.csv index 8162443e2ffb..1fedb7ccc678 100644 --- a/common/peer_status_wire.csv +++ b/common/peer_status_wire.csv @@ -8,6 +8,5 @@ msgdata,status_peer_error,channel,channel_id, msgdata,status_peer_error,desc,wirestring, # Take a deep breath, then try reconnecting to the precious little snowflake. msgdata,status_peer_error,warning,bool, -msgdata,status_peer_error,pps,per_peer_state, msgdata,status_peer_error,len,u16, msgdata,status_peer_error,error_for_them,u8,len diff --git a/common/per_peer_state.c b/common/per_peer_state.c index de11384e272e..b33305538d27 100644 --- a/common/per_peer_state.c +++ b/common/per_peer_state.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -15,121 +14,37 @@ static void destroy_per_peer_state(struct per_peer_state *pps) close(pps->peer_fd); if (pps->gossip_fd != -1) close(pps->gossip_fd); - if (pps->gossip_store_fd != -1) - close(pps->gossip_store_fd); } struct per_peer_state *new_per_peer_state(const tal_t *ctx) { struct per_peer_state *pps = tal(ctx, struct per_peer_state); - pps->gs = NULL; - pps->peer_fd = pps->gossip_fd = pps->gossip_store_fd = -1; - pps->grf = new_gossip_rcvd_filter(pps); + pps->peer_fd = pps->gossip_fd = -1; tal_add_destructor(pps, destroy_per_peer_state); return pps; } void per_peer_state_set_fds(struct per_peer_state *pps, - int peer_fd, int gossip_fd, int gossip_store_fd) + int peer_fd, int gossip_fd) { assert(pps->peer_fd == -1); assert(pps->gossip_fd == -1); - assert(pps->gossip_store_fd == -1); pps->peer_fd = peer_fd; pps->gossip_fd = gossip_fd; - pps->gossip_store_fd = gossip_store_fd; } void per_peer_state_set_fds_arr(struct per_peer_state *pps, const int *fds) { - /* We expect 3 fds. */ - assert(tal_count(fds) == 3); - 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); - towire_u32(pptr, gs->timestamp_min); - towire_u32(pptr, gs->timestamp_max); -} - -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); - gs->timestamp_min = fromwire_u32(cursor, max); - gs->timestamp_max = fromwire_u32(cursor, max); -} - -void towire_per_peer_state(u8 **pptr, const struct per_peer_state *pps) -{ - towire_bool(pptr, pps->gs != NULL); - if (pps->gs) - towire_gossip_state(pptr, pps->gs); - /* We don't pass the gossip_rcvd_filter: it's merely an optimization */ + /* We expect 2 fds. */ + assert(tal_count(fds) == 2); + per_peer_state_set_fds(pps, fds[0], fds[1]); } void per_peer_state_fdpass_send(int fd, const struct per_peer_state *pps) { assert(pps->peer_fd != -1); assert(pps->gossip_fd != -1); - assert(pps->gossip_store_fd != -1); fdpass_send(fd, pps->peer_fd); fdpass_send(fd, pps->gossip_fd); - fdpass_send(fd, pps->gossip_store_fd); -} - -struct per_peer_state *fromwire_per_peer_state(const tal_t *ctx, - const u8 **cursor, size_t *max) -{ - struct per_peer_state *pps; - - pps = new_per_peer_state(ctx); - 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(GOSSIP_FLUSH_INTERVAL(dev_fast_gossip)); - - pps->gs->next_gossip = timemono_add(time_mono(), t); - gossip_rcvd_filter_age(pps->grf); } diff --git a/common/per_peer_state.h b/common/per_peer_state.h index e5e3b914cb6f..a81360ab3485 100644 --- a/common/per_peer_state.h +++ b/common/per_peer_state.h @@ -15,45 +15,21 @@ struct gossip_state { /* Things we hand between daemons to talk to peers. */ struct per_peer_state { - /* NULL if it's not initialized yet */ - struct gossip_state *gs; - /* Cache of msgs we have received, to avoid re-xmitting from store */ - struct gossip_rcvd_filter *grf; /* If not -1, closed on freeing */ - int peer_fd, gossip_fd, gossip_store_fd; + int peer_fd, gossip_fd; }; /* Allocate a new per-peer state and add destructor to close fds if set; - * sets fds to -1 and ->gs to NULL.. */ + * sets fds to -1. */ struct per_peer_state *new_per_peer_state(const tal_t *ctx); /* Initialize the fds (must be -1 previous) */ void per_peer_state_set_fds(struct per_peer_state *pps, - int peer_fd, int gossip_fd, int gossip_store_fd); + int peer_fd, int gossip_fd); -/* Array version of above: tal_count(fds) must be 3 */ +/* Array version of above: tal_count(fds) must be 2 */ void per_peer_state_set_fds_arr(struct per_peer_state *pps, const int *fds); -/* These routines do *part* of the work: you need to per_peer_state_fdpass_send - * or receive the three fds afterwards! */ -void towire_per_peer_state(u8 **pptr, const struct per_peer_state *pps); 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, - 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); - -/* Used to speed up gossip iff DEVELOPER*/ -extern bool dev_fast_gossip; - #endif /* LIGHTNING_COMMON_PER_PEER_STATE_H */ diff --git a/common/read_peer_msg.c b/common/read_peer_msg.c index a1c0405e49a4..fe841108c6c4 100644 --- a/common/read_peer_msg.c +++ b/common/read_peer_msg.c @@ -1,8 +1,6 @@ #include "config.h" #include #include -#include -#include #include #include #include @@ -21,31 +19,15 @@ u8 *peer_or_gossip_sync_read(const tal_t *ctx, fd_set readfds; u8 *msg; - for (;;) { - struct timeval tv, *tptr; - struct timerel trel; - - if (time_to_next_gossip(pps, &trel)) { - tv = timerel_to_timeval(trel); - 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; - } + 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, NULL) <= 0) { + status_failed(STATUS_FAIL_GOSSIP_IO, + "select failed?: %s", strerror(errno)); } if (FD_ISSET(pps->peer_fd, &readfds)) { @@ -128,31 +110,6 @@ void handle_gossip_msg(struct per_peer_state *pps, const u8 *msg TAKES) } } -/* takes iff returns true */ -bool handle_timestamp_filter(struct per_peer_state *pps, const u8 *msg TAKES) -{ - struct bitcoin_blkid chain_hash; - u32 first_timestamp, timestamp_range; - - if (!fromwire_gossip_timestamp_filter(msg, &chain_hash, - &first_timestamp, - ×tamp_range)) { - return false; - } - - if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain_hash)) { - peer_write(pps, - take(towire_warningfmt(NULL, NULL, - "gossip_timestamp_filter" - " for bad chain: %s", - tal_hex(tmpctx, take(msg))))); - return true; - } - - gossip_setup_timestamp_filter(pps, first_timestamp, timestamp_range); - return true; -} - bool handle_peer_gossip_or_error(struct per_peer_state *pps, const struct channel_id *channel_id, bool soft_error, @@ -177,15 +134,11 @@ bool handle_peer_gossip_or_error(struct per_peer_state *pps, goto handled; #endif - if (handle_timestamp_filter(pps, msg)) - return true; - else if (check_ping_make_pong(NULL, msg, &pong)) { + if (check_ping_make_pong(NULL, msg, &pong)) { if (pong) peer_write(pps, take(pong)); return true; } else if (is_msg_for_gossipd(msg)) { - if (is_msg_gossip_broadcast(msg)) - gossip_rcvd_filter_add(pps->grf, msg); wire_sync_write(pps->gossip_fd, msg); /* wire_sync_write takes, so don't take again. */ return true; diff --git a/connectd/connectd.c b/connectd/connectd.c index f22f21d9937c..a3c939acbbcd 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -223,7 +223,7 @@ static bool get_gossipfds(struct daemon *daemon, const u8 *their_features, struct per_peer_state *pps) { - bool gossip_queries_feature, initial_routing_sync, success; + bool gossip_queries_feature, success; u8 *msg; /*~ The way features generally work is that both sides need to offer it; @@ -232,23 +232,16 @@ static bool get_gossipfds(struct daemon *daemon, = feature_negotiated(daemon->our_features, their_features, OPT_GOSSIP_QUERIES); - /*~ `initial_routing_sync` is supported by every node, since it was in - * the initial lightning specification: it means the peer wants the - * backlog of existing gossip. */ - initial_routing_sync - = feature_offered(their_features, OPT_INITIAL_ROUTING_SYNC); - /*~ We do this communication sync, since gossipd is our friend and * it's easier. If gossipd fails, we fail. */ - msg = towire_gossipd_new_peer(NULL, id, gossip_queries_feature, - initial_routing_sync); + msg = towire_gossipd_new_peer(NULL, id, gossip_queries_feature); if (!wire_sync_write(GOSSIPCTL_FD, take(msg))) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Failed writing to gossipctl: %s", strerror(errno)); msg = wire_sync_read(tmpctx, GOSSIPCTL_FD); - if (!fromwire_gossipd_new_peer_reply(pps, msg, &success, &pps->gs)) + if (!fromwire_gossipd_new_peer_reply(msg, &success)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Failed parsing msg gossipctl: %s", tal_hex(tmpctx, msg)); @@ -261,10 +254,9 @@ static bool get_gossipfds(struct daemon *daemon, return false; } - /* Otherwise, the next thing in the socket will be the file descriptors + /* Otherwise, the next thing in the socket will be the file descriptor * for the per-peer daemon. */ pps->gossip_fd = fdpass_recv(GOSSIPCTL_FD); - pps->gossip_store_fd = fdpass_recv(GOSSIPCTL_FD); return true; } @@ -454,6 +446,7 @@ struct io_plan *peer_connected(struct io_conn *conn, if (!peer) return io_close(conn); + /* FIXME: Remove pps abstraction! */ pps = new_per_peer_state(tmpctx); /* If gossipd can't give us a file descriptor, we give up connecting. */ @@ -467,7 +460,7 @@ struct io_plan *peer_connected(struct io_conn *conn, /* Create message to tell master peer has connected. */ msg = towire_connectd_peer_connected(NULL, id, addr, incoming, - pps, their_features); + their_features); /*~ daemon_conn is a message queue for inter-daemon communication: we * queue up the `connect_peer_connected` message to tell lightningd @@ -475,10 +468,9 @@ struct io_plan *peer_connected(struct io_conn *conn, daemon_conn_send(daemon->master, take(msg)); daemon_conn_send_fd(daemon->master, subd_fd); daemon_conn_send_fd(daemon->master, pps->gossip_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; + /* Don't try to close this on freeing. */ + pps->gossip_fd = -1; /*~ Now we set up this connection to read/write from subd */ return multiplex_peer_setup(conn, peer); @@ -1892,10 +1884,9 @@ static void peer_final_msg(struct io_conn *conn, struct per_peer_state *pps; struct node_id id; u8 *finalmsg; - int fds[3]; + int fds[2]; - /* pps is allocated off f, so fds are closed when f freed. */ - if (!fromwire_connectd_peer_final_msg(tmpctx, msg, &id, &pps, &finalmsg)) + if (!fromwire_connectd_peer_final_msg(tmpctx, msg, &id, &finalmsg)) master_badmsg(WIRE_CONNECTD_PEER_FINAL_MSG, msg); /* Get the fds for this peer. */ @@ -1912,8 +1903,9 @@ static void peer_final_msg(struct io_conn *conn, /* Close fd to ourselves. */ close(fds[0]); - /* We put peer fd into conn, but pps needs to free the rest */ - per_peer_state_set_fds(pps, -1, fds[1], fds[2]); + /* We put peer fd into conn, but pps needs to free the gossip_fd */ + pps = new_per_peer_state(tmpctx); + per_peer_state_set_fds(pps, -1, fds[1]); /* This can happen if peer hung up on us. */ peer = peer_htable_get(&daemon->peers, &id); diff --git a/connectd/connectd_gossipd_wire.csv b/connectd/connectd_gossipd_wire.csv index c0d9152c9957..11133197442f 100644 --- a/connectd/connectd_gossipd_wire.csv +++ b/connectd/connectd_gossipd_wire.csv @@ -5,15 +5,12 @@ # Communication between gossipd and connectd. msgtype,gossipd_new_peer,4000 msgdata,gossipd_new_peer,id,node_id, -# Did we negotiate LOCAL_GOSSIP_QUERIES? +# Did we negotiate OPT_GOSSIP_QUERIES? msgdata,gossipd_new_peer,gossip_queries_feature,bool, -# Did they offer LOCAL_INITIAL_ROUTING_SYNC? -msgdata,gossipd_new_peer,initial_routing_sync,bool, -# if success: + gossip fd and gossip_store fd +# if success: + gossip fd msgtype,gossipd_new_peer_reply,4100 msgdata,gossipd_new_peer_reply,success,bool, -msgdata,gossipd_new_peer_reply,gs,?gossip_state, # Connectd asks gossipd for any known addresses for that node. msgtype,gossipd_get_addrs,4001 diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index bb5d0296f78e..960f74f9f90a 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -2,7 +2,6 @@ #include #include #include -#include #include msgtype,connectd_init,2000 @@ -63,7 +62,6 @@ msgtype,connectd_peer_connected,2002 msgdata,connectd_peer_connected,id,node_id, msgdata,connectd_peer_connected,addr,wireaddr_internal, msgdata,connectd_peer_connected,incoming,bool, -msgdata,connectd_peer_connected,pps,per_peer_state, msgdata,connectd_peer_connected,flen,u16, msgdata,connectd_peer_connected,features,u8,flen @@ -74,7 +72,6 @@ msgdata,connectd_peer_disconnected,id,node_id, # master -> connectd: give message to peer and disconnect. Three fds: peer, gossip and gossip_store msgtype,connectd_peer_final_msg,2003 msgdata,connectd_peer_final_msg,id,node_id, -msgdata,connectd_peer_final_msg,pps,per_peer_state, msgdata,connectd_peer_final_msg,len,u16, msgdata,connectd_peer_final_msg,msg,u8,len diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index f1c57b9e8c1f..28feabde83f2 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -831,37 +831,21 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, struct peer *peer = tal(conn, struct peer); struct node *node; int fds[2]; - int gossip_store_fd; - struct gossip_state *gs; if (!fromwire_gossipd_new_peer(msg, &peer->id, - &peer->gossip_queries_feature, - &peer->initial_routing_sync_feature)) { + &peer->gossip_queries_feature)) { status_broken("Bad new_peer msg from connectd: %s", tal_hex(tmpctx, msg)); return io_close(conn); } - gossip_store_fd = gossip_store_readonly_fd(daemon->rstate->gs);; - if (gossip_store_fd < 0) { - status_broken("Failed to get readonly store fd: %s", - strerror(errno)); - daemon_conn_send(daemon->connectd, - take(towire_gossipd_new_peer_reply(NULL, - false, - NULL))); - goto done; - } - /* This can happen: we handle it gracefully, returning a `failed` msg. */ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) { status_broken("Failed to create socketpair: %s", strerror(errno)); - close(gossip_store_fd); daemon_conn_send(daemon->connectd, take(towire_gossipd_new_peer_reply(NULL, - false, - NULL))); + false))); goto done; } @@ -898,43 +882,10 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, /* This sends the initial timestamp filter. */ seeker_setup_peer_gossip(daemon->seeker, peer); - /* BOLT #7: - * - * A node: - * - if the `gossip_queries` feature is negotiated: - * - MUST NOT relay any gossip messages it did not generate itself, - * unless explicitly requested. - */ - if (peer->gossip_queries_feature) { - gs = NULL; - } 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. - */ - gs = tal(tmpctx, struct gossip_state); - gs->timestamp_min = 0; - gs->timestamp_max = UINT32_MAX; - - /* If they don't want initial sync, start at end of store */ - if (!peer->initial_routing_sync_feature) - lseek(gossip_store_fd, 0, SEEK_END); - - gs->next_gossip = time_mono(); - } - /* Reply with success, and the new fd and gossip_state. */ daemon_conn_send(daemon->connectd, - take(towire_gossipd_new_peer_reply(NULL, true, gs))); + take(towire_gossipd_new_peer_reply(NULL, true))); daemon_conn_send_fd(daemon->connectd, fds[1]); - daemon_conn_send_fd(daemon->connectd, gossip_store_fd); done: return daemon_conn_read_next(conn, daemon->connectd); diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 1a4cfd59eb9d..9344bc9bfac5 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -110,7 +110,7 @@ bool fromwire_gossipd_new_blockheight(const void *p UNNEEDED, u32 *blockheight U bool fromwire_gossipd_new_lease_rates(const void *p UNNEEDED, struct lease_rates *rates UNNEEDED) { fprintf(stderr, "fromwire_gossipd_new_lease_rates called!\n"); abort(); } /* Generated stub for fromwire_gossipd_new_peer */ -bool fromwire_gossipd_new_peer(const void *p UNNEEDED, struct node_id *id UNNEEDED, bool *gossip_queries_feature UNNEEDED, bool *initial_routing_sync UNNEEDED) +bool fromwire_gossipd_new_peer(const void *p UNNEEDED, struct node_id *id UNNEEDED, bool *gossip_queries_feature UNNEEDED) { fprintf(stderr, "fromwire_gossipd_new_peer called!\n"); abort(); } /* Generated stub for fromwire_gossipd_outpoint_spent */ bool fromwire_gossipd_outpoint_spent(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED) @@ -136,9 +136,6 @@ const u8 *gossip_store_get(const tal_t *ctx UNNEEDED, /* Generated stub for gossip_store_load */ u32 gossip_store_load(struct routing_state *rstate UNNEEDED, struct gossip_store *gs UNNEEDED) { fprintf(stderr, "gossip_store_load called!\n"); abort(); } -/* Generated stub for gossip_store_readonly_fd */ -int gossip_store_readonly_fd(struct gossip_store *gs UNNEEDED) -{ fprintf(stderr, "gossip_store_readonly_fd called!\n"); abort(); } /* Generated stub for gossip_time_now */ struct timeabs gossip_time_now(const struct routing_state *rstate UNNEEDED) { fprintf(stderr, "gossip_time_now called!\n"); abort(); } @@ -339,7 +336,7 @@ u8 *towire_gossipd_got_onionmsg_to_us(const tal_t *ctx UNNEEDED, bool obs2 UNNEE u8 *towire_gossipd_init_reply(const tal_t *ctx UNNEEDED) { fprintf(stderr, "towire_gossipd_init_reply called!\n"); abort(); } /* Generated stub for towire_gossipd_new_peer_reply */ -u8 *towire_gossipd_new_peer_reply(const tal_t *ctx UNNEEDED, bool success UNNEEDED, const struct gossip_state *gs UNNEEDED) +u8 *towire_gossipd_new_peer_reply(const tal_t *ctx UNNEEDED, bool success UNNEEDED) { fprintf(stderr, "towire_gossipd_new_peer_reply called!\n"); abort(); } /* Generated stub for towire_warningfmt */ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index 77a09622341d..a7342a2e1a0e 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -614,6 +614,9 @@ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) { enum hsmd_wire t = fromwire_peektype(c->msg_in); + if (!is_lightningd(c)) + status_peer_debug(&c->id, "Got %s", hsmd_wire_name(t)); + /* Before we do anything else, is this client allowed to do * what he asks for? */ if (!hsmd_check_client_capabilities(c->hsmd_client, t)) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 3d9b8dabd05b..0544db54daab 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -350,11 +351,12 @@ static void peer_start_closingd_after_shutdown(struct channel *channel, { struct per_peer_state *pps; - if (!fromwire_channeld_shutdown_complete(tmpctx, msg, &pps)) { + if (!fromwire_channeld_shutdown_complete(msg)) { channel_internal_error(channel, "bad shutdown_complete: %s", tal_hex(msg, msg)); return; } + pps = new_per_peer_state(msg); per_peer_state_set_fds_arr(pps, fds); /* This sets channel->owner, closes down channeld. */ @@ -482,9 +484,9 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) peer_got_shutdown(sd->channel, msg); break; case WIRE_CHANNELD_SHUTDOWN_COMPLETE: - /* We expect 3 fds. */ + /* We expect 2 fds. */ if (!fds) - return 3; + return 2; peer_start_closingd_after_shutdown(sd->channel, msg, fds); break; case WIRE_CHANNELD_FAIL_FALLEN_BEHIND: @@ -579,7 +581,6 @@ void peer_start_channeld(struct channel *channel, channel_set_billboard, take(&pps->peer_fd), take(&pps->gossip_fd), - take(&pps->gossip_store_fd), take(&hsmfd), NULL)); if (!channel->owner) { @@ -662,7 +663,6 @@ void peer_start_channeld(struct channel *channel, feerate_max(ld, NULL), try_get_feerate(ld->topology, FEERATE_PENALTY), &channel->last_sig, - pps, &channel->channel_info.remote_fundingkey, &channel->channel_info.theirbase, &channel->channel_info.remote_per_commit, diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index 96f600c7889a..4a42e1fea76f 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -380,7 +380,6 @@ void peer_start_closingd(struct channel *channel, channel_set_billboard, take(&pps->peer_fd), take(&pps->gossip_fd), - take(&pps->gossip_store_fd), take(&hsmfd), NULL)); @@ -455,7 +454,6 @@ void peer_start_closingd(struct channel *channel, initmsg = towire_closingd_init(tmpctx, chainparams, - pps, &channel->cid, &channel->funding, channel->funding_sats, @@ -476,7 +474,6 @@ void peer_start_closingd(struct channel *channel, && channel->closing_fee_negotiation_step_unit == CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE) /* Always use quickclose with anchors */ || option_anchor_outputs, - IFDEV(ld->dev_fast_gossip, false), channel->shutdown_wrong_funding); /* We don't expect a response: it will give us feedback on diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index c7a28589c707..bd0c6bfb28c7 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -315,9 +315,9 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd break; case WIRE_CONNECTD_PEER_CONNECTED: - if (tal_count(fds) != 3) - return 3; - peer_connected(connectd->ld, msg, fds[0], fds[1], fds[2]); + if (tal_count(fds) != 2) + return 2; + peer_connected(connectd->ld, msg, fds[0], fds[1]); break; case WIRE_CONNECTD_CONNECT_FAILED: diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index a53c38be9214..b7f502a4b382 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1332,16 +1333,16 @@ static void handle_channel_closed(struct subd *dualopend, struct per_peer_state *pps; struct channel *channel = dualopend->channel; - if (!fromwire_dualopend_shutdown_complete(tmpctx, msg, &pps)) { + if (!fromwire_dualopend_shutdown_complete(msg)) { channel_internal_error(dualopend->channel, "Bad DUALOPEND_SHUTDOWN_COMPLETE: %s", tal_hex(msg, msg)); close(fds[0]); close(fds[1]); - close(fds[2]); return; } + pps = new_per_peer_state(tmpctx); per_peer_state_set_fds_arr(pps, fds); peer_start_closingd(channel, pps); @@ -1614,12 +1615,13 @@ static void handle_channel_locked(struct subd *dualopend, struct channel *channel = dualopend->channel; struct per_peer_state *pps; - if (!fromwire_dualopend_channel_locked(tmpctx, msg, &pps)) { + if (!fromwire_dualopend_channel_locked(msg)) { channel_internal_error(channel, "Bad WIRE_DUALOPEND_CHANNEL_LOCKED: %s", tal_hex(msg, msg)); return; } + pps = new_per_peer_state(tmpctx); per_peer_state_set_fds_arr(pps, fds); assert(channel->scid); @@ -2957,16 +2959,16 @@ static unsigned int dual_opend_msg(struct subd *dualopend, handle_dry_run_finished(dualopend, msg); return 0; case WIRE_DUALOPEND_CHANNEL_LOCKED: - if (tal_count(fds) != 3) - return 3; + if (tal_count(fds) != 2) + return 2; handle_channel_locked(dualopend, fds, msg); return 0; case WIRE_DUALOPEND_GOT_SHUTDOWN: handle_peer_wants_to_close(dualopend, msg); return 0; case WIRE_DUALOPEND_SHUTDOWN_COMPLETE: - if (tal_count(fds) != 3) - return 3; + if (tal_count(fds) != 2) + return 2; handle_channel_closed(dualopend, fds, msg); return 0; case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND: @@ -3201,7 +3203,6 @@ static void start_fresh_dualopend(struct peer *peer, channel_set_billboard, take(&pps->peer_fd), take(&pps->gossip_fd), - take(&pps->gossip_store_fd), take(&hsmfd), NULL); if (!channel->owner) { @@ -3230,7 +3231,7 @@ static void start_fresh_dualopend(struct peer *peer, &channel->our_config, max_to_self_delay, min_effective_htlc_capacity, - pps, &channel->local_basepoints, + &channel->local_basepoints, &channel->local_funding_pubkey, channel->minimum_depth); subd_send_msg(channel->owner, take(msg)); @@ -3269,7 +3270,6 @@ void peer_restart_dualopend(struct peer *peer, channel_set_billboard, take(&pps->peer_fd), take(&pps->gossip_fd), - take(&pps->gossip_store_fd), take(&hsmfd), NULL)); if (!channel->owner) { log_broken(channel->log, "Could not subdaemon channel: %s", @@ -3311,7 +3311,6 @@ void peer_restart_dualopend(struct peer *peer, &channel->cid, max_to_self_delay, min_effective_htlc_capacity, - pps, &channel->local_basepoints, &channel->local_funding_pubkey, &channel->channel_info.remote_fundingkey, diff --git a/lightningd/opening_common.c b/lightningd/opening_common.c index 0b02b41d5de7..bcf6ba210719 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -192,14 +193,12 @@ void handle_reestablish(struct lightningd *ld, type_to_string(tmpctx, struct channel_id, channel_id)); subd_send_msg(ld->connectd, take(towire_connectd_peer_final_msg(NULL, peer_id, - pps, err))); + err))); subd_send_fd(ld->connectd, pps->peer_fd); subd_send_fd(ld->connectd, pps->gossip_fd); - subd_send_fd(ld->connectd, pps->gossip_store_fd); /* Don't close those fds! */ pps->peer_fd = pps->gossip_fd - = pps->gossip_store_fd = -1; } } diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 9e78a6963766..4cb58766e95f 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -348,7 +349,6 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, &remote_commit, &pbase, &remote_commit_sig, - &pps, &channel_info.theirbase.revocation, &channel_info.theirbase.payment, &channel_info.theirbase.htlc, @@ -370,6 +370,8 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, goto cleanup; } remote_commit->chainparams = chainparams; + + pps = new_per_peer_state(resp); per_peer_state_set_fds_arr(pps, fds); log_debug(ld->log, @@ -448,7 +450,6 @@ static void opening_fundee_finished(struct subd *openingd, &remote_commit, &pbase, &remote_commit_sig, - &pps, &channel_info.theirbase.revocation, &channel_info.theirbase.payment, &channel_info.theirbase.htlc, @@ -473,6 +474,7 @@ static void opening_fundee_finished(struct subd *openingd, } remote_commit->chainparams = chainparams; + pps = new_per_peer_state(tmpctx); per_peer_state_set_fds_arr(pps, fds); /* openingd should never accept them funding channel in this case. */ @@ -530,7 +532,6 @@ static void opening_fundee_finished(struct subd *openingd, failed: close(fds[0]); close(fds[1]); - close(fds[3]); tal_free(uc); } @@ -803,7 +804,7 @@ static void opening_got_offer(struct subd *openingd, } static void opening_got_reestablish(struct subd *openingd, const u8 *msg, - const int fds[3], + const int fds[2], struct uncommitted_channel *uc) { struct lightningd *ld = openingd->ld; @@ -813,12 +814,13 @@ static void opening_got_reestablish(struct subd *openingd, const u8 *msg, struct per_peer_state *pps; if (!fromwire_openingd_got_reestablish(tmpctx, msg, &channel_id, - &reestablish, &pps)) { + &reestablish)) { log_broken(openingd->log, "Malformed opening_got_reestablish %s", tal_hex(tmpctx, msg)); tal_free(openingd); return; } + pps = new_per_peer_state(tmpctx); per_peer_state_set_fds_arr(pps, fds); /* This could free peer */ @@ -841,8 +843,8 @@ static unsigned int openingd_msg(struct subd *openingd, tal_free(openingd); return 0; } - if (tal_count(fds) != 3) - return 3; + if (tal_count(fds) != 2) + return 2; opening_funder_finished(openingd, msg, fds, uc->fc); return 0; case WIRE_OPENINGD_FUNDER_START_REPLY: @@ -865,8 +867,8 @@ static unsigned int openingd_msg(struct subd *openingd, return 0; case WIRE_OPENINGD_FUNDEE: - if (tal_count(fds) != 3) - return 3; + if (tal_count(fds) != 2) + return 2; opening_fundee_finished(openingd, msg, fds, uc); return 0; @@ -875,8 +877,8 @@ static unsigned int openingd_msg(struct subd *openingd, return 0; case WIRE_OPENINGD_GOT_REESTABLISH: - if (tal_count(fds) != 3) - return 3; + if (tal_count(fds) != 2) + return 2; opening_got_reestablish(openingd, msg, fds, uc); return 0; @@ -932,7 +934,6 @@ void peer_start_openingd(struct peer *peer, struct per_peer_state *pps) opend_channel_set_billboard, take(&pps->peer_fd), take(&pps->gossip_fd), - take(&pps->gossip_store_fd), take(&hsmfd), NULL); if (!uc->open_daemon) { uncommitted_channel_disconnect(uc, LOG_BROKEN, @@ -962,13 +963,12 @@ void peer_start_openingd(struct peer *peer, struct per_peer_state *pps) &uc->our_config, max_to_self_delay, min_effective_htlc_capacity, - pps, &uc->local_basepoints, + &uc->local_basepoints, &uc->local_funding_pubkey, uc->minimum_depth, feerate_min(peer->ld, NULL), feerate_max(peer->ld, NULL), - IFDEV(peer->ld->dev_force_tmp_channel_id, NULL), - IFDEV(peer->ld->dev_fast_gossip, false)); + IFDEV(peer->ld->dev_force_tmp_channel_id, NULL)); subd_send_msg(uc->open_daemon, take(msg)); } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 415b4d69f467..d1f4dcc3199b 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1052,14 +1052,12 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa /* Get connectd to send error and close. */ subd_send_msg(ld->connectd, take(towire_connectd_peer_final_msg(NULL, &peer->id, - payload->pps, error))); + error))); subd_send_fd(ld->connectd, payload->pps->peer_fd); subd_send_fd(ld->connectd, payload->pps->gossip_fd); - subd_send_fd(ld->connectd, payload->pps->gossip_store_fd); /* Don't close those fds! */ payload->pps->peer_fd = payload->pps->gossip_fd - = payload->pps->gossip_store_fd = -1; } @@ -1117,7 +1115,7 @@ REGISTER_PLUGIN_HOOK(peer_connected, /* Connectd tells us a peer has connected: it never hands us duplicates, since * it holds them until we say peer_died. */ void peer_connected(struct lightningd *ld, const u8 *msg, - int peer_fd, int gossip_fd, int gossip_store_fd) + int peer_fd, int gossip_fd) { struct node_id id; u8 *their_features; @@ -1130,13 +1128,12 @@ void peer_connected(struct lightningd *ld, const u8 *msg, if (!fromwire_connectd_peer_connected(hook_payload, msg, &id, &hook_payload->addr, &hook_payload->incoming, - &hook_payload->pps, &their_features)) fatal("Connectd gave bad CONNECT_PEER_CONNECTED message %s", tal_hex(msg, msg)); - per_peer_state_set_fds(hook_payload->pps, - peer_fd, gossip_fd, gossip_store_fd); + hook_payload->pps = new_per_peer_state(hook_payload); + per_peer_state_set_fds(hook_payload->pps, peer_fd, gossip_fd); /* If we're already dealing with this peer, hand off to correct * subdaemon. Otherwise, we'll hand to openingd to wait there. */ diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 97d96753bad6..3ce98cd368bc 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -65,7 +65,7 @@ struct peer *peer_from_json(struct lightningd *ld, const jsmntok_t *peeridtok); void peer_connected(struct lightningd *ld, const u8 *msg, - int peer_fd, int gossip_fd, int gossip_store_fd); + int peer_fd, int gossip_fd); /* Could be configurable. */ #define OUR_CHANNEL_FLAGS CHANNEL_FLAGS_ANNOUNCE_CHANNEL diff --git a/lightningd/subd.c b/lightningd/subd.c index 0bb9afd8a9c7..3bcb84611402 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -404,7 +404,7 @@ static bool log_status_fail(struct subd *sd, const u8 *msg) return true; } -static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[3]) +static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[2]) { void *channel = sd->channel; struct channel_id channel_id; @@ -415,9 +415,10 @@ static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[3]) if (!fromwire_status_peer_error(msg, msg, &channel_id, &desc, &warning, - &pps, &err_for_them)) + &err_for_them)) return false; + pps = new_per_peer_state(msg); per_peer_state_set_fds_arr(pps, fds); /* Don't free sd; we may be about to free channel. */ @@ -523,11 +524,11 @@ static struct io_plan *sd_msg_read(struct io_conn *conn, struct subd *sd) if (sd->channel) { switch ((enum peer_status_wire)type) { case WIRE_STATUS_PEER_ERROR: - /* We expect 3 fds after this */ + /* We expect 2 fds after this */ if (!sd->fds_in) { /* Don't free msg_in: we go around again. */ tal_steal(sd, sd->msg_in); - plan = sd_collect_fds(conn, sd, 3); + plan = sd_collect_fds(conn, sd, 2); goto out; } if (!handle_peer_error(sd, sd->msg_in, sd->fds_in)) diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index 55d198f68038..83c5fd00d3d6 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -89,7 +89,7 @@ bool fromwire_status_fail(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, enu bool fromwire_status_peer_billboard(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *perm UNNEEDED, wirestring **happenings UNNEEDED) { fprintf(stderr, "fromwire_status_peer_billboard called!\n"); abort(); } /* Generated stub for fromwire_status_peer_error */ -bool fromwire_status_peer_error(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct channel_id *channel UNNEEDED, wirestring **desc UNNEEDED, bool *warning UNNEEDED, struct per_peer_state **pps UNNEEDED, u8 **error_for_them UNNEEDED) +bool fromwire_status_peer_error(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct channel_id *channel UNNEEDED, wirestring **desc UNNEEDED, bool *warning UNNEEDED, u8 **error_for_them UNNEEDED) { fprintf(stderr, "fromwire_status_peer_error called!\n"); abort(); } /* Generated stub for fromwire_status_version */ bool fromwire_status_version(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, wirestring **version UNNEEDED) @@ -170,6 +170,9 @@ struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, /* Generated stub for new_log_book */ struct log_book *new_log_book(struct lightningd *ld UNNEEDED, size_t max_mem UNNEEDED) { 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) +{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for new_topology */ struct chain_topology *new_topology(struct lightningd *ld UNNEEDED, struct log *log UNNEEDED) { fprintf(stderr, "new_topology called!\n"); abort(); } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 0b241ac71fda..ee40d1794457 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -210,7 +210,7 @@ bool fromwire_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, bool fromwire_channeld_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) { fprintf(stderr, "fromwire_channeld_dev_memleak_reply called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_connected */ -bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, bool *incoming UNNEEDED, struct per_peer_state **pps UNNEEDED, u8 **features UNNEEDED) +bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_connected called!\n"); abort(); } /* Generated stub for fromwire_hsmd_sign_bolt12_reply */ bool fromwire_hsmd_sign_bolt12_reply(const void *p UNNEEDED, struct bip340sig *sig UNNEEDED) @@ -444,6 +444,9 @@ struct height_states *new_height_states(const tal_t *ctx UNNEEDED, enum side opener UNNEEDED, const u32 *blockheight UNNEEDED) { fprintf(stderr, "new_height_states called!\n"); abort(); } +/* Generated stub for new_per_peer_state */ +struct per_peer_state *new_per_peer_state(const tal_t *ctx UNNEEDED) +{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for new_reltimer_ */ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, const tal_t *ctx UNNEEDED, @@ -599,7 +602,7 @@ struct channel *peer_unsaved_channel(struct peer *peer UNNEEDED) { fprintf(stderr, "peer_unsaved_channel called!\n"); abort(); } /* Generated stub for per_peer_state_set_fds */ void per_peer_state_set_fds(struct per_peer_state *pps UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED, int gossip_store_fd UNNEEDED) + int peer_fd UNNEEDED, int gossip_fd UNNEEDED) { fprintf(stderr, "per_peer_state_set_fds called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ bool plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, @@ -646,7 +649,7 @@ u8 *towire_channeld_specific_feerates(const tal_t *ctx UNNEEDED, u32 feerate_bas u8 *towire_connectd_connect_to_peer(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u32 seconds_waited UNNEEDED, const struct wireaddr_internal *addrhint UNNEEDED) { fprintf(stderr, "towire_connectd_connect_to_peer called!\n"); abort(); } /* Generated stub for towire_connectd_peer_final_msg */ -u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const struct per_peer_state *pps UNNEEDED, const u8 *msg UNNEEDED) +u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "towire_connectd_peer_final_msg called!\n"); abort(); } /* Generated stub for towire_errorfmt */ u8 *towire_errorfmt(const tal_t *ctx UNNEEDED, diff --git a/lightningd/test/run-shuffle_fds.c b/lightningd/test/run-shuffle_fds.c index c2a00d667439..3d7fb6e524d0 100644 --- a/lightningd/test/run-shuffle_fds.c +++ b/lightningd/test/run-shuffle_fds.c @@ -70,7 +70,7 @@ bool fromwire_status_fail(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, enu bool fromwire_status_peer_billboard(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *perm UNNEEDED, wirestring **happenings UNNEEDED) { fprintf(stderr, "fromwire_status_peer_billboard called!\n"); abort(); } /* Generated stub for fromwire_status_peer_error */ -bool fromwire_status_peer_error(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct channel_id *channel UNNEEDED, wirestring **desc UNNEEDED, bool *warning UNNEEDED, struct per_peer_state **pps UNNEEDED, u8 **error_for_them UNNEEDED) +bool fromwire_status_peer_error(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct channel_id *channel UNNEEDED, wirestring **desc UNNEEDED, bool *warning UNNEEDED, u8 **error_for_them UNNEEDED) { fprintf(stderr, "fromwire_status_peer_error called!\n"); abort(); } /* Generated stub for fromwire_status_version */ bool fromwire_status_version(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, wirestring **version UNNEEDED) @@ -108,6 +108,9 @@ struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, const struct node_id *default_node_id UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "new_log called!\n"); abort(); } +/* Generated stub for new_per_peer_state */ +struct per_peer_state *new_per_peer_state(const tal_t *ctx UNNEEDED) +{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for per_peer_state_set_fds_arr */ void per_peer_state_set_fds_arr(struct per_peer_state *pps UNNEEDED, const int *fds UNNEEDED) { fprintf(stderr, "per_peer_state_set_fds_arr called!\n"); abort(); } diff --git a/openingd/dualopend.c b/openingd/dualopend.c index d6c4fa4fb952..a67b6e5f2779 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -44,9 +45,9 @@ #include #include -/* stdin == lightningd, 3 == peer, 4 == gossipd, 5 = gossip_store, 6 = hsmd */ +/* stdin == lightningd, 3 == peer, 4 == gossipd, 5 = hsmd */ #define REQ_FD STDIN_FILENO -#define HSM_FD 6 +#define HSM_FD 5 /* tx_add_input, tx_add_output, tx_rm_input, tx_rm_output */ #define NUM_TX_MSGS (TX_RM_OUTPUT + 1) @@ -293,7 +294,7 @@ static u8 *psbt_changeset_get_next(const tal_t *ctx, static void shutdown(struct state *state) { - u8 *msg = towire_dualopend_shutdown_complete(state, state->pps); + u8 *msg = towire_dualopend_shutdown_complete(state); wire_sync_write(REQ_FD, msg); per_peer_state_fdpass_send(REQ_FD, state->pps); @@ -1156,7 +1157,7 @@ static u8 *handle_funding_locked(struct state *state, u8 *msg) billboard_update(state); if (state->funding_locked[LOCAL]) - return towire_dualopend_channel_locked(state, state->pps); + return towire_dualopend_channel_locked(state); return NULL; } @@ -1191,7 +1192,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) /* Some messages go straight to gossipd. */ if (is_msg_for_gossipd(msg)) { - gossip_rcvd_filter_add(state->pps->grf, msg); wire_sync_write(state->pps->gossip_fd, take(msg)); continue; } @@ -1205,10 +1205,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) if (is_unknown_msg_discardable(msg)) continue; - /* Might be a timestamp filter request: handle. */ - if (handle_timestamp_filter(state->pps, msg)) - continue; - /* A helper which decodes an error. */ if (is_peer_error(tmpctx, msg, &state->channel_id, &err, &warning)) { @@ -3418,8 +3414,7 @@ static u8 *handle_funding_depth(struct state *state, u8 *msg) send_funding_locked(state); if (state->funding_locked[REMOTE]) - return towire_dualopend_channel_locked(state, - state->pps); + return towire_dualopend_channel_locked(state); return NULL; } @@ -3437,14 +3432,6 @@ static void handle_gossip_in(struct state *state) handle_gossip_msg(state->pps, take(msg)); } -static void try_read_gossip_store(struct state *state) -{ - u8 *msg = gossip_store_next(tmpctx, state->pps); - - if (msg) - peer_write(state->pps, take(msg)); -} - /* Try to handle a custommsg Returns true if it was a custom message and has * been handled, false if the message was not handled. */ @@ -3834,7 +3821,6 @@ int main(int argc, char *argv[]) &state->tx_state->localconf, &state->max_to_self_delay, &state->min_effective_htlc_capacity, - &state->pps, &state->our_points, &state->our_funding_pubkey, &state->minimum_depth)) { @@ -3866,7 +3852,6 @@ int main(int argc, char *argv[]) &state->channel_id, &state->max_to_self_delay, &state->min_effective_htlc_capacity, - &state->pps, &state->our_points, &state->our_funding_pubkey, &state->their_funding_pubkey, @@ -3934,8 +3919,9 @@ int main(int argc, char *argv[]) - /* 3 == peer, 4 == gossipd, 5 = gossip_store, 6 = hsmd */ - per_peer_state_set_fds(state->pps, 3, 4, 5); + /* 3 == peer, 4 == gossipd, 5 = hsmd */ + state->pps = new_per_peer_state(state); + per_peer_state_set_fds(state->pps, 3, 4); /*~ We need an initial per-commitment point whether we're funding or * they are, and lightningd has reserved a unique dbid for us already, @@ -3974,19 +3960,13 @@ int main(int argc, char *argv[]) * opening_funder_reply or opening_fundee. */ msg = NULL; while (!msg) { - int t; - struct timerel trel; - if (time_to_next_gossip(state->pps, &trel)) - t = time_to_msec(trel); - else - t = -1; /*~ If we get a signal which aborts the poll() call, valgrind * complains about revents being uninitialized. I'm not sure * that's correct, but it's easy to be sure. */ pollfd[0].revents = pollfd[1].revents = pollfd[2].revents = 0; - poll(pollfd, ARRAY_SIZE(pollfd), t); + poll(pollfd, ARRAY_SIZE(pollfd), -1); /* Subtle: handle_master_in can do its own poll loop, so * don't try to service more than one fd per loop. */ /* First priority: messages from lightningd. */ @@ -3998,13 +3978,10 @@ int main(int argc, char *argv[]) /* Last priority: chit-chat from gossipd. */ else if (pollfd[1].revents & POLLIN) handle_gossip_in(state); - else - try_read_gossip_store(state); /* If we've shutdown, we're done */ if (shutdown_complete(state)) - msg = towire_dualopend_shutdown_complete(state, - state->pps); + msg = towire_dualopend_shutdown_complete(state); /* Since we're the top-level event loop, we clean up */ clean_tmpctx(); } diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index 3b3620c7472f..cd5600e3a2e8 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -23,7 +22,6 @@ msgdata,dualopend_init,our_config,channel_config, # Minimum/maximum configuration values we'll accept msgdata,dualopend_init,max_to_self_delay,u32, msgdata,dualopend_init,min_effective_htlc_capacity_msat,amount_msat, -msgdata,dualopend_init,pps,per_peer_state, msgdata,dualopend_init,our_basepoints,basepoints, msgdata,dualopend_init,our_funding_pubkey,pubkey, # Constraints in case the other end tries to open a channel. @@ -40,7 +38,6 @@ msgdata,dualopend_reinit,their_config,channel_config, msgdata,dualopend_reinit,channel_id,channel_id, msgdata,dualopend_reinit,max_to_self_delay,u32, msgdata,dualopend_reinit,min_effective_htlc_capacity_msat,amount_msat, -msgdata,dualopend_reinit,pps,per_peer_state, msgdata,dualopend_reinit,our_basepoints,basepoints, msgdata,dualopend_reinit,our_funding_pubkey,pubkey, msgdata,dualopend_reinit,their_funding_pubkey,pubkey, @@ -201,7 +198,6 @@ msgdata,dualopend_peer_locked,remote_per_commit,pubkey, # dualopend->master this channel has been locked msgtype,dualopend_channel_locked,7019 -msgdata,dualopend_channel_locked,pps,per_peer_state, # master->dualopend funding reached depth; tell peer msgtype,dualopend_depth_reached,7020 @@ -222,7 +218,6 @@ msgtype,dualopend_fail_fallen_behind,1028 # Shutdown is complete, ready for closing negotiation. + peer_fd & gossip_fd. msgtype,dualopend_shutdown_complete,7025 -msgdata,dualopend_shutdown_complete,per_peer_state,per_peer_state, # dualopend -> master: this was a dry run, here's some info about this open msgtype,dualopend_dry_run,7026 diff --git a/openingd/openingd.c b/openingd/openingd.c index 72471da3f6c5..e94c31f74437 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -35,9 +36,9 @@ #include #include -/* stdin == lightningd, 3 == peer, 4 == gossipd, 5 = gossip_store, 6 = hsmd */ +/* stdin == lightningd, 3 == peer, 4 == gossipd, 5 = hsmd */ #define REQ_FD STDIN_FILENO -#define HSM_FD 6 +#define HSM_FD 5 #if DEVELOPER /* If --dev-force-tmp-channel-id is set, it ends up here */ @@ -205,7 +206,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, /* Some messages go straight to gossipd. */ if (is_msg_for_gossipd(msg)) { - gossip_rcvd_filter_add(state->pps->grf, msg); wire_sync_write(state->pps->gossip_fd, take(msg)); continue; } @@ -219,10 +219,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, if (is_unknown_msg_discardable(msg)) continue; - /* Might be a timestamp filter request: handle. */ - if (handle_timestamp_filter(state->pps, msg)) - continue; - /* A helper which decodes an error. */ if (is_peer_error(tmpctx, msg, &state->channel_id, &err, &warning)) { @@ -774,7 +770,6 @@ static u8 *funder_channel_complete(struct state *state) tx, pbase, &sig, - state->pps, &state->their_points.revocation, &state->their_points.payment, &state->their_points.htlc, @@ -1234,7 +1229,6 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) local_commit, pbase, &theirsig, - state->pps, &theirs.revocation, &theirs.payment, &theirs.htlc, @@ -1286,8 +1280,7 @@ static u8 *handle_peer_in(struct state *state) /* Reestablish on some now-closed channel? Be nice. */ if (extracted && fromwire_peektype(msg) == WIRE_CHANNEL_REESTABLISH) { return towire_openingd_got_reestablish(NULL, - &channel_id, msg, - state->pps); + &channel_id, msg); } peer_write(state->pps, take(towire_warningfmt(NULL, @@ -1427,14 +1420,6 @@ static u8 *handle_master_in(struct state *state) "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) - peer_write(state->pps, take(msg)); -} - int main(int argc, char *argv[]) { setup_locale(); @@ -1460,21 +1445,20 @@ int main(int argc, char *argv[]) &state->localconf, &state->max_to_self_delay, &state->min_effective_htlc_capacity, - &state->pps, &state->our_points, &state->our_funding_pubkey, &state->minimum_depth, &state->min_feerate, &state->max_feerate, - &force_tmp_channel_id, - &dev_fast_gossip)) + &force_tmp_channel_id)) master_badmsg(WIRE_OPENINGD_INIT, msg); #if DEVELOPER dev_force_tmp_channel_id = force_tmp_channel_id; #endif - /* 3 == peer, 4 == gossipd, 5 = gossip_store, 6 = hsmd */ - per_peer_state_set_fds(state->pps, 3, 4, 5); + /* 3 == peer, 4 == gossipd, 5 = hsmd */ + state->pps = new_per_peer_state(state); + per_peer_state_set_fds(state->pps, 3, 4); /*~ Initially we're not associated with a channel, but * handle_peer_gossip_or_error compares this. */ @@ -1520,19 +1504,12 @@ int main(int argc, char *argv[]) * opening_funder_reply or opening_fundee. */ msg = NULL; while (!msg) { - int t; - struct timerel trel; - if (time_to_next_gossip(state->pps, &trel)) - t = time_to_msec(trel); - else - t = -1; - /*~ If we get a signal which aborts the poll() call, valgrind * complains about revents being uninitialized. I'm not sure * that's correct, but it's easy to be sure. */ pollfd[0].revents = pollfd[1].revents = pollfd[2].revents = 0; - poll(pollfd, ARRAY_SIZE(pollfd), t); + poll(pollfd, ARRAY_SIZE(pollfd), -1); /* Subtle: handle_master_in can do its own poll loop, so * don't try to service more than one fd per loop. */ /* First priority: messages from lightningd. */ @@ -1544,8 +1521,6 @@ int main(int argc, char *argv[]) /* Last priority: chit-chat from gossipd. */ else if (pollfd[1].revents & POLLIN) handle_gossip_in(state); - else - try_read_gossip_store(state); /* Since we're the top-level event loop, we clean up */ clean_tmpctx(); diff --git a/openingd/openingd_wire.csv b/openingd/openingd_wire.csv index 7a688c7f692f..b8f0fc5b9d6f 100644 --- a/openingd/openingd_wire.csv +++ b/openingd/openingd_wire.csv @@ -5,7 +5,6 @@ #include #include #include -#include msgtype,openingd_init,6000 # Which network are we configured for? @@ -18,7 +17,6 @@ msgdata,openingd_init,our_config,channel_config, # Minimum/maximum configuration values we'll accept msgdata,openingd_init,max_to_self_delay,u32, msgdata,openingd_init,min_effective_htlc_capacity_msat,amount_msat, -msgdata,openingd_init,pps,per_peer_state, msgdata,openingd_init,our_basepoints,basepoints, msgdata,openingd_init,our_funding_pubkey,pubkey, # Constraints in case the other end tries to open a channel. @@ -26,14 +24,12 @@ msgdata,openingd_init,minimum_depth,u32, msgdata,openingd_init,min_feerate,u32, msgdata,openingd_init,max_feerate,u32, msgdata,openingd_init,dev_temporary_channel_id,?byte,32 -msgdata,openingd_init,dev_fast_gossip,bool, # Openingd->master: they tried to reestablish a channel. msgtype,openingd_got_reestablish,6001 msgdata,openingd_got_reestablish,channel_id,channel_id, msgdata,openingd_got_reestablish,len,u16, msgdata,openingd_got_reestablish,msg,u8,len -msgdata,openingd_got_reestablish,pps,per_peer_state, # Openingd->master: they offered channel, should we continue? msgtype,openingd_got_offer,6005 @@ -65,7 +61,6 @@ msgdata,openingd_funder_reply,their_config,channel_config, msgdata,openingd_funder_reply,first_commit,bitcoin_tx, msgdata,openingd_funder_reply,pbase,?penalty_base, msgdata,openingd_funder_reply,first_commit_sig,bitcoin_signature, -msgdata,openingd_funder_reply,pps,per_peer_state, msgdata,openingd_funder_reply,revocation_basepoint,pubkey, msgdata,openingd_funder_reply,payment_basepoint,pubkey, msgdata,openingd_funder_reply,htlc_basepoint,pubkey, @@ -119,7 +114,6 @@ msgdata,openingd_fundee,their_config,channel_config, msgdata,openingd_fundee,first_commit,bitcoin_tx, msgdata,openingd_fundee,pbase,?penalty_base, msgdata,openingd_fundee,first_commit_sig,bitcoin_signature, -msgdata,openingd_fundee,pps,per_peer_state, msgdata,openingd_fundee,revocation_basepoint,pubkey, msgdata,openingd_fundee,payment_basepoint,pubkey, msgdata,openingd_fundee,htlc_basepoint,pubkey, diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 49d72a31907e..018989e41493 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1330,8 +1330,7 @@ def test_gossipwith(node_factory): num_msgs += 1 # one channel announcement, two channel_updates, two node announcements. - # FIXME: Currently gets double gossip! - assert num_msgs == 5 * 2 + assert num_msgs == 5 def test_gossip_notices_close(node_factory, bitcoind): diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index e961f515d1f2..a239b1f7e9ce 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -130,7 +130,7 @@ bool fromwire_channeld_offer_htlc_reply(const tal_t *ctx UNNEEDED, const void *p bool fromwire_channeld_sending_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct penalty_base **pbase UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_signature *commit_sig UNNEEDED, struct bitcoin_signature **htlc_sigs UNNEEDED) { fprintf(stderr, "fromwire_channeld_sending_commitsig called!\n"); abort(); } /* Generated stub for fromwire_connectd_peer_connected */ -bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, bool *incoming UNNEEDED, struct per_peer_state **pps UNNEEDED, u8 **features UNNEEDED) +bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_connected called!\n"); abort(); } /* Generated stub for fromwire_custommsg_in */ bool fromwire_custommsg_in(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **msg UNNEEDED) @@ -448,6 +448,9 @@ struct chain_coin_mvt *new_coin_deposit_sat(const tal_t *ctx UNNEEDED, u32 blockheight UNNEEDED, struct amount_sat amount UNNEEDED) { fprintf(stderr, "new_coin_deposit_sat called!\n"); abort(); } +/* Generated stub for new_per_peer_state */ +struct per_peer_state *new_per_peer_state(const tal_t *ctx UNNEEDED) +{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for notify_chain_mvt */ void notify_chain_mvt(struct lightningd *ld UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED) { fprintf(stderr, "notify_chain_mvt called!\n"); abort(); } @@ -629,7 +632,7 @@ const char *peer_wire_name(int e UNNEEDED) { fprintf(stderr, "peer_wire_name called!\n"); abort(); } /* Generated stub for per_peer_state_set_fds */ void per_peer_state_set_fds(struct per_peer_state *pps UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED, int gossip_store_fd UNNEEDED) + int peer_fd UNNEEDED, int gossip_fd UNNEEDED) { fprintf(stderr, "per_peer_state_set_fds called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ bool plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, @@ -720,7 +723,7 @@ u8 *towire_connectd_connect_to_peer(const tal_t *ctx UNNEEDED, const struct node u8 *towire_connectd_peer_disconnected(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "towire_connectd_peer_disconnected called!\n"); abort(); } /* Generated stub for towire_connectd_peer_final_msg */ -u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const struct per_peer_state *pps UNNEEDED, const u8 *msg UNNEEDED) +u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "towire_connectd_peer_final_msg called!\n"); abort(); } /* Generated stub for towire_custommsg_out */ u8 *towire_custommsg_out(const tal_t *ctx UNNEEDED, const u8 *msg UNNEEDED) From be86baeca38c4e47be7f04f9a8ac25999bfe2086 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:09 +1030 Subject: [PATCH 25/51] lightningd: remove per_peer_state struct. Just hand around the two fds. We have to take a little care to close them manually now, though. Signed-off-by: Rusty Russell --- lightningd/channel_control.c | 13 ++---- lightningd/channel_control.h | 3 +- lightningd/closing_control.c | 10 ++--- lightningd/closing_control.h | 4 +- lightningd/dual_open_control.c | 30 ++++++-------- lightningd/dual_open_control.h | 6 +-- lightningd/onchain_control.c | 2 +- lightningd/opening_common.c | 19 ++++----- lightningd/opening_common.h | 8 +--- lightningd/opening_control.c | 26 +++++------- lightningd/opening_control.h | 3 +- lightningd/peer_control.c | 44 ++++++++++++--------- lightningd/peer_control.h | 3 +- lightningd/subd.c | 18 ++++----- lightningd/subd.h | 6 +-- lightningd/test/run-find_my_abspath.c | 6 --- lightningd/test/run-invoice-select-inchan.c | 15 ++----- lightningd/test/run-shuffle_fds.c | 6 --- wallet/test/run-wallet.c | 15 ++----- 19 files changed, 92 insertions(+), 145 deletions(-) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 0544db54daab..04fb24d25761 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -349,18 +348,14 @@ static void peer_start_closingd_after_shutdown(struct channel *channel, const u8 *msg, const int *fds) { - struct per_peer_state *pps; - if (!fromwire_channeld_shutdown_complete(msg)) { channel_internal_error(channel, "bad shutdown_complete: %s", tal_hex(msg, msg)); return; } - pps = new_per_peer_state(msg); - per_peer_state_set_fds_arr(pps, fds); /* This sets channel->owner, closes down channeld. */ - peer_start_closingd(channel, pps); + peer_start_closingd(channel, fds[0], fds[1]); /* We might have reconnected, so already be here. */ if (!channel_closed(channel) @@ -544,7 +539,7 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) } void peer_start_channeld(struct channel *channel, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const u8 *fwd_msg, bool reconnected, const u8 *reestablish_only) @@ -579,8 +574,8 @@ void peer_start_channeld(struct channel *channel, channel_msg, channel_errmsg, channel_set_billboard, - take(&pps->peer_fd), - take(&pps->gossip_fd), + take(&peer_fd), + take(&gossip_fd), take(&hsmfd), NULL)); if (!channel->owner) { diff --git a/lightningd/channel_control.h b/lightningd/channel_control.h index ce91cf68bcfc..ac5a1b88db03 100644 --- a/lightningd/channel_control.h +++ b/lightningd/channel_control.h @@ -7,11 +7,10 @@ struct channel; struct crypto_state; struct lightningd; -struct per_peer_state; struct peer; void peer_start_channeld(struct channel *channel, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const u8 *fwd_msg, bool reconnected, const u8 *reestablish_only); diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index 4a42e1fea76f..0b297cbc5ea8 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -348,8 +347,7 @@ static unsigned closing_msg(struct subd *sd, const u8 *msg, const int *fds UNUSE return 0; } -void peer_start_closingd(struct channel *channel, - struct per_peer_state *pps) +void peer_start_closingd(struct channel *channel, int peer_fd, int gossip_fd) { u8 *initmsg; u32 min_feerate, feerate, *max_feerate; @@ -361,6 +359,8 @@ void peer_start_closingd(struct channel *channel, bool option_anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS); if (!channel->shutdown_scriptpubkey[REMOTE]) { + close(peer_fd); + close(gossip_fd); channel_internal_error(channel, "Can't start closing: no remote info"); return; @@ -378,8 +378,8 @@ void peer_start_closingd(struct channel *channel, closingd_wire_name, closing_msg, channel_errmsg, channel_set_billboard, - take(&pps->peer_fd), - take(&pps->gossip_fd), + take(&peer_fd), + take(&gossip_fd), take(&hsmfd), NULL)); diff --git a/lightningd/closing_control.h b/lightningd/closing_control.h index 8991b44439bc..e36450d3aab4 100644 --- a/lightningd/closing_control.h +++ b/lightningd/closing_control.h @@ -6,12 +6,10 @@ struct channel; struct lightningd; -struct per_peer_state; void resolve_close_command(struct lightningd *ld, struct channel *channel, bool cooperative); -void peer_start_closingd(struct channel *channel, - struct per_peer_state *pps); +void peer_start_closingd(struct channel *channel, int peer_fd, int gossip_fd); #endif /* LIGHTNING_LIGHTNINGD_CLOSING_CONTROL_H */ diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index b7f502a4b382..62a1fefb5c3c 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -1330,7 +1329,6 @@ static void handle_channel_closed(struct subd *dualopend, const int *fds, const u8 *msg) { - struct per_peer_state *pps; struct channel *channel = dualopend->channel; if (!fromwire_dualopend_shutdown_complete(msg)) { @@ -1342,10 +1340,7 @@ static void handle_channel_closed(struct subd *dualopend, return; } - pps = new_per_peer_state(tmpctx); - per_peer_state_set_fds_arr(pps, fds); - - peer_start_closingd(channel, pps); + peer_start_closingd(channel, fds[0], fds[1]); channel_set_state(channel, CHANNELD_SHUTTING_DOWN, CLOSINGD_SIGEXCHANGE, @@ -1613,7 +1608,6 @@ static void handle_channel_locked(struct subd *dualopend, const u8 *msg) { struct channel *channel = dualopend->channel; - struct per_peer_state *pps; if (!fromwire_dualopend_channel_locked(msg)) { channel_internal_error(channel, @@ -1621,8 +1615,6 @@ static void handle_channel_locked(struct subd *dualopend, tal_hex(msg, msg)); return; } - pps = new_per_peer_state(tmpctx); - per_peer_state_set_fds_arr(pps, fds); assert(channel->scid); assert(channel->remote_funding_locked); @@ -1643,7 +1635,7 @@ static void handle_channel_locked(struct subd *dualopend, wallet_channel_clear_inflights(dualopend->ld->wallet, channel); /* FIXME: LND sigs/update_fee msgs? */ - peer_start_channeld(channel, pps, NULL, false, NULL); + peer_start_channeld(channel, fds[0], fds[1], NULL, false, NULL); return; } @@ -3179,7 +3171,7 @@ AUTODATA(json_command, &openchannel_bump_command); AUTODATA(json_command, &openchannel_abort_command); static void start_fresh_dualopend(struct peer *peer, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, struct channel *channel) { int hsmfd; @@ -3201,8 +3193,8 @@ static void start_fresh_dualopend(struct peer *peer, dual_opend_msg, channel_errmsg, channel_set_billboard, - take(&pps->peer_fd), - take(&pps->gossip_fd), + take(&peer_fd), + take(&gossip_fd), take(&hsmfd), NULL); if (!channel->owner) { @@ -3239,7 +3231,7 @@ static void start_fresh_dualopend(struct peer *peer, } void peer_restart_dualopend(struct peer *peer, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, struct channel *channel) { u32 max_to_self_delay, blockheight; @@ -3251,7 +3243,7 @@ void peer_restart_dualopend(struct peer *peer, u8 *msg; if (channel_unsaved(channel)) { - start_fresh_dualopend(peer, pps, channel); + start_fresh_dualopend(peer, peer_fd, gossip_fd, channel); return; } hsmfd = hsm_get_client_fd(peer->ld, &peer->id, channel->dbid, @@ -3268,8 +3260,8 @@ void peer_restart_dualopend(struct peer *peer, dual_opend_msg, channel_errmsg, channel_set_billboard, - take(&pps->peer_fd), - take(&pps->gossip_fd), + take(&peer_fd), + take(&gossip_fd), take(&hsmfd), NULL)); if (!channel->owner) { log_broken(channel->log, "Could not subdaemon channel: %s", @@ -3343,7 +3335,7 @@ void peer_restart_dualopend(struct peer *peer, subd_send_msg(channel->owner, take(msg)); } -void peer_start_dualopend(struct peer *peer, struct per_peer_state *pps) +void peer_start_dualopend(struct peer *peer, int peer_fd, int gossip_fd) { struct channel *channel; @@ -3353,5 +3345,5 @@ void peer_start_dualopend(struct peer *peer, struct per_peer_state *pps) peer->ld->config.fee_base, peer->ld->config.fee_per_satoshi); - start_fresh_dualopend(peer, pps, channel); + start_fresh_dualopend(peer, peer_fd, gossip_fd, channel); } diff --git a/lightningd/dual_open_control.h b/lightningd/dual_open_control.h index 8657a40a6b1b..f7a11d786321 100644 --- a/lightningd/dual_open_control.h +++ b/lightningd/dual_open_control.h @@ -4,12 +4,10 @@ #include "config.h" #include -struct per_peer_state; - -void peer_start_dualopend(struct peer *peer, struct per_peer_state *pps); +void peer_start_dualopend(struct peer *peer, int peer_fd, int gossip_fd); void peer_restart_dualopend(struct peer *peer, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, struct channel *channel); void dualopen_tell_depth(struct subd *dualopend, diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index da24e6c4c2db..c6b77e9b47a1 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -571,7 +571,7 @@ static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds U /* Only error onchaind can get is if it dies. */ static void onchain_error(struct channel *channel, - struct per_peer_state *pps UNUSED, + int peer_fd UNUSED, int gossip_fd UNUSED, const struct channel_id *channel_id UNUSED, const char *desc, bool warning UNUSED, diff --git a/lightningd/opening_common.c b/lightningd/opening_common.c index bcf6ba210719..eb2ff1aecce0 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -1,7 +1,6 @@ #include "config.h" #include #include -#include #include #include #include @@ -76,14 +75,15 @@ new_uncommitted_channel(struct peer *peer) } void opend_channel_errmsg(struct uncommitted_channel *uc, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const struct channel_id *channel_id UNUSED, const char *desc, bool warning UNUSED, const u8 *err_for_them UNUSED) { /* Close fds, if any. */ - tal_free(pps); + close(peer_fd); + close(gossip_fd); uncommitted_channel_disconnect(uc, LOG_INFORM, desc); tal_free(uc); } @@ -169,7 +169,7 @@ void handle_reestablish(struct lightningd *ld, const struct node_id *peer_id, const struct channel_id *channel_id, const u8 *reestablish, - struct per_peer_state *pps) + int peer_fd, int gossip_fd) { struct peer *peer; struct channel *c; @@ -185,7 +185,8 @@ void handle_reestablish(struct lightningd *ld, if (c && channel_closed(c)) { log_debug(c->log, "Reestablish on %s channel: using channeld to reply", channel_state_name(c)); - peer_start_channeld(c, pps, NULL, true, reestablish); + peer_start_channeld(c, peer_fd, gossip_fd, NULL, true, + reestablish); } else { const u8 *err = towire_errorfmt(tmpctx, channel_id, "Unknown channel for reestablish"); @@ -194,12 +195,8 @@ void handle_reestablish(struct lightningd *ld, subd_send_msg(ld->connectd, take(towire_connectd_peer_final_msg(NULL, peer_id, err))); - subd_send_fd(ld->connectd, pps->peer_fd); - subd_send_fd(ld->connectd, pps->gossip_fd); - /* Don't close those fds! */ - pps->peer_fd - = pps->gossip_fd - = -1; + subd_send_fd(ld->connectd, peer_fd); + subd_send_fd(ld->connectd, gossip_fd); } } diff --git a/lightningd/opening_common.h b/lightningd/opening_common.h index 8def23c573de..644a876f59e6 100644 --- a/lightningd/opening_common.h +++ b/lightningd/opening_common.h @@ -89,17 +89,13 @@ struct funding_channel { /* Any commands trying to cancel us. */ struct command **cancels; - - /* Place to stash the per-peer-state while we wait - * for them to get back to us with signatures */ - struct per_peer_state *pps; }; struct uncommitted_channel * new_uncommitted_channel(struct peer *peer); void opend_channel_errmsg(struct uncommitted_channel *uc, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const struct channel_id *channel_id UNUSED, const char *desc, bool warning UNUSED, @@ -125,7 +121,7 @@ void handle_reestablish(struct lightningd *ld, const struct node_id *peer_id, const struct channel_id *channel_id, const u8 *reestablish, - struct per_peer_state *pps); + int peer_fd, int gossip_fd); #if DEVELOPER struct command; diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 4cb58766e95f..441658de8d7b 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -337,7 +336,6 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, struct channel *channel; struct lightningd *ld = openingd->ld; u8 *remote_upfront_shutdown_script; - struct per_peer_state *pps; struct penalty_base *pbase; struct channel_type *type; @@ -371,9 +369,6 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, } remote_commit->chainparams = chainparams; - pps = new_per_peer_state(resp); - per_peer_state_set_fds_arr(pps, fds); - log_debug(ld->log, "%s", type_to_string(tmpctx, struct pubkey, &channel_info.remote_per_commit)); @@ -411,7 +406,7 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, wallet_penalty_base_add(ld->wallet, channel->dbid, pbase); funding_success(channel); - peer_start_channeld(channel, pps, NULL, false, NULL); + peer_start_channeld(channel, fds[0], fds[1], NULL, false, NULL); cleanup: /* Frees fc too */ @@ -436,7 +431,6 @@ static void opening_fundee_finished(struct subd *openingd, u8 channel_flags; struct channel *channel; u8 *remote_upfront_shutdown_script, *local_upfront_shutdown_script; - struct per_peer_state *pps; struct penalty_base *pbase; struct channel_type *type; @@ -474,8 +468,6 @@ static void opening_fundee_finished(struct subd *openingd, } remote_commit->chainparams = chainparams; - pps = new_per_peer_state(tmpctx); - per_peer_state_set_fds_arr(pps, fds); /* openingd should never accept them funding channel in this case. */ if (peer_active_channel(uc->peer)) { @@ -524,7 +516,7 @@ static void opening_fundee_finished(struct subd *openingd, wallet_penalty_base_add(ld->wallet, channel->dbid, pbase); /* On to normal operation! */ - peer_start_channeld(channel, pps, fwd_msg, false, NULL); + peer_start_channeld(channel, fds[0], fds[1], fwd_msg, false, NULL); tal_free(uc); return; @@ -811,22 +803,22 @@ static void opening_got_reestablish(struct subd *openingd, const u8 *msg, struct node_id peer_id = uc->peer->id; struct channel_id channel_id; u8 *reestablish; - struct per_peer_state *pps; if (!fromwire_openingd_got_reestablish(tmpctx, msg, &channel_id, &reestablish)) { log_broken(openingd->log, "Malformed opening_got_reestablish %s", tal_hex(tmpctx, msg)); tal_free(openingd); + close(fds[0]); + close(fds[1]); return; } - pps = new_per_peer_state(tmpctx); - per_peer_state_set_fds_arr(pps, fds); /* This could free peer */ tal_free(uc); - handle_reestablish(ld, &peer_id, &channel_id, reestablish, pps); + handle_reestablish(ld, &peer_id, &channel_id, reestablish, + fds[0], fds[1]); } static unsigned int openingd_msg(struct subd *openingd, @@ -909,7 +901,7 @@ static unsigned int openingd_msg(struct subd *openingd, return 0; } -void peer_start_openingd(struct peer *peer, struct per_peer_state *pps) +void peer_start_openingd(struct peer *peer, int peer_fd, int gossip_fd) { int hsmfd; u32 max_to_self_delay; @@ -932,8 +924,8 @@ void peer_start_openingd(struct peer *peer, struct per_peer_state *pps) openingd_msg, opend_channel_errmsg, opend_channel_set_billboard, - take(&pps->peer_fd), - take(&pps->gossip_fd), + take(&peer_fd), + take(&gossip_fd), take(&hsmfd), NULL); if (!uc->open_daemon) { uncommitted_channel_disconnect(uc, LOG_BROKEN, diff --git a/lightningd/opening_control.h b/lightningd/opening_control.h index 3c5f3343afc1..b17f480e5f01 100644 --- a/lightningd/opening_control.h +++ b/lightningd/opening_control.h @@ -8,14 +8,13 @@ struct channel_id; struct crypto_state; struct json_stream; struct lightningd; -struct per_peer_state; struct uncommitted_channel; void json_add_uncommitted_channel(struct json_stream *response, const struct uncommitted_channel *uc); void peer_start_openingd(struct peer *peer, - struct per_peer_state *pps); + int peer_fd, int gossip_fd); struct subd *peer_get_owning_subd(struct peer *peer); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index d1f4dcc3199b..1bd26e281cab 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -281,7 +280,7 @@ void drop_to_chain(struct lightningd *ld, struct channel *channel, } void channel_errmsg(struct channel *channel, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const struct channel_id *channel_id UNUSED, const char *desc, bool warning, @@ -299,8 +298,8 @@ void channel_errmsg(struct channel *channel, return; } - /* No per_peer_state means a subd crash or disconnection. */ - if (!pps) { + /* No peer_fd means a subd crash or disconnection. */ + if (peer_fd < 0) { /* If the channel is unsaved, we forget it */ channel_fail_reconnect(channel, "%s: %s", channel->owner->name, desc); @@ -931,7 +930,7 @@ struct peer_connected_hook_payload { struct wireaddr_internal addr; bool incoming; struct peer *peer; - struct per_peer_state *pps; + int peer_fd, gossip_fd; u8 *error; }; @@ -1011,7 +1010,10 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa assert(!channel->owner); channel->peer->addr = addr; channel->peer->connected_incoming = payload->incoming; - peer_restart_dualopend(peer, payload->pps, channel); + peer_restart_dualopend(peer, + payload->peer_fd, + payload->gossip_fd, + channel); return; case CHANNELD_AWAITING_LOCKIN: case CHANNELD_NORMAL: @@ -1020,7 +1022,10 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa assert(!channel->owner); channel->peer->addr = addr; channel->peer->connected_incoming = payload->incoming; - peer_start_channeld(channel, payload->pps, NULL, true, + peer_start_channeld(channel, + payload->peer_fd, + payload->gossip_fd, + NULL, true, NULL); return; } @@ -1039,11 +1044,18 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa || channel->state == AWAITING_UNILATERAL); channel->peer->addr = addr; channel->peer->connected_incoming = payload->incoming; - peer_restart_dualopend(peer, payload->pps, channel); + peer_restart_dualopend(peer, + payload->peer_fd, + payload->gossip_fd, + channel); } else - peer_start_dualopend(peer, payload->pps); + peer_start_dualopend(peer, + payload->peer_fd, + payload->gossip_fd); } else - peer_start_openingd(peer, payload->pps); + peer_start_openingd(peer, + payload->peer_fd, + payload->gossip_fd); return; send_error: @@ -1053,12 +1065,8 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa subd_send_msg(ld->connectd, take(towire_connectd_peer_final_msg(NULL, &peer->id, error))); - subd_send_fd(ld->connectd, payload->pps->peer_fd); - subd_send_fd(ld->connectd, payload->pps->gossip_fd); - /* Don't close those fds! */ - payload->pps->peer_fd - = payload->pps->gossip_fd - = -1; + subd_send_fd(ld->connectd, payload->peer_fd); + subd_send_fd(ld->connectd, payload->gossip_fd); } static bool @@ -1132,8 +1140,8 @@ void peer_connected(struct lightningd *ld, const u8 *msg, fatal("Connectd gave bad CONNECT_PEER_CONNECTED message %s", tal_hex(msg, msg)); - hook_payload->pps = new_per_peer_state(hook_payload); - per_peer_state_set_fds(hook_payload->pps, peer_fd, gossip_fd); + hook_payload->peer_fd = peer_fd; + hook_payload->gossip_fd = gossip_fd; /* If we're already dealing with this peer, hand off to correct * subdaemon. Otherwise, we'll hand to openingd to wait there. */ diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 3ce98cd368bc..ecdc39b39a7e 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -11,7 +11,6 @@ #include #include -struct per_peer_state; struct wally_psbt; struct peer { @@ -71,7 +70,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg, #define OUR_CHANNEL_FLAGS CHANNEL_FLAGS_ANNOUNCE_CHANNEL void channel_errmsg(struct channel *channel, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const struct channel_id *channel_id, const char *desc, bool warning, diff --git a/lightningd/subd.c b/lightningd/subd.c index 3bcb84611402..56a6d49bd810 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -409,21 +409,21 @@ static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[2]) void *channel = sd->channel; struct channel_id channel_id; char *desc; - struct per_peer_state *pps; u8 *err_for_them; bool warning; if (!fromwire_status_peer_error(msg, msg, &channel_id, &desc, &warning, - &err_for_them)) + &err_for_them)) { + close(fds[0]); + close(fds[1]); return false; - - pps = new_per_peer_state(msg); - per_peer_state_set_fds_arr(pps, fds); + } /* Don't free sd; we may be about to free channel. */ sd->channel = NULL; - sd->errcb(channel, pps, &channel_id, desc, warning, err_for_them); + sd->errcb(channel, fds[0], fds[1], &channel_id, desc, warning, + err_for_them); return true; } @@ -626,7 +626,7 @@ static void destroy_subd(struct subd *sd) if (!outer_transaction) db_begin_transaction(db); if (sd->errcb) - sd->errcb(channel, NULL, NULL, + sd->errcb(channel, -1, -1, NULL, tal_fmt(sd, "Owning subdaemon %s died (%i)", sd->name, status), false, NULL); @@ -682,7 +682,7 @@ static struct subd *new_subd(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const struct channel_id *channel_id, const char *desc, bool warning, @@ -792,7 +792,7 @@ struct subd *new_channel_subd_(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const struct channel_id *channel_id, const char *desc, bool warning, diff --git a/lightningd/subd.h b/lightningd/subd.h index 73b9534bda2b..bfa7fef1c26f 100644 --- a/lightningd/subd.h +++ b/lightningd/subd.h @@ -47,7 +47,7 @@ struct subd { * sufficient information to hand back to gossipd, including the * error message we sent them if any. */ void (*errcb)(void *channel, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const struct channel_id *channel_id, const char *desc, bool warning, @@ -124,7 +124,7 @@ struct subd *new_channel_subd_(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - struct per_peer_state *pps, + int peer_fd, int gossip_fd, const struct channel_id *channel_id, const char *desc, bool warning, @@ -141,7 +141,7 @@ struct subd *new_channel_subd_(struct lightningd *ld, (msgname), (msgcb), \ typesafe_cb_postargs(void, void *, (errcb), \ (channel), \ - struct per_peer_state *, \ + int, int, \ const struct channel_id *, \ const char *, bool, const u8 *), \ typesafe_cb_postargs(void, void *, (billboardcb), \ diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index 83c5fd00d3d6..b0a2469d946a 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -170,18 +170,12 @@ struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, /* Generated stub for new_log_book */ struct log_book *new_log_book(struct lightningd *ld UNNEEDED, size_t max_mem UNNEEDED) { 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) -{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for new_topology */ struct chain_topology *new_topology(struct lightningd *ld UNNEEDED, struct log *log UNNEEDED) { fprintf(stderr, "new_topology called!\n"); abort(); } /* Generated stub for onchaind_replay_channels */ void onchaind_replay_channels(struct lightningd *ld UNNEEDED) { fprintf(stderr, "onchaind_replay_channels called!\n"); abort(); } -/* Generated stub for per_peer_state_set_fds_arr */ -void per_peer_state_set_fds_arr(struct per_peer_state *pps UNNEEDED, const int *fds UNNEEDED) -{ fprintf(stderr, "per_peer_state_set_fds_arr called!\n"); abort(); } /* Generated stub for plugins_config */ void plugins_config(struct plugins *plugins UNNEEDED) { fprintf(stderr, "plugins_config called!\n"); abort(); } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index ee40d1794457..19d2028fccb4 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -444,9 +444,6 @@ struct height_states *new_height_states(const tal_t *ctx UNNEEDED, enum side opener UNNEEDED, const u32 *blockheight UNNEEDED) { fprintf(stderr, "new_height_states called!\n"); abort(); } -/* Generated stub for new_per_peer_state */ -struct per_peer_state *new_per_peer_state(const tal_t *ctx UNNEEDED) -{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for new_reltimer_ */ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, const tal_t *ctx UNNEEDED, @@ -580,30 +577,26 @@ struct channel *peer_normal_channel(struct peer *peer UNNEEDED) { fprintf(stderr, "peer_normal_channel called!\n"); abort(); } /* Generated stub for peer_restart_dualopend */ void peer_restart_dualopend(struct peer *peer UNNEEDED, - struct per_peer_state *pps UNNEEDED, + int peer_fd UNNEEDED, int gossip_fd UNNEEDED, struct channel *channel UNNEEDED) { fprintf(stderr, "peer_restart_dualopend called!\n"); abort(); } /* Generated stub for peer_start_channeld */ void peer_start_channeld(struct channel *channel UNNEEDED, - struct per_peer_state *pps UNNEEDED, + int peer_fd UNNEEDED, int gossip_fd UNNEEDED, const u8 *fwd_msg UNNEEDED, bool reconnected UNNEEDED, const u8 *reestablish_only UNNEEDED) { fprintf(stderr, "peer_start_channeld called!\n"); abort(); } /* Generated stub for peer_start_dualopend */ -void peer_start_dualopend(struct peer *peer UNNEEDED, struct per_peer_state *pps UNNEEDED) +void peer_start_dualopend(struct peer *peer UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED) { fprintf(stderr, "peer_start_dualopend called!\n"); abort(); } /* Generated stub for peer_start_openingd */ void peer_start_openingd(struct peer *peer UNNEEDED, - struct per_peer_state *pps UNNEEDED) + int peer_fd UNNEEDED, int gossip_fd UNNEEDED) { fprintf(stderr, "peer_start_openingd called!\n"); abort(); } /* Generated stub for peer_unsaved_channel */ struct channel *peer_unsaved_channel(struct peer *peer UNNEEDED) { fprintf(stderr, "peer_unsaved_channel called!\n"); abort(); } -/* Generated stub for per_peer_state_set_fds */ -void per_peer_state_set_fds(struct per_peer_state *pps UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED) -{ fprintf(stderr, "per_peer_state_set_fds called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ bool plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, tal_t *cb_arg STEALS UNNEEDED) diff --git a/lightningd/test/run-shuffle_fds.c b/lightningd/test/run-shuffle_fds.c index 3d7fb6e524d0..651f49b6484f 100644 --- a/lightningd/test/run-shuffle_fds.c +++ b/lightningd/test/run-shuffle_fds.c @@ -108,12 +108,6 @@ struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, const struct node_id *default_node_id UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "new_log called!\n"); abort(); } -/* Generated stub for new_per_peer_state */ -struct per_peer_state *new_per_peer_state(const tal_t *ctx UNNEEDED) -{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } -/* Generated stub for per_peer_state_set_fds_arr */ -void per_peer_state_set_fds_arr(struct per_peer_state *pps UNNEEDED, const int *fds UNNEEDED) -{ fprintf(stderr, "per_peer_state_set_fds_arr called!\n"); abort(); } /* Generated stub for subdaemon_path */ const char *subdaemon_path(const tal_t *ctx UNNEEDED, const struct lightningd *ld UNNEEDED, const char *name UNNEEDED) { fprintf(stderr, "subdaemon_path called!\n"); abort(); } diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index a239b1f7e9ce..82ebc3dcef7a 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -448,9 +448,6 @@ struct chain_coin_mvt *new_coin_deposit_sat(const tal_t *ctx UNNEEDED, u32 blockheight UNNEEDED, struct amount_sat amount UNNEEDED) { fprintf(stderr, "new_coin_deposit_sat called!\n"); abort(); } -/* Generated stub for new_per_peer_state */ -struct per_peer_state *new_per_peer_state(const tal_t *ctx UNNEEDED) -{ fprintf(stderr, "new_per_peer_state called!\n"); abort(); } /* Generated stub for notify_chain_mvt */ void notify_chain_mvt(struct lightningd *ld UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED) { fprintf(stderr, "notify_chain_mvt called!\n"); abort(); } @@ -607,22 +604,22 @@ void peer_memleak_done(struct command *cmd UNNEEDED, struct subd *leaker UNNEEDE { fprintf(stderr, "peer_memleak_done called!\n"); abort(); } /* Generated stub for peer_restart_dualopend */ void peer_restart_dualopend(struct peer *peer UNNEEDED, - struct per_peer_state *pps UNNEEDED, + int peer_fd UNNEEDED, int gossip_fd UNNEEDED, struct channel *channel UNNEEDED) { fprintf(stderr, "peer_restart_dualopend called!\n"); abort(); } /* Generated stub for peer_start_channeld */ void peer_start_channeld(struct channel *channel UNNEEDED, - struct per_peer_state *pps UNNEEDED, + int peer_fd UNNEEDED, int gossip_fd UNNEEDED, const u8 *fwd_msg UNNEEDED, bool reconnected UNNEEDED, const u8 *reestablish_only UNNEEDED) { fprintf(stderr, "peer_start_channeld called!\n"); abort(); } /* Generated stub for peer_start_dualopend */ -void peer_start_dualopend(struct peer *peer UNNEEDED, struct per_peer_state *pps UNNEEDED) +void peer_start_dualopend(struct peer *peer UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED) { fprintf(stderr, "peer_start_dualopend called!\n"); abort(); } /* Generated stub for peer_start_openingd */ void peer_start_openingd(struct peer *peer UNNEEDED, - struct per_peer_state *pps UNNEEDED) + int peer_fd UNNEEDED, int gossip_fd UNNEEDED) { fprintf(stderr, "peer_start_openingd called!\n"); abort(); } /* Generated stub for peer_wire_is_defined */ bool peer_wire_is_defined(u16 type UNNEEDED) @@ -630,10 +627,6 @@ bool peer_wire_is_defined(u16 type UNNEEDED) /* Generated stub for peer_wire_name */ const char *peer_wire_name(int e UNNEEDED) { fprintf(stderr, "peer_wire_name called!\n"); abort(); } -/* Generated stub for per_peer_state_set_fds */ -void per_peer_state_set_fds(struct per_peer_state *pps UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED) -{ fprintf(stderr, "per_peer_state_set_fds called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ bool plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, tal_t *cb_arg STEALS UNNEEDED) From 006a335e128b24962ac3a9d4cbfee349cbcd4f9e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:09 +1030 Subject: [PATCH 26/51] connectd: remove per_peer_state in favor of keeping gossip_fd directly. Signed-off-by: Rusty Russell --- connectd/connectd.c | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index a3c939acbbcd..fc02c3242b19 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -218,10 +218,9 @@ static void peer_connected_in(struct daemon *daemon, * 'features' is a field in the `init` message, indicating properties of the * node. */ -static bool get_gossipfds(struct daemon *daemon, - const struct node_id *id, - const u8 *their_features, - struct per_peer_state *pps) +static int get_gossipfd(struct daemon *daemon, + const struct node_id *id, + const u8 *their_features) { bool gossip_queries_feature, success; u8 *msg; @@ -251,13 +250,13 @@ static bool get_gossipfds(struct daemon *daemon, if (!success) { status_broken("Gossipd did not give us an fd: losing peer %s", type_to_string(tmpctx, struct node_id, id)); - return false; + return -1; } /* Otherwise, the next thing in the socket will be the file descriptor * for the per-peer daemon. */ - pps->gossip_fd = fdpass_recv(GOSSIPCTL_FD); - return true; + return fdpass_recv(GOSSIPCTL_FD); + } /*~ This is an ad-hoc marshalling structure where we store arguments so we @@ -387,8 +386,7 @@ struct io_plan *peer_connected(struct io_conn *conn, struct peer *peer; int unsup; size_t depender, missing; - int subd_fd; - struct per_peer_state *pps; + int subd_fd, gossip_fd; peer = peer_htable_get(&daemon->peers, id); if (peer) @@ -446,11 +444,9 @@ struct io_plan *peer_connected(struct io_conn *conn, if (!peer) return io_close(conn); - /* FIXME: Remove pps abstraction! */ - pps = new_per_peer_state(tmpctx); - /* If gossipd can't give us a file descriptor, we give up connecting. */ - if (!get_gossipfds(daemon, id, their_features, pps)) { + gossip_fd = get_gossipfd(daemon, id, their_features); + if (gossip_fd < 0) { close(subd_fd); return tal_free(peer); } @@ -467,10 +463,7 @@ struct io_plan *peer_connected(struct io_conn *conn, * we have connected, and give the peer and gossip fds. */ daemon_conn_send(daemon->master, take(msg)); daemon_conn_send_fd(daemon->master, subd_fd); - daemon_conn_send_fd(daemon->master, pps->gossip_fd); - - /* Don't try to close this on freeing. */ - pps->gossip_fd = -1; + daemon_conn_send_fd(daemon->master, gossip_fd); /*~ Now we set up this connection to read/write from subd */ return multiplex_peer_setup(conn, peer); @@ -1881,32 +1874,24 @@ static void peer_final_msg(struct io_conn *conn, struct daemon *daemon, const u8 *msg) { struct peer *peer; - struct per_peer_state *pps; struct node_id id; u8 *finalmsg; - int fds[2]; if (!fromwire_connectd_peer_final_msg(tmpctx, msg, &id, &finalmsg)) master_badmsg(WIRE_CONNECTD_PEER_FINAL_MSG, msg); - /* Get the fds for this peer. */ + /* Get the peer_fd and gossip_fd for this peer: we don't need them. */ io_fd_block(io_conn_fd(conn), true); - for (size_t i = 0; i < ARRAY_SIZE(fds); i++) { - fds[i] = fdpass_recv(io_conn_fd(conn)); - if (fds[i] == -1) + for (size_t i = 0; i < 2; i++) { + int fd = fdpass_recv(io_conn_fd(conn)); + if (fd == -1) status_failed(STATUS_FAIL_MASTER_IO, "Getting fd %zu after peer_final_msg: %s", i, strerror(errno)); + close(fd); } io_fd_block(io_conn_fd(conn), false); - /* Close fd to ourselves. */ - close(fds[0]); - - /* We put peer fd into conn, but pps needs to free the gossip_fd */ - pps = new_per_peer_state(tmpctx); - per_peer_state_set_fds(pps, -1, fds[1]); - /* This can happen if peer hung up on us. */ peer = peer_htable_get(&daemon->peers, &id); if (peer) { From 71b02f418633518131ab513a84ad1c7dddb3a8f4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:09 +1030 Subject: [PATCH 27/51] connectd: put more stuff into struct gossip_state. We're the only ones who use it now, so put our fields inside it and make it local. Signed-off-by: Rusty Russell --- common/gossip_store.c | 95 +++++++++------------------- common/gossip_store.h | 9 +-- common/per_peer_state.h | 7 --- connectd/connectd.c | 2 - connectd/connectd.h | 23 ++++--- connectd/multiplex.c | 134 ++++++++++++++++++++-------------------- 6 files changed, 118 insertions(+), 152 deletions(-) diff --git a/common/gossip_store.c b/common/gossip_store.c index 191e9d8b6d8c..57a12d3c683e 100644 --- a/common/gossip_store.c +++ b/common/gossip_store.c @@ -11,7 +11,8 @@ #include #include -static bool timestamp_filter(const struct gossip_state *gs, u32 timestamp) +static bool timestamp_filter(u32 timestamp_min, u32 timestamp_max, + u32 timestamp) { /* BOLT #7: * @@ -20,25 +21,11 @@ static bool timestamp_filter(const struct gossip_state *gs, u32 timestamp) * `timestamp_range`. */ /* Note that we turn first_timestamp & timestamp_range into an inclusive range */ - return timestamp >= gs->timestamp_min - && timestamp <= gs->timestamp_max; + return timestamp >= timestamp_min + && timestamp <= timestamp_max; } -/* Not all the data we expected was there: rewind file */ -static void failed_read(int fd, int len) -{ - if (len < 0) { - /* Grab errno before lseek overrides it */ - const char *err = strerror(errno); - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "gossip_store: failed read @%"PRIu64": %s", - (u64)lseek(fd, 0, SEEK_CUR), err); - } - - lseek(fd, -len, SEEK_CUR); -} - -static void reopen_gossip_store(int *gossip_store_fd, const u8 *msg) +static size_t reopen_gossip_store(int *gossip_store_fd, const u8 *msg) { u64 equivalent_offset; int newfd; @@ -57,17 +44,16 @@ static void reopen_gossip_store(int *gossip_store_fd, const u8 *msg) status_debug("gossip_store at end, new fd moved to %"PRIu64, equivalent_offset); - lseek(newfd, equivalent_offset, SEEK_SET); close(*gossip_store_fd); *gossip_store_fd = newfd; + return equivalent_offset; } -u8 *gossip_store_iter(const tal_t *ctx, +u8 *gossip_store_next(const tal_t *ctx, int *gossip_store_fd, - struct gossip_state *gs, - struct gossip_rcvd_filter *grf, - size_t *off) + u32 timestamp_min, u32 timestamp_max, + size_t *off, size_t *end) { u8 *msg = NULL; @@ -77,16 +63,9 @@ u8 *gossip_store_iter(const tal_t *ctx, bool push; int type, r; - if (off) - r = pread(*gossip_store_fd, &hdr, sizeof(hdr), *off); - else - r = read(*gossip_store_fd, &hdr, sizeof(hdr)); - if (r != sizeof(hdr)) { - /* We expect a 0 read here at EOF */ - if (r != 0 && off) - failed_read(*gossip_store_fd, r); + r = pread(*gossip_store_fd, &hdr, sizeof(hdr), *off); + if (r != sizeof(hdr)) return NULL; - } msglen = be32_to_cpu(hdr.len); push = (msglen & GOSSIP_STORE_LEN_PUSH_BIT); @@ -94,56 +73,42 @@ u8 *gossip_store_iter(const tal_t *ctx, /* Skip any deleted entries. */ if (be32_to_cpu(hdr.len) & GOSSIP_STORE_LEN_DELETED_BIT) { - /* Skip over it. */ - if (off) - *off += r + msglen; - else - lseek(*gossip_store_fd, msglen, SEEK_CUR); + *off += r + msglen; continue; } checksum = be32_to_cpu(hdr.crc); timestamp = be32_to_cpu(hdr.timestamp); msg = tal_arr(ctx, u8, msglen); - if (off) - r = pread(*gossip_store_fd, msg, msglen, *off + r); - else - r = read(*gossip_store_fd, msg, msglen); - if (r != msglen) { - if (!off) - failed_read(*gossip_store_fd, r); + r = pread(*gossip_store_fd, msg, msglen, *off + r); + if (r != msglen) return NULL; - } if (checksum != crc32c(be32_to_cpu(hdr.timestamp), msg, msglen)) status_failed(STATUS_FAIL_INTERNAL_ERROR, - "gossip_store: bad checksum offset %" - PRIi64": %s", - off ? (s64)*off : - (s64)lseek(*gossip_store_fd, - 0, SEEK_CUR) - msglen, - tal_hex(tmpctx, msg)); + "gossip_store: bad checksum offset %zu" + ": %s", + *off, tal_hex(tmpctx, msg)); /* Definitely processing it now */ - if (off) - *off += sizeof(hdr) + msglen; - - /* Don't send back gossip they sent to us! */ - if (gossip_rcvd_filter_del(grf, msg)) { - msg = tal_free(msg); - continue; - } + *off += sizeof(hdr) + msglen; + if (*off > *end) + *end = *off; type = fromwire_peektype(msg); - if (type == WIRE_GOSSIP_STORE_ENDED) - reopen_gossip_store(gossip_store_fd, msg); + /* end can go backwards in this case! */ + if (type == WIRE_GOSSIP_STORE_ENDED) { + *off = *end = reopen_gossip_store(gossip_store_fd, msg); /* Ignore gossipd internal messages. */ - else if (type != WIRE_CHANNEL_ANNOUNCEMENT - && type != WIRE_CHANNEL_UPDATE - && type != WIRE_NODE_ANNOUNCEMENT) + } else if (type != WIRE_CHANNEL_ANNOUNCEMENT + && type != WIRE_CHANNEL_UPDATE + && type != WIRE_NODE_ANNOUNCEMENT) { msg = tal_free(msg); - else if (!push && !timestamp_filter(gs, timestamp)) + } else if (!push && + !timestamp_filter(timestamp_min, timestamp_max, + timestamp)) { msg = tal_free(msg); + } } return msg; diff --git a/common/gossip_store.h b/common/gossip_store.h index e1d760860ae6..b5d8fad1905d 100644 --- a/common/gossip_store.h +++ b/common/gossip_store.h @@ -40,12 +40,13 @@ struct gossip_hdr { * Direct store accessor: loads gossip msg from store. * * Returns NULL if there are no more gossip msgs. + * Updates *end if the known end of file has moved. + * Updates *gossip_store_fd if file has been compacted. */ -u8 *gossip_store_iter(const tal_t *ctx, +u8 *gossip_store_next(const tal_t *ctx, int *gossip_store_fd, - struct gossip_state *gs, - struct gossip_rcvd_filter *grf, - size_t *off); + u32 timestamp_min, u32 timestamp_max, + size_t *off, size_t *end); /** * Gossipd will be writing to this, and it's not atomic! Safest diff --git a/common/per_peer_state.h b/common/per_peer_state.h index a81360ab3485..af41d95f0a8d 100644 --- a/common/per_peer_state.h +++ b/common/per_peer_state.h @@ -6,13 +6,6 @@ #include #include -struct gossip_state { - /* Time for next gossip burst. */ - struct timemono next_gossip; - /* Timestamp filtering for gossip. */ - u32 timestamp_min, timestamp_max; -}; - /* Things we hand between daemons to talk to peers. */ struct per_peer_state { /* If not -1, closed on freeing */ diff --git a/connectd/connectd.c b/connectd/connectd.c index fc02c3242b19..9aab4c9d2545 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -357,7 +357,6 @@ static struct peer *new_peer(struct daemon *daemon, peer->urgent = false; peer->peer_outq = msg_queue_new(peer); peer->subd_outq = msg_queue_new(peer); - peer->grf = new_gossip_rcvd_filter(peer); /* Aim for connection to shuffle data back and forth: sets up * peer->to_subd */ @@ -368,7 +367,6 @@ static struct peer *new_peer(struct daemon *daemon, peer_htable_add(&daemon->peers, peer); tal_add_destructor2(peer, destroy_peer, daemon); - peer->gs = NULL; return peer; } diff --git a/connectd/connectd.h b/connectd/connectd.h index 09c79bd18e3a..ff4057538cd7 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -13,6 +13,20 @@ struct io_conn; struct connecting; struct wireaddr_internal; +/*~ All the gossip_store related fields are kept together for convenience. */ +struct gossip_state { + /* Is it active right now? */ + bool active; + /* Except with dev override, this fires every 60 seconds */ + struct oneshot *gossip_timer; + /* Timestamp filtering for gossip. */ + u32 timestamp_min, timestamp_max; + /* I think this is called "echo cancellation" */ + struct gossip_rcvd_filter *grf; + /* Offset within the gossip_store file */ + size_t off; +}; + /*~ We keep a hash table (ccan/htable) of peers, which tells us what peers are * already connected (by peer->id). */ struct peer { @@ -45,13 +59,8 @@ struct peer { /* Peer sent buffer (for freeing after sending) */ const u8 *sent_to_peer; - /* Gossip store. */ - struct gossip_state *gs; - /* FIXME: move into gs. */ - struct gossip_rcvd_filter *grf; - size_t gossip_store_off; - - struct oneshot *gossip_timer; + /* We stream from the gossip_store for them, when idle */ + struct gossip_state gs; }; /*~ The HTABLE_DEFINE_TYPE() macro needs a keyof() function to extract the key: diff --git a/connectd/multiplex.c b/connectd/multiplex.c index f77a5e5da7c0..30c2d1088202 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -51,41 +51,28 @@ static void send_warning(struct peer *peer, const char *fmt, ...) va_end(ap); } -/* Either for initial setup, or when they ask by timestamp */ -static bool setup_gossip_filter(struct peer *peer, - u32 first_timestamp, - u32 timestamp_range) -{ - bool immediate_sync; +/* Kicks off write_to_peer() to look for more gossip to send from store */ +static void wake_gossip(struct peer *peer); - /* If this is the first filter, we gossip sync immediately. */ - if (!peer->gs) { - peer->gs = tal(peer, struct gossip_state); - peer->gs->next_gossip = time_mono(); - immediate_sync = true; - } else - immediate_sync = false; +static struct oneshot *gossip_stream_timer(struct peer *peer) +{ + u32 next; /* BOLT #7: * - * The receiver: - * - SHOULD send all gossip messages whose `timestamp` is greater or - * equal to `first_timestamp`, and less than `first_timestamp` plus - * `timestamp_range`. - * - MAY wait for the next outgoing gossip flush to send these. - * ... - * - SHOULD restrict future gossip messages to those whose `timestamp` - * is greater or equal to `first_timestamp`, and less than - * `first_timestamp` plus `timestamp_range`. + * 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). */ - peer->gs->timestamp_min = first_timestamp; - peer->gs->timestamp_max = first_timestamp + timestamp_range - 1; - /* Make sure we never leave it on an impossible value. */ - if (peer->gs->timestamp_max < peer->gs->timestamp_min) - peer->gs->timestamp_max = UINT32_MAX; + /* We shorten this for dev_fast_gossip! */ + next = GOSSIP_FLUSH_INTERVAL(peer->daemon->dev_fast_gossip); - peer->gossip_store_off = 1; - return immediate_sync; + return new_reltimer(&peer->daemon->timers, + peer, time_from_sec(next), + wake_gossip, peer); } /* This is called once we need it: otherwise, the gossip_store may not exist, @@ -111,7 +98,7 @@ void setup_peer_gossip_store(struct peer *peer, if (peer->daemon->gossip_store_fd == -1) setup_gossip_store(peer->daemon); - peer->gossip_timer = NULL; + peer->gs.grf = new_gossip_rcvd_filter(peer); /* BOLT #7: * @@ -120,10 +107,17 @@ void setup_peer_gossip_store(struct peer *peer, * - MUST NOT relay any gossip messages it did not generate itself, * unless explicitly requested. */ - if (feature_negotiated(our_features, their_features, OPT_GOSSIP_QUERIES)) + if (feature_negotiated(our_features, their_features, OPT_GOSSIP_QUERIES)) { + peer->gs.gossip_timer = NULL; + peer->gs.active = false; + peer->gs.off = 1; return; + } - setup_gossip_filter(peer, 0, UINT32_MAX); + peer->gs.gossip_timer = gossip_stream_timer(peer); + peer->gs.active = true; + peer->gs.timestamp_min = 0; + peer->gs.timestamp_max = UINT32_MAX; /* BOLT #7: * @@ -136,10 +130,12 @@ void setup_peer_gossip_store(struct peer *peer, * - SHOULD resume normal operation, as specified in the * following [Rebroadcasting](#rebroadcasting) section. */ - if (!feature_offered(their_features, OPT_INITIAL_ROUTING_SYNC)) { + if (feature_offered(their_features, OPT_INITIAL_ROUTING_SYNC)) + peer->gs.off = 1; + else { /* During tests, particularly, we find that the gossip_store * moves fast, so make sure it really does start at the end. */ - peer->gossip_store_off + peer->gs.off = find_gossip_store_end(peer->daemon->gossip_store_fd, peer->daemon->gossip_store_end); } @@ -270,8 +266,11 @@ static inline bool timemono_before(struct timemono a, struct timemono b) /* Kicks off write_to_peer() to look for more gossip to send from store */ static void wake_gossip(struct peer *peer) { - peer->gossip_timer = NULL; + peer->gs.active = true; io_wake(peer->peer_outq); + + /* And go again in 60 seconds (from now, now when we finish!) */ + peer->gs.gossip_timer = gossip_stream_timer(peer); } /* If we are streaming gossip, get something from gossip store */ @@ -280,43 +279,32 @@ static u8 *maybe_from_gossip_store(const tal_t *ctx, struct peer *peer) u8 *msg; /* Not streaming yet? */ - if (!peer->gs) + if (!peer->gs.active) return NULL; - /* Still waiting for timer? */ - if (peer->gossip_timer != NULL) - return NULL; - - msg = gossip_store_iter(ctx, &peer->daemon->gossip_store_fd, - peer->gs, peer->grf, &peer->gossip_store_off); - - /* Cache highest valid offset (FIXME: doesn't really work when - * gossip_store gets rewritten!) */ - if (peer->gossip_store_off > peer->daemon->gossip_store_end) - peer->daemon->gossip_store_end = peer->gossip_store_off; + /* This should be around to kick us every 60 seconds */ + assert(peer->gs.gossip_timer); +again: + msg = gossip_store_next(ctx, &peer->daemon->gossip_store_fd, + peer->gs.timestamp_min, + peer->gs.timestamp_max, + &peer->gs.off, + &peer->daemon->gossip_store_end); + /* Don't send back gossip they sent to us! */ if (msg) { + status_peer_debug(&peer->id, + "Sending gossip %s", + peer_wire_name(fromwire_peektype(msg))); + if (gossip_rcvd_filter_del(peer->gs.grf, msg)) { + msg = tal_free(msg); + goto again; + } status_peer_io(LOG_IO_OUT, &peer->id, msg); return msg; } - /* 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). - */ - /* We do 60 seconds from *start*, not from *now* */ - peer->gs->next_gossip - = timemono_add(time_mono(), - time_from_sec(GOSSIP_FLUSH_INTERVAL( - peer->daemon->dev_fast_gossip))); - peer->gossip_timer = new_abstimer(&peer->daemon->timers, peer, - peer->gs->next_gossip, - wake_gossip, peer); + peer->gs.active = false; return NULL; } @@ -328,7 +316,7 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg) /* We remember these so we don't rexmit them */ if (is_msg_gossip_broadcast(msg)) - gossip_rcvd_filter_add(peer->grf, msg); + gossip_rcvd_filter_add(peer->gs.grf, msg); if (!fromwire_gossip_timestamp_filter(msg, &chain_hash, &first_timestamp, @@ -342,9 +330,21 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg) return true; } - /* Returns true the first time. */ - if (setup_gossip_filter(peer, first_timestamp, timestamp_range)) + peer->gs.timestamp_min = first_timestamp; + peer->gs.timestamp_max = first_timestamp + timestamp_range - 1; + /* Make sure we never leave it on an impossible value. */ + if (peer->gs.timestamp_max < peer->gs.timestamp_min) + peer->gs.timestamp_max = UINT32_MAX; + + peer->gs.off = 1; + + /* BOLT #7: + * - MAY wait for the next outgoing gossip flush to send these. + */ + /* We send immediately the first time, after that we wait. */ + if (!peer->gs.gossip_timer) wake_gossip(peer); + return true; } From d80283467b1a2a3889f430bb8c80a41271ace397 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:10 +1030 Subject: [PATCH 28/51] connectd: get addresses from lightningd, not gossipd. It's weird to have connectd ask gossipd, when lightningd can just do it and hand all the addresses together. Signed-off-by: Rusty Russell --- connectd/connectd.c | 38 +++---- connectd/connectd_gossipd_wire.csv | 8 -- connectd/connectd_wire.csv | 2 + gossipd/gossipd.c | 27 +++-- gossipd/gossipd_wire.csv | 8 ++ lightningd/channel.c | 8 +- lightningd/connect_control.c | 104 ++++++++++++++++---- lightningd/connect_control.h | 4 +- lightningd/gossip_control.c | 2 + lightningd/peer_control.c | 25 +---- lightningd/test/run-invoice-select-inchan.c | 15 +-- wallet/test/run-wallet.c | 11 +-- 12 files changed, 134 insertions(+), 118 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 9aab4c9d2545..3cbfc3c7ffa6 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1669,37 +1669,19 @@ static void add_seed_addrs(struct wireaddr_internal **addrs, } } -static bool wireaddr_int_equals_wireaddr(struct wireaddr_internal *addr_a, - struct wireaddr *addr_b) +static bool wireaddr_int_equals_wireaddr(const struct wireaddr_internal *addr_a, + const struct wireaddr *addr_b) { if (!addr_a || !addr_b) return false; return wireaddr_eq(&addr_a->u.wireaddr, addr_b); } -/*~ This asks gossipd for any addresses advertized by the node. */ +/*~ Orders the addresses which lightningd gave us. */ static void add_gossip_addrs(struct wireaddr_internal **addrs, - const struct node_id *id, - struct wireaddr_internal *addrhint) + const struct wireaddr *normal_addrs, + const struct wireaddr_internal *addrhint) { - u8 *msg; - struct wireaddr *normal_addrs; - - /* For simplicity, we do this synchronous. */ - msg = towire_gossipd_get_addrs(NULL, id); - if (!wire_sync_write(GOSSIPCTL_FD, take(msg))) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed writing to gossipctl: %s", - strerror(errno)); - - /* This returns 'struct wireaddr's since that's what's supported by - * the BOLT #7 protocol. */ - msg = wire_sync_read(tmpctx, GOSSIPCTL_FD); - if (!fromwire_gossipd_get_addrs_reply(tmpctx, msg, &normal_addrs)) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed parsing get_addrs_reply gossipctl: %s", - tal_hex(tmpctx, msg)); - /* Wrap each one in a wireaddr_internal and add to addrs. */ for (size_t i = 0; i < tal_count(normal_addrs); i++) { /* This is not supported, ignore. */ @@ -1736,6 +1718,7 @@ static void add_gossip_addrs(struct wireaddr_internal **addrs, static void try_connect_peer(struct daemon *daemon, const struct node_id *id, u32 seconds_waited, + struct wireaddr *gossip_addrs, struct wireaddr_internal *addrhint STEALS) { struct wireaddr_internal *addrs; @@ -1767,7 +1750,7 @@ static void try_connect_peer(struct daemon *daemon, if (addrhint) tal_arr_expand(&addrs, *addrhint); - add_gossip_addrs(&addrs, id, addrhint); + add_gossip_addrs(&addrs, gossip_addrs, addrhint); if (tal_count(addrs) == 0) { /* Don't resolve via DNS seed if we're supposed to use proxy. */ @@ -1824,13 +1807,14 @@ static void connect_to_peer(struct daemon *daemon, const u8 *msg) struct node_id id; u32 seconds_waited; struct wireaddr_internal *addrhint; + struct wireaddr *addrs; if (!fromwire_connectd_connect_to_peer(tmpctx, msg, - &id, &seconds_waited, - &addrhint)) + &id, &seconds_waited, + &addrs, &addrhint)) master_badmsg(WIRE_CONNECTD_CONNECT_TO_PEER, msg); - try_connect_peer(daemon, &id, seconds_waited, addrhint); + try_connect_peer(daemon, &id, seconds_waited, addrs, addrhint); } /* A peer is gone: clean things up. */ diff --git a/connectd/connectd_gossipd_wire.csv b/connectd/connectd_gossipd_wire.csv index 11133197442f..5517b450afde 100644 --- a/connectd/connectd_gossipd_wire.csv +++ b/connectd/connectd_gossipd_wire.csv @@ -11,11 +11,3 @@ msgdata,gossipd_new_peer,gossip_queries_feature,bool, # if success: + gossip fd msgtype,gossipd_new_peer_reply,4100 msgdata,gossipd_new_peer_reply,success,bool, - -# Connectd asks gossipd for any known addresses for that node. -msgtype,gossipd_get_addrs,4001 -msgdata,gossipd_get_addrs,id,node_id, - -msgtype,gossipd_get_addrs_reply,4101 -msgdata,gossipd_get_addrs_reply,num,u16, -msgdata,gossipd_get_addrs_reply,addrs,wireaddr,num diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index 960f74f9f90a..deee01f4f4a3 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -47,6 +47,8 @@ msgdata,connectd_reconnected,id,node_id, msgtype,connectd_connect_to_peer,2001 msgdata,connectd_connect_to_peer,id,node_id, msgdata,connectd_connect_to_peer,seconds_waited,u32, +msgdata,connectd_connect_to_peer,len,u32, +msgdata,connectd_connect_to_peer,addrs,wireaddr,len msgdata,connectd_connect_to_peer,addrhint,?wireaddr_internal, # Connectd->master: connect failed. diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 28feabde83f2..e3964a1c224b 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -891,10 +891,10 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, return daemon_conn_read_next(conn, daemon->connectd); } -/*~ connectd can also ask us if we know any addresses for a given id. */ -static struct io_plan *connectd_get_address(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +/*~ lightningd asks us if we know any addresses for a given id. */ +static struct io_plan *handle_get_address(struct io_conn *conn, + struct daemon *daemon, + const u8 *msg) { struct node_id id; u8 rgb_color[3]; @@ -903,20 +903,17 @@ static struct io_plan *connectd_get_address(struct io_conn *conn, struct wireaddr *addrs; struct lease_rates *rates; - if (!fromwire_gossipd_get_addrs(msg, &id)) { - status_broken("Bad gossipd_get_addrs msg from connectd: %s", - tal_hex(tmpctx, msg)); - return io_close(conn); - } + if (!fromwire_gossipd_get_addrs(msg, &id)) + master_badmsg(WIRE_GOSSIPD_GET_ADDRS, msg); if (!get_node_announcement_by_id(tmpctx, daemon, &id, rgb_color, alias, &features, &addrs, &rates)) addrs = NULL; - daemon_conn_send(daemon->connectd, + daemon_conn_send(daemon->master, take(towire_gossipd_get_addrs_reply(NULL, addrs))); - return daemon_conn_read_next(conn, daemon->connectd); + return daemon_conn_read_next(conn, daemon->master); } /*~ connectd's input handler is very simple. */ @@ -930,12 +927,8 @@ static struct io_plan *connectd_req(struct io_conn *conn, case WIRE_GOSSIPD_NEW_PEER: return connectd_new_peer(conn, daemon, msg); - case WIRE_GOSSIPD_GET_ADDRS: - return connectd_get_address(conn, daemon, msg); - /* We send these, don't receive them. */ case WIRE_GOSSIPD_NEW_PEER_REPLY: - case WIRE_GOSSIPD_GET_ADDRS_REPLY: break; } @@ -1413,6 +1406,9 @@ static struct io_plan *recv_req(struct io_conn *conn, handle_new_lease_rates(daemon, msg); goto done; + case WIRE_GOSSIPD_GET_ADDRS: + return handle_get_address(conn, daemon, msg); + #if DEVELOPER case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: dev_set_max_scids_encode_size(daemon, msg); @@ -1450,6 +1446,7 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: case WIRE_GOSSIPD_ADDGOSSIP_REPLY: + case WIRE_GOSSIPD_GET_ADDRS_REPLY: break; } diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index 8f49421d0312..705ffec75770 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -105,3 +105,11 @@ msgdata,gossipd_addgossip_reply,err,wirestring, # Updated lease rates available msgtype,gossipd_new_lease_rates,3046 msgdata,gossipd_new_lease_rates,rates,lease_rates, + +# Lightningd asks gossipd for any known addresses for that node. +msgtype,gossipd_get_addrs,3050 +msgdata,gossipd_get_addrs,id,node_id, + +msgtype,gossipd_get_addrs_reply,3150 +msgdata,gossipd_get_addrs_reply,num,u16, +msgdata,gossipd_get_addrs_reply,addrs,wireaddr,num diff --git a/lightningd/channel.c b/lightningd/channel.c index 7dd36581458d..6a7f0161bf31 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -875,10 +875,10 @@ static void err_and_reconnect(struct channel *channel, channel_set_owner(channel, NULL); /* Their address only useful if we connected to them */ - delay_then_reconnect(channel, seconds_before_reconnect, - channel->peer->connected_incoming - ? NULL - : &channel->peer->addr); + try_reconnect(channel, seconds_before_reconnect, + channel->peer->connected_incoming + ? NULL + : &channel->peer->addr); } void channel_fail_reconnect_later(struct channel *channel, const char *fmt, ...) diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index bd0c6bfb28c7..fe96b555e077 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,14 @@ static struct command_result *connect_cmd_succeed(struct command *cmd, return command_success(cmd, response); } +/* FIXME: Reorder! */ +static void try_connect(const tal_t *ctx, + struct lightningd *ld, + const struct node_id *id, + struct channel *channel, + u32 seconds_delay, + const struct wireaddr_internal *addrhint); + static struct command_result *json_connect(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, @@ -82,7 +91,6 @@ static struct command_result *json_connect(struct command *cmd, char *ataddr = NULL; const char *name; struct wireaddr_internal *addr; - u8 *msg; const char *err_msg; struct peer *peer; @@ -165,8 +173,7 @@ static struct command_result *json_connect(struct command *cmd, } else addr = NULL; - msg = towire_connectd_connect_to_peer(NULL, &id, 0, addr); - subd_send_msg(cmd->ld->connectd, take(msg)); + try_connect(cmd, cmd->ld, &id, NULL, 0, addr); /* Leave this here for peer_connected or connect_failed. */ new_connect(cmd->ld, &id, cmd); @@ -182,36 +189,65 @@ static const struct json_command connect_command = { }; AUTODATA(json_command, &connect_command); +/* We actually use this even if we don't need a delay, while we talk to + * gossipd to get the addresses. */ struct delayed_reconnect { + struct lightningd *ld; + struct node_id id; + /* May be unset if there's no associated channel */ struct channel *channel; u32 seconds_delayed; struct wireaddr_internal *addrhint; }; -static void maybe_reconnect(struct delayed_reconnect *d) +static void gossipd_got_addrs(struct subd *subd, + const u8 *msg, + const int *fds, + struct delayed_reconnect *d) { - struct peer *peer = d->channel->peer; - - /* Might have gone onchain since we started timer. */ - if (channel_active(d->channel)) { - u8 *msg = towire_connectd_connect_to_peer(NULL, &peer->id, - d->seconds_delayed, - d->addrhint); - subd_send_msg(peer->ld->connectd, take(msg)); + struct wireaddr *addrs; + u8 *connectmsg; + + if (!fromwire_gossipd_get_addrs_reply(tmpctx, msg, &addrs)) + fatal("Gossipd gave bad GOSSIPD_GET_ADDRS_REPLY %s", + tal_hex(msg, msg)); + + /* Might have gone onchain (if it was actually freed, we were too). */ + if (d->channel && !channel_active(d->channel)) { + tal_free(d); + return; } + + connectmsg = towire_connectd_connect_to_peer(NULL, + &d->id, + d->seconds_delayed, + addrs, + d->addrhint); + subd_send_msg(d->ld->connectd, take(connectmsg)); tal_free(d); } -void delay_then_reconnect(struct channel *channel, u32 seconds_delay, - const struct wireaddr_internal *addrhint) +/* We might be off a delay timer. Now ask gossipd about public addresses. */ +static void do_connect(struct delayed_reconnect *d) { - struct delayed_reconnect *d; - struct lightningd *ld = channel->peer->ld; + u8 *msg = towire_gossipd_get_addrs(NULL, &d->id); - if (!ld->reconnect) - return; + subd_req(d, d->ld->gossip, take(msg), -1, 0, gossipd_got_addrs, d); +} - d = tal(channel, struct delayed_reconnect); +/* channel may be NULL here */ +static void try_connect(const tal_t *ctx, + struct lightningd *ld, + const struct node_id *id, + struct channel *channel, + u32 seconds_delay, + const struct wireaddr_internal *addrhint) +{ + struct delayed_reconnect *d; + + d = tal(ctx, struct delayed_reconnect); + d->ld = ld; + d->id = *id; d->channel = channel; d->seconds_delayed = seconds_delay; if (addrhint) @@ -219,6 +255,17 @@ void delay_then_reconnect(struct channel *channel, u32 seconds_delay, else d->addrhint = NULL; + if (!seconds_delay) { + do_connect(d); + return; + } + + /* We never have a delay when connecting without a channel */ + assert(channel); + channel_set_billboard(channel, false, + tal_fmt(tmpctx, + "Will attempt reconnect " + "in %u seconds", seconds_delay)); log_debug(channel->log, "Will try reconnect in %u seconds", seconds_delay); @@ -227,7 +274,22 @@ void delay_then_reconnect(struct channel *channel, u32 seconds_delay, notleak(new_reltimer(ld->timers, d, timerel_add(time_from_sec(seconds_delay), time_from_usec(pseudorand(1000000))), - maybe_reconnect, d)); + do_connect, d)); +} + +void try_reconnect(struct channel *channel, + u32 seconds_delay, + const struct wireaddr_internal *addrhint) +{ + if (!channel->peer->ld->reconnect) + return; + + try_connect(channel, + channel->peer->ld, + &channel->peer->id, + channel, + seconds_delay, + addrhint); } static void connect_failed(struct lightningd *ld, const u8 *msg) @@ -254,7 +316,7 @@ static void connect_failed(struct lightningd *ld, const u8 *msg) /* If we have an active channel, then reconnect. */ channel = active_channel_by_id(ld, &id, NULL); if (channel) - delay_then_reconnect(channel, seconds_to_delay, addrhint); + try_reconnect(channel, seconds_to_delay, addrhint); } void connect_succeeded(struct lightningd *ld, const struct peer *peer, diff --git a/lightningd/connect_control.h b/lightningd/connect_control.h index 830332b3d37c..67beb003782b 100644 --- a/lightningd/connect_control.h +++ b/lightningd/connect_control.h @@ -10,8 +10,8 @@ struct wireaddr_internal; int connectd_init(struct lightningd *ld); void connectd_activate(struct lightningd *ld); -void delay_then_reconnect(struct channel *channel, u32 seconds_delay, - const struct wireaddr_internal *addrhint TAKES); +void try_reconnect(struct channel *channel, u32 seconds_delay, + const struct wireaddr_internal *addrhint TAKES); void connect_succeeded(struct lightningd *ld, const struct peer *peer, bool incoming, const struct wireaddr_internal *addr); diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index d64575220a04..622fa2fdcd80 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -126,12 +126,14 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: case WIRE_GOSSIPD_SEND_ONIONMSG: case WIRE_GOSSIPD_ADDGOSSIP: + case WIRE_GOSSIPD_GET_ADDRS: /* This is a reply, so never gets through to here. */ case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY: case WIRE_GOSSIPD_ADDGOSSIP_REPLY: + case WIRE_GOSSIPD_GET_ADDRS_REPLY: break; case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 1bd26e281cab..afeb63660b12 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1537,7 +1537,6 @@ command_find_channel(struct command *cmd, static void activate_peer(struct peer *peer, u32 delay) { - u8 *msg; struct channel *channel; struct channel_inflight *inflight; struct lightningd *ld = peer->ld; @@ -1545,28 +1544,8 @@ static void activate_peer(struct peer *peer, u32 delay) /* We can only have one active channel: make sure connectd * knows to try reconnecting. */ channel = peer_active_channel(peer); - if (channel && ld->reconnect) { - if (delay > 0) { - channel_set_billboard(channel, false, - tal_fmt(tmpctx, - "Will attempt reconnect " - "in %u seconds", - delay)); - delay_then_reconnect(channel, delay, - peer->connected_incoming - ? NULL - : &peer->addr); - } else { - msg = towire_connectd_connect_to_peer(NULL, - &peer->id, 0, - peer->connected_incoming - ? NULL - : &peer->addr); - subd_send_msg(ld->connectd, take(msg)); - channel_set_billboard(channel, false, - "Attempting to reconnect"); - } - } + if (channel) + try_reconnect(channel, delay, &peer->addr); list_for_each(&peer->channels, channel, list) { if (channel_unsaved(channel)) diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 19d2028fccb4..5af0727915fe 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -94,10 +94,6 @@ void channel_internal_error(struct channel *channel UNNEEDED, const char *fmt UN /* Generated stub for channel_last_funding_feerate */ u32 channel_last_funding_feerate(const struct channel *channel UNNEEDED) { fprintf(stderr, "channel_last_funding_feerate called!\n"); abort(); } -/* Generated stub for channel_set_billboard */ -void channel_set_billboard(struct channel *channel UNNEEDED, bool perm UNNEEDED, - const char *str TAKES UNNEEDED) -{ fprintf(stderr, "channel_set_billboard called!\n"); abort(); } /* Generated stub for channel_set_last_tx */ void channel_set_last_tx(struct channel *channel UNNEEDED, struct bitcoin_tx *tx UNNEEDED, @@ -164,10 +160,6 @@ void db_begin_transaction_(struct db *db UNNEEDED, const char *location UNNEEDED /* Generated stub for db_commit_transaction */ void db_commit_transaction(struct db *db UNNEEDED) { fprintf(stderr, "db_commit_transaction called!\n"); abort(); } -/* Generated stub for delay_then_reconnect */ -void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UNNEEDED, - const struct wireaddr_internal *addrhint TAKES UNNEEDED) -{ fprintf(stderr, "delay_then_reconnect called!\n"); abort(); } /* Generated stub for delete_channel */ void delete_channel(struct channel *channel STEALS UNNEEDED) { fprintf(stderr, "delete_channel called!\n"); abort(); } @@ -638,9 +630,6 @@ u8 *towire_channeld_dev_reenable_commit(const tal_t *ctx UNNEEDED) /* Generated stub for towire_channeld_specific_feerates */ u8 *towire_channeld_specific_feerates(const tal_t *ctx UNNEEDED, u32 feerate_base UNNEEDED, u32 feerate_ppm UNNEEDED) { fprintf(stderr, "towire_channeld_specific_feerates called!\n"); abort(); } -/* Generated stub for towire_connectd_connect_to_peer */ -u8 *towire_connectd_connect_to_peer(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u32 seconds_waited UNNEEDED, const struct wireaddr_internal *addrhint UNNEEDED) -{ fprintf(stderr, "towire_connectd_connect_to_peer called!\n"); abort(); } /* Generated stub for towire_connectd_peer_final_msg */ u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "towire_connectd_peer_final_msg called!\n"); abort(); } @@ -669,6 +658,10 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, const struct channel_id *channel UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "towire_warningfmt called!\n"); abort(); } +/* Generated stub for try_reconnect */ +void try_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UNNEEDED, + const struct wireaddr_internal *addrhint TAKES UNNEEDED) +{ fprintf(stderr, "try_reconnect called!\n"); abort(); } /* Generated stub for version */ const char *version(void) { fprintf(stderr, "version called!\n"); abort(); } diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 82ebc3dcef7a..493c3fb0f511 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -95,10 +95,6 @@ struct onionreply *create_onionreply(const tal_t *ctx UNNEEDED, const struct secret *shared_secret UNNEEDED, const u8 *failure_msg UNNEEDED) { fprintf(stderr, "create_onionreply called!\n"); abort(); } -/* Generated stub for delay_then_reconnect */ -void delay_then_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UNNEEDED, - const struct wireaddr_internal *addrhint TAKES UNNEEDED) -{ fprintf(stderr, "delay_then_reconnect called!\n"); abort(); } /* Generated stub for derive_channel_id */ void derive_channel_id(struct channel_id *channel_id UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED) @@ -709,9 +705,6 @@ u8 *towire_channeld_sending_commitsig_reply(const tal_t *ctx UNNEEDED) /* Generated stub for towire_channeld_specific_feerates */ u8 *towire_channeld_specific_feerates(const tal_t *ctx UNNEEDED, u32 feerate_base UNNEEDED, u32 feerate_ppm UNNEEDED) { fprintf(stderr, "towire_channeld_specific_feerates called!\n"); abort(); } -/* Generated stub for towire_connectd_connect_to_peer */ -u8 *towire_connectd_connect_to_peer(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u32 seconds_waited UNNEEDED, const struct wireaddr_internal *addrhint UNNEEDED) -{ fprintf(stderr, "towire_connectd_connect_to_peer called!\n"); abort(); } /* Generated stub for towire_connectd_peer_disconnected */ u8 *towire_connectd_peer_disconnected(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED) { fprintf(stderr, "towire_connectd_peer_disconnected called!\n"); abort(); } @@ -794,6 +787,10 @@ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, const struct channel_id *channel UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "towire_warningfmt called!\n"); abort(); } +/* Generated stub for try_reconnect */ +void try_reconnect(struct channel *channel UNNEEDED, u32 seconds_delay UNNEEDED, + const struct wireaddr_internal *addrhint TAKES UNNEEDED) +{ fprintf(stderr, "try_reconnect called!\n"); abort(); } /* Generated stub for watch_txid */ struct txwatch *watch_txid(const tal_t *ctx UNNEEDED, struct chain_topology *topo UNNEEDED, From aee1b466f5722de24a705faf64254ef703da2d71 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:49 +1030 Subject: [PATCH 29/51] lightningd: start gossipd after channels are loaded. This is in preparation for gossipd feeding us the latest channel_updates, rather than having lightningd and channeld query gossipd when it wants to send an onion error with an update included. This means gossipd will start telling us the updates, so we need the channels loaded first. Signed-off-by: Rusty Russell --- lightningd/lightningd.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 45b8f4adc8f1..1303f3ed75e2 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -1027,11 +1027,6 @@ int main(int argc, char *argv[]) * socket pair, and gives us the other */ connectd_gossipd_fd = connectd_init(ld); - /*~ The gossip daemon looks after the routing gossip; - * channel_announcement, channel_update, node_announcement and gossip - * queries. */ - gossip_init(ld, connectd_gossipd_fd); - /*~ We do every database operation within a transaction; usually this * is covered by the infrastructure (eg. opening a transaction before * handling a message or expiring a timer), but for startup we do this @@ -1078,6 +1073,12 @@ int main(int argc, char *argv[]) unconnected_htlcs_in = load_channels_from_wallet(ld); db_commit_transaction(ld->wallet->db); + /*~ The gossip daemon looks after the routing gossip; + * channel_announcement, channel_update, node_announcement and gossip + * queries. It also hands us the latest channel_updates for our + * channels. */ + gossip_init(ld, connectd_gossipd_fd); + /*~ Create RPC socket: now lightning-cli can send us JSON RPC commands * over a UNIX domain socket specified by `ld->rpc_filename`. */ jsonrpc_listen(ld->jsonrpc, ld); From 3e00b5dcadc91e069e4a04df9dac2dd42898cd2e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:49 +1030 Subject: [PATCH 30/51] gossipd: infrastructure to tell lightningd about local channel updates. We want it to keep the latest, so it can make its own error msgs without asking us. This installs (but does not use!) the message handler. Signed-off-by: Rusty Russell --- gossipd/gossipd.c | 1 + gossipd/gossipd_wire.csv | 6 ++++++ lightningd/channel.c | 2 ++ lightningd/channel.h | 3 +++ lightningd/gossip_control.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 43 insertions(+) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index e3964a1c224b..ec3f9f23e7cb 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1447,6 +1447,7 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: case WIRE_GOSSIPD_ADDGOSSIP_REPLY: case WIRE_GOSSIPD_GET_ADDRS_REPLY: + case WIRE_GOSSIPD_GOT_LOCAL_CHANNEL_UPDATE: break; } diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index 705ffec75770..fac229afedc3 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -113,3 +113,9 @@ msgdata,gossipd_get_addrs,id,node_id, msgtype,gossipd_get_addrs_reply,3150 msgdata,gossipd_get_addrs_reply,num,u16, msgdata,gossipd_get_addrs_reply,addrs,wireaddr,num + +# Tell master a local channel update (so it can serve errors). +msgtype,gossipd_got_local_channel_update,3151 +msgdata,gossipd_got_local_channel_update,scid,short_channel_id, +msgdata,gossipd_got_local_channel_update,len,u16, +msgdata,gossipd_got_local_channel_update,channel_update,u8,len diff --git a/lightningd/channel.c b/lightningd/channel.c index 6a7f0161bf31..c98d8864b159 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -254,6 +254,7 @@ struct channel *new_unsaved_channel(struct peer *peer, = CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE; channel->shutdown_wrong_funding = NULL; channel->closing_feerate_range = NULL; + channel->channel_update = NULL; /* Channel is connected! */ channel->connected = true; @@ -462,6 +463,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->lease_chan_max_msat = lease_chan_max_msat; channel->lease_chan_max_ppt = lease_chan_max_ppt; channel->blockheight_states = dup_height_states(channel, height_states); + channel->channel_update = NULL; list_add_tail(&peer->channels, &channel->list); channel->rr_number = peer->ld->rr_counter++; diff --git a/lightningd/channel.h b/lightningd/channel.h index 76a73d5b47ae..e0ce8e395aff 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -233,6 +233,9 @@ struct channel { u32 lease_chan_max_msat; /* Lease commited max part per thousandth channel fee (ppm * 1000) */ u16 lease_chan_max_ppt; + + /* Latest channel_update, for use in error messages. */ + u8 *channel_update; }; /* For v2 opens, a channel that has not yet been committed/saved to disk */ diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 622fa2fdcd80..027129189b1a 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -4,10 +4,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -106,6 +108,32 @@ static void get_txout(struct subd *gossip, const u8 *msg) } } +static void handle_local_channel_update(struct lightningd *ld, const u8 *msg) +{ + struct short_channel_id scid; + u8 *update; + struct channel *channel; + + if (!fromwire_gossipd_got_local_channel_update(msg, msg, + &scid, &update)) { + fatal("Gossip gave bad GOSSIP_GOT_LOCAL_CHANNEL_UPDATE %s", + tal_hex(msg, msg)); + } + + /* In theory this could vanish before gossipd gets around to telling + * us. */ + channel = any_channel_by_scid(ld, &scid); + if (!channel) { + log_broken(ld->log, "Local update for bad scid %s", + type_to_string(tmpctx, struct short_channel_id, + &scid)); + return; + } + + tal_free(channel->channel_update); + channel->channel_update = tal_steal(channel, update); +} + static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) { enum gossipd_wire t = fromwire_peektype(msg); @@ -142,6 +170,9 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_GET_TXOUT: get_txout(gossip, msg); break; + case WIRE_GOSSIPD_GOT_LOCAL_CHANNEL_UPDATE: + handle_local_channel_update(gossip->ld, msg); + break; } return 0; } From 40dac53409053e31843fbb8e7bbfa04701aa79cc Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:49 +1030 Subject: [PATCH 31/51] gossipd: feed lightningd the channel_updates as soon as we make them. Even if we're deferring putting them in the store and broadcasting them, we tell lightningd so it will use it in any error messages. Signed-off-by: Rusty Russell --- gossipd/gossip_generation.c | 7 +++++++ gossipd/test/run-check_node_announcement.c | 6 ++++++ gossipd/test/run-crc32_of_update.c | 6 ++++++ tests/test_gossip.py | 11 +++++++++-- tests/test_misc.py | 4 +++- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 6ca0ff3e521e..22497709eb6c 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -3,6 +3,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include @@ -418,6 +420,11 @@ static u8 *sign_and_timestamp_update(const tal_t *ctx, if (taken(unsigned_update)) tal_free(unsigned_update); + /* Tell lightningd about this immediately (even if we're not actually + * applying it now) */ + msg = towire_gossipd_got_local_channel_update(NULL, &chan->scid, update); + daemon_conn_send(daemon->master, take(msg)); + return update; } diff --git a/gossipd/test/run-check_node_announcement.c b/gossipd/test/run-check_node_announcement.c index 95b2bdc1930e..ac5c80f27b89 100644 --- a/gossipd/test/run-check_node_announcement.c +++ b/gossipd/test/run-check_node_announcement.c @@ -24,6 +24,9 @@ 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 ecdh */ void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) { fprintf(stderr, "ecdh called!\n"); abort(); } @@ -97,6 +100,9 @@ void status_fmt(enum log_level level UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "status_fmt called!\n"); abort(); } +/* Generated stub for towire_gossipd_got_local_channel_update */ +u8 *towire_gossipd_got_local_channel_update(const tal_t *ctx UNNEEDED, const struct short_channel_id *scid UNNEEDED, const u8 *channel_update UNNEEDED) +{ fprintf(stderr, "towire_gossipd_got_local_channel_update called!\n"); abort(); } /* Generated stub for towire_hsmd_cupdate_sig_req */ u8 *towire_hsmd_cupdate_sig_req(const tal_t *ctx UNNEEDED, const u8 *cu UNNEEDED) { fprintf(stderr, "towire_hsmd_cupdate_sig_req called!\n"); abort(); } diff --git a/gossipd/test/run-crc32_of_update.c b/gossipd/test/run-crc32_of_update.c index 3b7595f16a84..9c0fef29d132 100644 --- a/gossipd/test/run-crc32_of_update.c +++ b/gossipd/test/run-crc32_of_update.c @@ -28,6 +28,9 @@ 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 daemon_conn_wake */ void daemon_conn_wake(struct daemon_conn *dc UNNEEDED) { fprintf(stderr, "daemon_conn_wake called!\n"); abort(); } @@ -133,6 +136,9 @@ void status_fmt(enum log_level level UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "status_fmt called!\n"); abort(); } +/* Generated stub for towire_gossipd_got_local_channel_update */ +u8 *towire_gossipd_got_local_channel_update(const tal_t *ctx UNNEEDED, const struct short_channel_id *scid UNNEEDED, const u8 *channel_update UNNEEDED) +{ fprintf(stderr, "towire_gossipd_got_local_channel_update called!\n"); abort(); } /* Generated stub for towire_hsmd_cupdate_sig_req */ u8 *towire_hsmd_cupdate_sig_req(const tal_t *ctx UNNEEDED, const u8 *cu UNNEEDED) { fprintf(stderr, "towire_hsmd_cupdate_sig_req called!\n"); abort(); } diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 018989e41493..03312913a8c5 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1794,10 +1794,13 @@ def test_gossip_ratelimit(node_factory, bitcoind): canned gossip to the other partition consisting of l3. l3 should ratelimit the incoming gossip. + We get BROKEN logs because gossipd talks about non-existent channels to + lightningd ("**BROKEN** lightningd: Local update for bad scid 103x1x1"). """ l3, = node_factory.get_nodes( 1, - opts=[{'dev-gossip-time': 1568096251}] + opts=[{'dev-gossip-time': 1568096251, + 'allow_broken_log': True}] ) # Bump to block 102, so the following tx ends up in 103x1: @@ -1953,7 +1956,11 @@ def test_torport_onions(node_factory): @unittest.skipIf(not COMPAT, "needs COMPAT to convert obsolete gossip_store") def test_gossip_store_upgrade_v7_v8(node_factory): """Version 8 added feature bits to local channel announcements""" - l1 = node_factory.get_node(start=False) + + # We get BROKEN logs because gossipd talks about non-existent channels to + # lightningd ("**BROKEN** lightningd: Local update for bad scid 103x1x1"). + l1 = node_factory.get_node(start=False, + allow_broken_log=True) # A channel announcement with no channel_update. with open(os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, 'gossip_store'), 'wb') as f: diff --git a/tests/test_misc.py b/tests/test_misc.py index 7580432d66bd..4afcb4751ebd 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1139,7 +1139,9 @@ def test_funding_reorg_private(node_factory, bitcoind): # Rescan to detect reorg at restart and may_reconnect so channeld # will restart. Reorg can cause bad gossip msg. opts = {'funding-confirms': 2, 'rescan': 10, 'may_reconnect': True, - 'allow_bad_gossip': True} + 'allow_bad_gossip': True, + # gossipd send lightning update for original channel. + 'allow_broken_log': True} l1, l2 = node_factory.line_graph(2, fundchannel=False, opts=opts) l1.fundwallet(10000000) sync_blockheight(bitcoind, [l1]) # height 102 From d581a86e5313bfe69b77c0ec4a765410c1ef4c69 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 15:42:49 +1030 Subject: [PATCH 32/51] lightningd: tell gossipd when we use the channel_update. This way it can flush it if it was pending. Signed-off-by: Rusty Russell --- gossipd/gossip_generation.c | 20 ++++++++++++++++++++ gossipd/gossip_generation.h | 3 +++ gossipd/gossipd.c | 4 ++++ gossipd/gossipd_wire.csv | 4 ++++ gossipd/test/run-check_node_announcement.c | 6 ++++++ gossipd/test/run-crc32_of_update.c | 3 +++ gossipd/test/run-onion_message.c | 3 +++ lightningd/channel.h | 2 ++ lightningd/gossip_control.c | 12 ++++++++++++ 9 files changed, 57 insertions(+) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 22497709eb6c..2653f479a57b 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -811,6 +811,26 @@ void local_disable_chan(struct daemon *daemon, const struct chan *chan, int dire defer_update(daemon, 0xFFFFFFFF, chan, direction, take(update)); } +/* lightningd tells us it used the local channel update. */ +void handle_used_local_channel_update(struct daemon *daemon, const u8 *msg) +{ + struct short_channel_id scid; + struct chan *chan; + + if (!fromwire_gossipd_used_local_channel_update(msg, &scid)) + master_badmsg(WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE, msg); + + chan = get_channel(daemon->rstate, &scid); + /* Might have closed in meantime, but v unlikely! */ + if (!chan) { + status_broken("used_local_channel_update on unknown %s", + type_to_string(tmpctx, struct short_channel_id, + &scid)); + return; + } + local_channel_update_latest(daemon, chan); +} + void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction) { struct deferred_update *du; diff --git a/gossipd/gossip_generation.h b/gossipd/gossip_generation.h index 2e7b396f547f..adc3f81db51d 100644 --- a/gossipd/gossip_generation.h +++ b/gossipd/gossip_generation.h @@ -53,4 +53,7 @@ bool handle_local_channel_update(struct daemon *daemon, const struct node_id *src, const u8 *msg); +/* lightningd tells us it used the last channel_update we sent. */ +void handle_used_local_channel_update(struct daemon *daemon, const u8 *msg); + #endif /* LIGHTNING_GOSSIPD_GOSSIP_GENERATION_H */ diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index ec3f9f23e7cb..bede5aa84449 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1409,6 +1409,10 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_GOSSIPD_GET_ADDRS: return handle_get_address(conn, daemon, msg); + case WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE: + handle_used_local_channel_update(daemon, msg); + goto done; + #if DEVELOPER case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: dev_set_max_scids_encode_size(daemon, msg); diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index fac229afedc3..5b1f2cf79903 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -119,3 +119,7 @@ msgtype,gossipd_got_local_channel_update,3151 msgdata,gossipd_got_local_channel_update,scid,short_channel_id, msgdata,gossipd_got_local_channel_update,len,u16, msgdata,gossipd_got_local_channel_update,channel_update,u8,len + +# Tell gossipd we used the channel update (in case it was deferred) +msgtype,gossipd_used_local_channel_update,3052 +msgdata,gossipd_used_local_channel_update,scid,short_channel_id, diff --git a/gossipd/test/run-check_node_announcement.c b/gossipd/test/run-check_node_announcement.c index ac5c80f27b89..4104556fade7 100644 --- a/gossipd/test/run-check_node_announcement.c +++ b/gossipd/test/run-check_node_announcement.c @@ -39,6 +39,9 @@ char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr /* Generated stub for fromwire_gossipd_local_channel_update */ bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *disable UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, struct amount_msat *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, struct amount_msat *htlc_maximum_msat UNNEEDED) { fprintf(stderr, "fromwire_gossipd_local_channel_update called!\n"); abort(); } +/* Generated stub for fromwire_gossipd_used_local_channel_update */ +bool fromwire_gossipd_used_local_channel_update(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED) +{ fprintf(stderr, "fromwire_gossipd_used_local_channel_update called!\n"); abort(); } /* Generated stub for fromwire_hsmd_cupdate_sig_reply */ bool fromwire_hsmd_cupdate_sig_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **cu UNNEEDED) { fprintf(stderr, "fromwire_hsmd_cupdate_sig_reply called!\n"); abort(); } @@ -78,6 +81,9 @@ void json_object_end(struct json_stream *js UNNEEDED) /* Generated stub for json_object_start */ void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) { fprintf(stderr, "json_object_start called!\n"); abort(); } +/* Generated stub for master_badmsg */ +void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) +{ fprintf(stderr, "master_badmsg called!\n"); abort(); } /* Generated stub for new_onionreply */ struct onionreply *new_onionreply(const tal_t *ctx UNNEEDED, const u8 *contents TAKES UNNEEDED) { fprintf(stderr, "new_onionreply called!\n"); abort(); } diff --git a/gossipd/test/run-crc32_of_update.c b/gossipd/test/run-crc32_of_update.c index 9c0fef29d132..7d9b64037473 100644 --- a/gossipd/test/run-crc32_of_update.c +++ b/gossipd/test/run-crc32_of_update.c @@ -60,6 +60,9 @@ bool fromwire_gossipd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 /* Generated stub for fromwire_gossipd_local_channel_update */ bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *disable UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, struct amount_msat *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, struct amount_msat *htlc_maximum_msat UNNEEDED) { fprintf(stderr, "fromwire_gossipd_local_channel_update called!\n"); abort(); } +/* Generated stub for fromwire_gossipd_used_local_channel_update */ +bool fromwire_gossipd_used_local_channel_update(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED) +{ fprintf(stderr, "fromwire_gossipd_used_local_channel_update called!\n"); abort(); } /* Generated stub for fromwire_hsmd_cupdate_sig_reply */ bool fromwire_hsmd_cupdate_sig_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **cu UNNEEDED) { fprintf(stderr, "fromwire_hsmd_cupdate_sig_reply called!\n"); abort(); } diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 9344bc9bfac5..1fdcdb1c809d 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -183,6 +183,9 @@ const u8 *handle_reply_channel_range(struct peer *peer UNNEEDED, const u8 *msg U /* Generated stub for handle_reply_short_channel_ids_end */ const u8 *handle_reply_short_channel_ids_end(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "handle_reply_short_channel_ids_end called!\n"); abort(); } +/* Generated stub for handle_used_local_channel_update */ +void handle_used_local_channel_update(struct daemon *daemon UNNEEDED, const u8 *msg UNNEEDED) +{ fprintf(stderr, "handle_used_local_channel_update called!\n"); abort(); } /* Generated stub for json_add_member */ void json_add_member(struct json_stream *js UNNEEDED, const char *fieldname UNNEEDED, diff --git a/lightningd/channel.h b/lightningd/channel.h index e0ce8e395aff..774e146ac010 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -469,4 +469,6 @@ void channel_set_billboard(struct channel *channel, bool perm, struct htlc_in *channel_has_htlc_in(struct channel *channel); struct htlc_out *channel_has_htlc_out(struct channel *channel); +const u8 *get_channel_update(struct channel *channel); + #endif /* LIGHTNING_LIGHTNINGD_CHANNEL_H */ diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 027129189b1a..c775bfd2353f 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -134,6 +134,17 @@ static void handle_local_channel_update(struct lightningd *ld, const u8 *msg) channel->channel_update = tal_steal(channel, update); } +const u8 *get_channel_update(struct channel *channel) +{ + /* Tell gossipd we're using it (if shutting down, might be NULL) */ + if (channel->channel_update && channel->peer->ld->gossip) { + subd_send_msg(channel->peer->ld->gossip, + take(towire_gossipd_used_local_channel_update + (NULL, channel->scid))); + } + return channel->channel_update; +} + static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) { enum gossipd_wire t = fromwire_peektype(msg); @@ -155,6 +166,7 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_SEND_ONIONMSG: case WIRE_GOSSIPD_ADDGOSSIP: case WIRE_GOSSIPD_GET_ADDRS: + case WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE: /* This is a reply, so never gets through to here. */ case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: From 0842e89aaf53f2b7d2ce5d956f050774c25c2998 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:56 +1030 Subject: [PATCH 33/51] lightningd: use our cached channel_update for errors instead of asking gossipd. We also no longer strip the type off: everyone handles both forms, and Eclair doesn't strip (and it's easier!). Signed-off-by: Rusty Russell --- gossipd/gossipd.c | 55 ---------- gossipd/gossipd_wire.csv | 8 -- gossipd/test/run-onion_message.c | 6 -- lightningd/gossip_control.c | 2 - lightningd/lightningd.c | 7 +- lightningd/pay.c | 12 +-- lightningd/pay.h | 5 +- lightningd/peer_htlcs.c | 167 +++++++------------------------ lightningd/peer_htlcs.h | 5 +- tests/test_pay.py | 6 +- wallet/test/run-wallet.c | 21 ++-- 11 files changed, 61 insertions(+), 233 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index bede5aa84449..8cc2eee9e21e 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1173,56 +1173,6 @@ static void dev_gossip_set_time(struct daemon *daemon, const u8 *msg) } #endif /* DEVELOPER */ -/*~ lightningd: so, get me the latest update for this local channel, - * so I can include it in an error message. */ -static void get_stripped_cupdate(struct daemon *daemon, const u8 *msg) -{ - struct short_channel_id scid; - struct chan *chan; - const u8 *stripped_update; - - if (!fromwire_gossipd_get_stripped_cupdate(msg, &scid)) - master_badmsg(WIRE_GOSSIPD_GET_STRIPPED_CUPDATE, msg); - - chan = get_channel(daemon->rstate, &scid); - if (!chan) { - status_debug("Failed to resolve local channel %s", - type_to_string(tmpctx, struct short_channel_id, &scid)); - stripped_update = NULL; - } else { - int direction; - const struct half_chan *hc; - - if (!local_direction(daemon->rstate, chan, &direction)) { - status_broken("%s is a non-local channel!", - type_to_string(tmpctx, - struct short_channel_id, - &scid)); - stripped_update = NULL; - goto out; - } - - /* Since we're going to use it, make sure it's up-to-date. */ - local_channel_update_latest(daemon, chan); - - hc = &chan->half[direction]; - if (is_halfchan_defined(hc)) { - const u8 *update; - - update = gossip_store_get(tmpctx, daemon->rstate->gs, - hc->bcast.index); - stripped_update = tal_dup_arr(tmpctx, u8, update + 2, - tal_count(update) - 2, 0); - } else - stripped_update = NULL; - } - -out: - daemon_conn_send(daemon->master, - take(towire_gossipd_get_stripped_cupdate_reply(NULL, - stripped_update))); -} - /*~ We queue incoming channel_announcement pending confirmation from lightningd * that it really is an unspent output. Here's its reply. */ static void handle_txout_reply(struct daemon *daemon, const u8 *msg) @@ -1378,10 +1328,6 @@ static struct io_plan *recv_req(struct io_conn *conn, gossip_init(daemon, msg); goto done; - case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE: - get_stripped_cupdate(daemon, msg); - goto done; - case WIRE_GOSSIPD_GET_TXOUT_REPLY: handle_txout_reply(daemon, msg); goto done; @@ -1444,7 +1390,6 @@ static struct io_plan *recv_req(struct io_conn *conn, /* We send these, we don't receive them */ case WIRE_GOSSIPD_INIT_REPLY: - case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY: case WIRE_GOSSIPD_GET_TXOUT: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index 5b1f2cf79903..8e41cd3b13ba 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -27,14 +27,6 @@ msgdata,gossipd_dev_set_time,dev_gossip_time,u32, msgtype,gossipd_dev_set_max_scids_encode_size,3030 msgdata,gossipd_dev_set_max_scids_encode_size,max,u32, -# Given a short_channel_id, return the latest (stripped) update for error msg. -msgtype,gossipd_get_stripped_cupdate,3010 -msgdata,gossipd_get_stripped_cupdate,channel_id,short_channel_id, - -msgtype,gossipd_get_stripped_cupdate_reply,3110 -msgdata,gossipd_get_stripped_cupdate_reply,stripped_update_len,u16, -msgdata,gossipd_get_stripped_cupdate_reply,stripped_update,u8,stripped_update_len - # gossipd->master: we're closing this channel. msgtype,gossipd_local_channel_close,3027 msgdata,gossipd_local_channel_close,short_channel_id,short_channel_id, diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 1fdcdb1c809d..7eff11f33491 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -85,9 +85,6 @@ bool fromwire_gossipd_dev_suppress(const void *p UNNEEDED) /* Generated stub for fromwire_gossipd_get_addrs */ bool fromwire_gossipd_get_addrs(const void *p UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_gossipd_get_addrs called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_get_stripped_cupdate */ -bool fromwire_gossipd_get_stripped_cupdate(const void *p UNNEEDED, struct short_channel_id *channel_id UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_get_stripped_cupdate called!\n"); abort(); } /* Generated stub for fromwire_gossipd_get_txout_reply */ bool fromwire_gossipd_get_txout_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct amount_sat *satoshis UNNEEDED, u8 **outscript UNNEEDED) { fprintf(stderr, "fromwire_gossipd_get_txout_reply called!\n"); abort(); } @@ -323,9 +320,6 @@ u8 *towire_gossipd_dev_memleak_reply(const tal_t *ctx UNNEEDED, bool leak UNNEED /* Generated stub for towire_gossipd_get_addrs_reply */ u8 *towire_gossipd_get_addrs_reply(const tal_t *ctx UNNEEDED, const struct wireaddr *addrs UNNEEDED) { fprintf(stderr, "towire_gossipd_get_addrs_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_get_stripped_cupdate_reply */ -u8 *towire_gossipd_get_stripped_cupdate_reply(const tal_t *ctx UNNEEDED, const u8 *stripped_update UNNEEDED) -{ fprintf(stderr, "towire_gossipd_get_stripped_cupdate_reply called!\n"); abort(); } /* Generated stub for towire_gossipd_get_txout */ u8 *towire_gossipd_get_txout(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED) { fprintf(stderr, "towire_gossipd_get_txout called!\n"); abort(); } diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index c775bfd2353f..9879599db2fd 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -152,7 +152,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) switch (t) { /* These are messages we send, not them. */ case WIRE_GOSSIPD_INIT: - case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE: case WIRE_GOSSIPD_GET_TXOUT_REPLY: case WIRE_GOSSIPD_OUTPOINT_SPENT: case WIRE_GOSSIPD_NEW_LEASE_RATES: @@ -171,7 +170,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: - case WIRE_GOSSIPD_GET_STRIPPED_CUPDATE_REPLY: case WIRE_GOSSIPD_ADDGOSSIP_REPLY: case WIRE_GOSSIPD_GET_ADDRS_REPLY: break; diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 1303f3ed75e2..3700816625ea 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -526,6 +526,8 @@ static void shutdown_subdaemons(struct lightningd *ld) /*~ The three "global" daemons, which we shutdown explicitly: we * give them 10 seconds to exit gracefully before killing them. */ ld->connectd = subd_shutdown(ld->connectd, 10); + ld->gossip = subd_shutdown(ld->gossip, 10); + ld->hsm = subd_shutdown(ld->hsm, 10); /* Now we free all the HTLCs */ free_htlcs(ld, NULL); @@ -558,11 +560,6 @@ static void shutdown_subdaemons(struct lightningd *ld) tal_free(p); } - /*~ Now they're all dead, we can stop gossipd: doing it before HTLCs is - * problematic because local_fail_in_htlc_needs_update() asks gossipd */ - ld->gossip = subd_shutdown(ld->gossip, 10); - ld->hsm = subd_shutdown(ld->hsm, 10); - /*~ Commit the transaction. Note that the db is actually * single-threaded, so commits never fail and we don't need * spin-and-retry logic everywhere. */ diff --git a/lightningd/pay.c b/lightningd/pay.c index f4db4fc527f5..3b198355c4be 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -536,7 +536,7 @@ void payment_store(struct lightningd *ld, struct wallet_payment *payment TAKES) } void payment_failed(struct lightningd *ld, const struct htlc_out *hout, - const char *localfail, const u8 *failmsg_needs_update) + const char *localfail) { struct wallet_payment *payment; struct routing_failure* fail = NULL; @@ -569,10 +569,7 @@ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, if (localfail) { /* Use temporary_channel_failure if failmsg has it */ enum onion_wire failcode; - if (failmsg_needs_update) - failcode = fromwire_peektype(failmsg_needs_update); - else - failcode = fromwire_peektype(hout->failmsg); + failcode = fromwire_peektype(hout->failmsg); fail = local_routing_failure(tmpctx, ld, hout, failcode, payment); @@ -782,13 +779,12 @@ static const u8 *send_onion(const tal_t *ctx, struct lightningd *ld, { const u8 *onion; unsigned int base_expiry; - bool dont_care_about_channel_update; + base_expiry = get_block_height(ld->topology) + 1; onion = serialize_onionpacket(tmpctx, packet); return send_htlc_out(ctx, channel, first_hop->amount, base_expiry + first_hop->delay, payment_hash, - blinding, partid, groupid, onion, NULL, hout, - &dont_care_about_channel_update); + blinding, partid, groupid, onion, NULL, hout); } static struct command_result *check_offer_usage(struct command *cmd, diff --git a/lightningd/pay.h b/lightningd/pay.h index 1aace68bbc99..7c933877418d 100644 --- a/lightningd/pay.h +++ b/lightningd/pay.h @@ -15,10 +15,9 @@ struct routing_failure; void payment_succeeded(struct lightningd *ld, struct htlc_out *hout, const struct preimage *rval); -/* failmsg_needs_update is if we actually wanted to temporary_channel_failure - * but we haven't got the update msg yet */ +/* hout->failmsg or hout->failonion must be set. */ void payment_failed(struct lightningd *ld, const struct htlc_out *hout, - const char *localfail, const u8 *failmsg_needs_update); + const char *localfail); /* Inform payment system to save the payment. */ void payment_store(struct lightningd *ld, struct wallet_payment *payment); diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 5914deb25829..babb126745c8 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -138,58 +138,6 @@ static void tell_channeld_htlc_failed(const struct htlc_in *hin, take(towire_channeld_fail_htlc(NULL, failed_htlc))); } -struct failmsg_update_cbdata { - struct htlc_in *hin; - const u8 *failmsg_needs_update; -}; - -static void failmsg_update_reply(struct subd *gossipd, - const u8 *msg, - const int *unused, - struct failmsg_update_cbdata *cbdata) -{ - u8 *failmsg; - u8 *stripped_update; - struct failed_htlc *failed_htlc; - - /* This can happen because channel never got properly announced.*/ - if (!fromwire_gossipd_get_stripped_cupdate_reply(msg, msg, - &stripped_update) - || !tal_count(stripped_update)) { - failmsg = towire_temporary_node_failure(NULL); - } else { - /* End of failmsg is two zero bytes (empty update). */ - assert(tal_count(cbdata->failmsg_needs_update) >= 2); - failmsg = tal_dup_arr(msg, u8, - cbdata->failmsg_needs_update, - tal_count(cbdata->failmsg_needs_update)-2, - 0); - towire_u16(&failmsg, tal_count(stripped_update)); - towire_u8_array(&failmsg, - stripped_update, tal_count(stripped_update)); - } - - /* Now we replace dummy failonion with this real one */ - tal_free(cbdata->hin->failonion); - cbdata->hin->failonion - = create_onionreply(cbdata->hin, - cbdata->hin->shared_secret, - failmsg); - - bool we_filled = false; - wallet_htlc_update(gossipd->ld->wallet, - cbdata->hin->dbid, cbdata->hin->hstate, - cbdata->hin->preimage, - max_unsigned(cbdata->hin->key.channel->next_index[LOCAL], - cbdata->hin->key.channel->next_index[REMOTE]), - cbdata->hin->badonion, - cbdata->hin->failonion, NULL, &we_filled); - - failed_htlc = mk_failed_htlc(tmpctx, - cbdata->hin, cbdata->hin->failonion); - tell_channeld_htlc_failed(cbdata->hin, failed_htlc); -} - static void fail_in_htlc(struct htlc_in *hin, const struct onionreply *failonion TAKES) { @@ -211,6 +159,15 @@ static void fail_in_htlc(struct htlc_in *hin, #endif failed_htlc = mk_failed_htlc(tmpctx, hin, hin->failonion); + bool we_filled = false; + wallet_htlc_update(hin->key.channel->peer->ld->wallet, + hin->dbid, hin->hstate, + hin->preimage, + max_unsigned(hin->key.channel->next_index[LOCAL], + hin->key.channel->next_index[REMOTE]), + hin->badonion, + hin->failonion, NULL, &we_filled); + tell_channeld_htlc_failed(hin, failed_htlc); } @@ -244,34 +201,6 @@ void local_fail_in_htlc(struct htlc_in *hin, const u8 *failmsg TAKES) fail_in_htlc(hin, take(failonion)); } -/* This is used for cases where we can immediately fail the HTLC, but - * need to append a channel_update. */ -void local_fail_in_htlc_needs_update(struct htlc_in *hin, - const u8 *failmsg_needs_update TAKES, - const struct short_channel_id *failmsg_scid) -{ - struct failmsg_update_cbdata *cbdata; - - /* To avoid the state where we have no failonion, we use a temporary - * one, and update once we get the reply from gossipd. */ - assert(!hin->preimage); - - hin->failonion = create_onionreply(hin, - hin->shared_secret, - towire_temporary_node_failure(tmpctx)); - /* We update state now to signal it's in progress, for persistence. */ - htlc_in_update_state(hin->key.channel, hin, SENT_REMOVE_HTLC); - htlc_in_check(hin, __func__); - - cbdata = tal(hin, struct failmsg_update_cbdata); - cbdata->hin = hin; - cbdata->failmsg_needs_update - = tal_dup_talarr(cbdata, u8, failmsg_needs_update); - subd_req(cbdata, hin->key.channel->peer->ld->gossip, - take(towire_gossipd_get_stripped_cupdate(NULL, failmsg_scid)), - -1, 0, failmsg_update_reply, cbdata); -} - /* Helper to create (common) WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS */ const u8 *failmsg_incorrect_or_unknown_(const tal_t *ctx, struct lightningd *ld, @@ -286,39 +215,27 @@ const u8 *failmsg_incorrect_or_unknown_(const tal_t *ctx, } /* localfail are for handing to the local payer if it's local. */ -static void fail_out_htlc(struct htlc_out *hout, - const char *localfail, - const u8 *failmsg_needs_update TAKES) +static void fail_out_htlc(struct htlc_out *hout, const char *localfail) { htlc_out_check(hout, __func__); assert(hout->failmsg || hout->failonion); if (hout->am_origin) { - payment_failed(hout->key.channel->peer->ld, hout, localfail, - failmsg_needs_update); - if (taken(failmsg_needs_update)) - tal_free(failmsg_needs_update); + payment_failed(hout->key.channel->peer->ld, hout, localfail); } else if (hout->in) { - if (failmsg_needs_update) { - local_fail_in_htlc_needs_update(hout->in, - failmsg_needs_update, - hout->key.channel->scid); - } else { - const struct onionreply *failonion; + const struct onionreply *failonion; - /* If we have an onion, simply copy it. */ - if (hout->failonion) - failonion = hout->failonion; - /* Otherwise, we need to onionize this local error. */ - else - failonion = create_onionreply(hout, - hout->in->shared_secret, - hout->failmsg); - fail_in_htlc(hout->in, failonion); - } + /* If we have an onion, simply copy it. */ + if (hout->failonion) + failonion = hout->failonion; + /* Otherwise, we need to onionize this local error. */ + else + failonion = create_onionreply(hout, + hout->in->shared_secret, + hout->failmsg); + fail_in_htlc(hout->in, failonion); } else { - if (taken(failmsg_needs_update)) - tal_free(failmsg_needs_update); + log_broken(hout->key.channel->log, "Neither origin nor in?"); } } @@ -530,8 +447,8 @@ static void destroy_hout_subd_died(struct htlc_out *hout) "Failing HTLC %"PRIu64" due to peer death", hout->key.id); - /* This isn't really used, except as sanity check */ - hout->failmsg = towire_temporary_node_failure(hout); + hout->failmsg = towire_temporary_channel_failure(hout, + get_channel_update(hout->key.channel)); /* Assign a temporary state (we're about to free it!) so checks * are happy that it has a failure message */ @@ -541,8 +458,7 @@ static void destroy_hout_subd_died(struct htlc_out *hout) if (!have_tx) db_begin_transaction(db); - fail_out_htlc(hout, "Outgoing subdaemon died", - take(towire_temporary_channel_failure(NULL, NULL))); + fail_out_htlc(hout, "Outgoing subdaemon died"); if (!have_tx) db_commit_transaction(db); @@ -573,7 +489,7 @@ static void rcvd_htlc_reply(struct subd *subd, const u8 *msg, const int *fds UNU char *localfail = tal_fmt(msg, "%s: %s", onion_wire_name(fromwire_peektype(failmsg)), failurestr); - payment_failed(ld, hout, localfail, NULL); + payment_failed(ld, hout, localfail); } else if (hout->in) { struct onionreply *failonion; @@ -644,13 +560,11 @@ const u8 *send_htlc_out(const tal_t *ctx, u64 groupid, const u8 *onion_routing_packet, struct htlc_in *in, - struct htlc_out **houtp, - bool *needs_update_appended) + struct htlc_out **houtp) { u8 *msg; *houtp = NULL; - *needs_update_appended = false; if (!channel_can_add_htlc(out)) { log_info(out->log, "Attempt to send HTLC but not ready (%s)", @@ -661,8 +575,8 @@ const u8 *send_htlc_out(const tal_t *ctx, if (!out->owner) { log_info(out->log, "Attempt to send HTLC but unowned (%s)", channel_state_name(out)); - *needs_update_appended = true; - return towire_temporary_channel_failure(ctx, NULL); + return towire_temporary_channel_failure(ctx, + get_channel_update(out)); } if (!topology_synced(out->peer->ld->topology)) { @@ -706,7 +620,6 @@ static void forward_htlc(struct htlc_in *hin, struct lightningd *ld = hin->key.channel->peer->ld; struct channel *next = active_channel_by_scid(ld, scid); struct htlc_out *hout = NULL; - bool needs_update_appended; /* Unknown peer, or peer not ready. */ if (!next || !next->scid) { @@ -732,9 +645,8 @@ static void forward_htlc(struct htlc_in *hin, || !check_fwd_amount(hin, amt_to_forward, hin->msat, next->old_feerate_base, next->old_feerate_ppm)) { - needs_update_appended = true; failmsg = towire_fee_insufficient(tmpctx, hin->msat, - NULL); + get_channel_update(next)); goto fail; } log_info(hin->key.channel->log, @@ -743,9 +655,8 @@ static void forward_htlc(struct htlc_in *hin, if (!check_cltv(hin, cltv_expiry, outgoing_cltv_value, ld->config.cltv_expiry_delta)) { - needs_update_appended = true; failmsg = towire_incorrect_cltv_expiry(tmpctx, cltv_expiry, - NULL); + get_channel_update(next)); goto fail; } @@ -763,8 +674,8 @@ static void forward_htlc(struct htlc_in *hin, "Expiry cltv %u too close to current %u", outgoing_cltv_value, get_block_height(ld->topology)); - needs_update_appended = true; - failmsg = towire_expiry_too_soon(tmpctx, NULL); + failmsg = towire_expiry_too_soon(tmpctx, + get_channel_update(next)); goto fail; } @@ -780,7 +691,6 @@ static void forward_htlc(struct htlc_in *hin, outgoing_cltv_value, get_block_height(ld->topology), ld->config.locktime_max); - needs_update_appended = false; failmsg = towire_expiry_too_far(tmpctx); goto fail; } @@ -788,15 +698,12 @@ static void forward_htlc(struct htlc_in *hin, failmsg = send_htlc_out(tmpctx, next, amt_to_forward, outgoing_cltv_value, &hin->payment_hash, next_blinding, 0 /* partid */, 0 /* groupid */, - next_onion, hin, &hout, &needs_update_appended); + next_onion, hin, &hout); if (!failmsg) return; fail: - if (needs_update_appended) - local_fail_in_htlc_needs_update(hin, failmsg, next->scid); - else - local_fail_in_htlc(hin, failmsg); + local_fail_in_htlc(hin, failmsg); wallet_forwarded_payment_add(ld->wallet, hin, next->scid, hout, FORWARD_LOCAL_FAILED, @@ -1494,7 +1401,7 @@ void onchain_failed_our_htlc(const struct channel *channel, char *localfail = tal_fmt(channel, "%s: %s", onion_wire_name(WIRE_PERMANENT_CHANNEL_FAILURE), why); - payment_failed(ld, hout, localfail, NULL); + payment_failed(ld, hout, localfail); tal_free(localfail); } else if (hout->in) { local_fail_in_htlc(hout->in, @@ -1567,7 +1474,7 @@ static void remove_htlc_out(struct channel *channel, struct htlc_out *hout) /* If it's failed, now we can forward since it's completely locked-in */ if (!hout->preimage) { - fail_out_htlc(hout, NULL, NULL); + fail_out_htlc(hout, NULL); } else { const struct channel_coin_mvt *mvt; struct amount_msat oldamt = channel->our_msat; diff --git a/lightningd/peer_htlcs.h b/lightningd/peer_htlcs.h index 50618a7499d1..8c0daf2ab764 100644 --- a/lightningd/peer_htlcs.h +++ b/lightningd/peer_htlcs.h @@ -39,7 +39,7 @@ void peer_got_revoke(struct channel *channel, const u8 *msg); void update_per_commit_point(struct channel *channel, const struct pubkey *per_commitment_point); -/* Returns NULL on success, otherwise failmsg (and sets *needs_update_appended)*/ +/* Returns NULL on success, otherwise failmsg*/ const u8 *send_htlc_out(const tal_t *ctx, struct channel *out, struct amount_msat amount, u32 cltv, @@ -49,8 +49,7 @@ const u8 *send_htlc_out(const tal_t *ctx, u64 groupid, const u8 *onion_routing_packet, struct htlc_in *in, - struct htlc_out **houtp, - bool *needs_update_appended); + struct htlc_out **houtp); void onchain_failed_our_htlc(const struct channel *channel, const struct htlc_stub *htlc, diff --git a/tests/test_pay.py b/tests/test_pay.py index 5516099d90ac..c74e65802445 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -307,7 +307,7 @@ def test_pay_get_error_with_update(node_factory): # channel_update, and it should patch it to include a type prefix. The # prefix 0x0102 should be in the channel_update, but not in the # onionreply (negation of 0x0102 in the RE) - l1.daemon.wait_for_log(r'Extracted channel_update 0102.*from onionreply 10070088[0-9a-fA-F]{88}') + l1.daemon.wait_for_log(r'Extracted channel_update 0102.*from onionreply 1007008a[0-9a-fA-F]{276}$') # And now monitor for l1 to apply the channel_update we just extracted wait_for(lambda: not l1.is_channel_active(chanid2)) @@ -1748,7 +1748,9 @@ def listpays_nofail(b11): def test_pay_routeboost(node_factory, bitcoind, compat): """Make sure we can use routeboost information. """ # l1->l2->l3--private-->l4 - l1, l2 = node_factory.line_graph(2, announce_channels=True, wait_for_announce=True) + # Note: l1 gets upset because it extracts update for private channel. + l1, l2 = node_factory.line_graph(2, announce_channels=True, wait_for_announce=True, + opts=[{'allow_bad_gossip': True}, {}]) l3, l4, l5 = node_factory.line_graph(3, announce_channels=False, wait_for_announce=False) # This should a "could not find a route" because that's true. diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 493c3fb0f511..4b18694214b3 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -131,16 +131,12 @@ bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p U /* Generated stub for fromwire_custommsg_in */ bool fromwire_custommsg_in(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **msg UNNEEDED) { fprintf(stderr, "fromwire_custommsg_in called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_get_stripped_cupdate_reply */ -bool fromwire_gossipd_get_stripped_cupdate_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **stripped_update UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_get_stripped_cupdate_reply called!\n"); abort(); } -u8 *towire_hsmd_new_channel(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 dbid UNNEEDED) -{ fprintf(stderr, "towire_hsmd_new_channel called!\n"); abort(); } -bool fromwire_hsmd_new_channel_reply(const void *p UNNEEDED) -{ fprintf(stderr, "fromwire_hsmd_new_channel_reply called!\n"); abort(); } /* Generated stub for fromwire_hsmd_get_output_scriptpubkey_reply */ bool fromwire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **script UNNEEDED) { fprintf(stderr, "fromwire_hsmd_get_output_scriptpubkey_reply called!\n"); abort(); } +/* Generated stub for fromwire_hsmd_new_channel_reply */ +bool fromwire_hsmd_new_channel_reply(const void *p UNNEEDED) +{ fprintf(stderr, "fromwire_hsmd_new_channel_reply called!\n"); abort(); } /* Generated stub for fromwire_hsmd_sign_commitment_tx_reply */ bool fromwire_hsmd_sign_commitment_tx_reply(const void *p UNNEEDED, struct bitcoin_signature *sig UNNEEDED) { fprintf(stderr, "fromwire_hsmd_sign_commitment_tx_reply called!\n"); abort(); } @@ -150,6 +146,9 @@ bool fromwire_onchaind_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNE /* Generated stub for get_block_height */ u32 get_block_height(const struct chain_topology *topo UNNEEDED) { fprintf(stderr, "get_block_height called!\n"); abort(); } +/* Generated stub for get_channel_update */ +const u8 *get_channel_update(struct channel *channel UNNEEDED) +{ fprintf(stderr, "get_channel_update called!\n"); abort(); } /* Generated stub for htlc_is_trimmed */ bool htlc_is_trimmed(enum side htlc_owner UNNEEDED, struct amount_msat htlc_amount UNNEEDED, @@ -583,7 +582,7 @@ struct onionpacket *parse_onionpacket(const tal_t *ctx UNNEEDED, { fprintf(stderr, "parse_onionpacket called!\n"); abort(); } /* Generated stub for payment_failed */ void payment_failed(struct lightningd *ld UNNEEDED, const struct htlc_out *hout UNNEEDED, - const char *localfail UNNEEDED, const u8 *failmsg_needs_update UNNEEDED) + const char *localfail UNNEEDED) { fprintf(stderr, "payment_failed called!\n"); abort(); } /* Generated stub for payment_store */ void payment_store(struct lightningd *ld UNNEEDED, struct wallet_payment *payment UNNEEDED) @@ -734,12 +733,12 @@ u8 *towire_final_incorrect_cltv_expiry(const tal_t *ctx UNNEEDED, u32 cltv_expir /* Generated stub for towire_final_incorrect_htlc_amount */ u8 *towire_final_incorrect_htlc_amount(const tal_t *ctx UNNEEDED, struct amount_msat incoming_htlc_amt UNNEEDED) { fprintf(stderr, "towire_final_incorrect_htlc_amount called!\n"); abort(); } -/* Generated stub for towire_gossipd_get_stripped_cupdate */ -u8 *towire_gossipd_get_stripped_cupdate(const tal_t *ctx UNNEEDED, const struct short_channel_id *channel_id UNNEEDED) -{ fprintf(stderr, "towire_gossipd_get_stripped_cupdate called!\n"); abort(); } /* Generated stub for towire_hsmd_get_output_scriptpubkey */ u8 *towire_hsmd_get_output_scriptpubkey(const tal_t *ctx UNNEEDED, u64 channel_id UNNEEDED, const struct node_id *peer_id UNNEEDED, const struct pubkey *commitment_point UNNEEDED) { fprintf(stderr, "towire_hsmd_get_output_scriptpubkey called!\n"); abort(); } +/* Generated stub for towire_hsmd_new_channel */ +u8 *towire_hsmd_new_channel(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 dbid UNNEEDED) +{ fprintf(stderr, "towire_hsmd_new_channel called!\n"); abort(); } /* Generated stub for towire_hsmd_sign_commitment_tx */ u8 *towire_hsmd_sign_commitment_tx(const tal_t *ctx UNNEEDED, const struct node_id *peer_id UNNEEDED, u64 channel_dbid UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const struct pubkey *remote_funding_key UNNEEDED) { fprintf(stderr, "towire_hsmd_sign_commitment_tx called!\n"); abort(); } From a668ed2d84e5205314036e7e9208fe0039829b24 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:58 +1030 Subject: [PATCH 34/51] channeld: keep local copy of latest channel_update for errors. Now we don't ask gossipd, but lightningd keeps channeld up-to-date. Signed-off-by: Rusty Russell --- channeld/channeld.c | 59 ++++++++++++++-------------- channeld/channeld_wire.csv | 10 +++++ gossipd/gossip_generation.c | 2 +- gossipd/gossip_generation.h | 3 -- gossipd/gossipd.c | 66 -------------------------------- gossipd/gossipd_peerd_wire.csv | 10 ----- gossipd/test/run-onion_message.c | 9 ----- lightningd/channel_control.c | 22 ++++++++++- lightningd/channel_control.h | 4 ++ lightningd/gossip_control.c | 4 +- 10 files changed, 69 insertions(+), 120 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 2cccbfefb32c..50796ce868c0 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -191,6 +191,9 @@ struct peer { /* We allow a 'tx-sigs' message between reconnect + funding_locked */ bool tx_sigs_allowed; + + /* Most recent channel_update message. */ + u8 *channel_update; }; static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer); @@ -414,28 +417,6 @@ static void send_channel_update(struct peer *peer, int disable_flag) wire_sync_write(peer->pps->gossip_fd, take(msg)); } -/* Get the latest channel update for this channel from gossipd */ -static const u8 *get_local_channel_update(const tal_t *ctx, struct peer *peer) -{ - const u8 *msg; - - msg = towire_gossipd_get_update(NULL, &peer->short_channel_ids[LOCAL]); - wire_sync_write(peer->pps->gossip_fd, take(msg)); - - /* Wait for reply to come back; handle other gossipd msgs meanwhile */ - while ((msg = wire_sync_read(tmpctx, peer->pps->gossip_fd)) != NULL) { - u8 *update; - if (fromwire_gossipd_get_update_reply(ctx, msg, &update)) - return update; - - handle_gossip_msg(peer->pps, take(msg)); - } - - /* Gossipd hangs up on us to kill us when a new - * connection comes in. */ - peer_failed_connection_lost(); -} - /** * Add a channel locally and send a channel update to the peer * @@ -3322,6 +3303,15 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) billboard_update(peer); } +static const u8 *get_cupdate(const struct peer *peer) +{ + /* Technically we only need to tell it the first time (unless it's + * changed). But it's not that common. */ + wire_sync_write(MASTER_FD, + take(towire_channeld_used_channel_update(NULL))); + return peer->channel_update; +} + static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) { u8 *msg; @@ -3383,7 +3373,7 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) peer->htlc_id++; return; case CHANNEL_ERR_INVALID_EXPIRY: - failwiremsg = towire_incorrect_cltv_expiry(inmsg, cltv_expiry, get_local_channel_update(tmpctx, peer)); + failwiremsg = towire_incorrect_cltv_expiry(inmsg, cltv_expiry, get_cupdate(peer)); failstr = tal_fmt(inmsg, "Invalid cltv_expiry %u", cltv_expiry); goto failed; case CHANNEL_ERR_DUPLICATE: @@ -3397,18 +3387,18 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) goto failed; /* FIXME: Fuzz the boundaries a bit to avoid probing? */ case CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED: - failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer)); + failwiremsg = towire_temporary_channel_failure(inmsg, get_cupdate(peer)); failstr = tal_fmt(inmsg, "Capacity exceeded - HTLC fee: %s", fmt_amount_sat(inmsg, htlc_fee)); goto failed; case CHANNEL_ERR_HTLC_BELOW_MINIMUM: - failwiremsg = towire_amount_below_minimum(inmsg, amount, get_local_channel_update(inmsg, peer)); + failwiremsg = towire_amount_below_minimum(inmsg, amount, get_cupdate(peer)); failstr = tal_fmt(inmsg, "HTLC too small (%s minimum)", type_to_string(tmpctx, struct amount_msat, &peer->channel->config[REMOTE].htlc_minimum)); goto failed; case CHANNEL_ERR_TOO_MANY_HTLCS: - failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer)); + failwiremsg = towire_temporary_channel_failure(inmsg, get_cupdate(peer)); failstr = "Too many HTLCs"; goto failed; case CHANNEL_ERR_DUST_FAILURE: @@ -3418,7 +3408,7 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg) * - SHOULD NOT send this HTLC * - SHOULD fail this HTLC if it's forwarded */ - failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer)); + failwiremsg = towire_temporary_channel_failure(inmsg, get_cupdate(peer)); failstr = "HTLC too dusty, allowed dust limit reached"; goto failed; } @@ -3601,6 +3591,14 @@ static void handle_shutdown_cmd(struct peer *peer, const u8 *inmsg) start_commit_timer(peer); } +/* Lightningd tells us when channel_update has changed. */ +static void handle_channel_update(struct peer *peer, const u8 *msg) +{ + peer->channel_update = tal_free(peer->channel_update); + if (!fromwire_channeld_channel_update(peer, msg, &peer->channel_update)) + master_badmsg(WIRE_CHANNELD_CHANNEL_UPDATE, msg); +} + static void handle_send_error(struct peer *peer, const u8 *msg) { char *reason; @@ -3767,6 +3765,9 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_PING: handle_send_ping(peer, msg); return; + case WIRE_CHANNELD_CHANNEL_UPDATE: + handle_channel_update(peer, msg); + return; #if DEVELOPER case WIRE_CHANNELD_DEV_REENABLE_COMMIT: handle_dev_reenable_commit(peer); @@ -3803,6 +3804,7 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_DEV_QUIESCE_REPLY: case WIRE_CHANNELD_UPGRADED: case WIRE_CHANNELD_PING_REPLY: + case WIRE_CHANNELD_USED_CHANNEL_UPDATE: break; } @@ -3908,7 +3910,8 @@ static void init_channel(struct peer *peer) &dev_fail_process_onionpacket, &dev_disable_commit, &pbases, - &reestablish_only)) { + &reestablish_only, + &peer->channel_update)) { master_badmsg(WIRE_CHANNELD_INIT, msg); } diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index f095b3cb5f61..00d9784b7616 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -77,6 +77,8 @@ msgdata,channeld_init,num_penalty_bases,u32, msgdata,channeld_init,pbases,penalty_base,num_penalty_bases msgdata,channeld_init,reestablish_only_len,u16, msgdata,channeld_init,reestablish_only,u8,reestablish_only_len +msgdata,channeld_init,channel_update_len,u16, +msgdata,channeld_init,channel_update,u8,channel_update_len # master->channeld funding hit new depth(funding locked if >= lock depth) msgtype,channeld_funding_depth,1002 @@ -224,6 +226,14 @@ msgdata,channeld_send_error,reason,wirestring, # Tell master channeld has sent the error message. msgtype,channeld_send_error_reply,1108 +# Tell channeld about the latest channel_update +msgtype,channeld_channel_update,1001 +msgdata,channeld_channel_update,len,u16, +msgdata,channeld_channel_update,msg,u8,len + +# Tell lightningd we used the latest channel_update for an error. +msgtype,channeld_used_channel_update,1102 + # Ask channeld to quiesce. msgtype,channeld_dev_quiesce,1009 msgtype,channeld_dev_quiesce_reply,1109 diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 2653f479a57b..adef74e5e262 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -598,7 +598,7 @@ static void defer_update(struct daemon *daemon, } /* If there is a pending update for this local channel, apply immediately. */ -bool local_channel_update_latest(struct daemon *daemon, struct chan *chan) +static bool local_channel_update_latest(struct daemon *daemon, struct chan *chan) { struct deferred_update *du; diff --git a/gossipd/gossip_generation.h b/gossipd/gossip_generation.h index adc3f81db51d..3d8f257aba54 100644 --- a/gossipd/gossip_generation.h +++ b/gossipd/gossip_generation.h @@ -35,9 +35,6 @@ bool nannounce_different(struct gossip_store *gs, /* Should we announce our own node? Called at strategic places. */ void maybe_send_own_node_announce(struct daemon *daemon, bool startup); -/* Flush any pending changes to this channel. */ -bool local_channel_update_latest(struct daemon *daemon, struct chan *chan); - /* Disable this local channel (lazily) */ void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction); diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 8cc2eee9e21e..a2cd9ad4e34f 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -276,65 +276,6 @@ static u8 *handle_channel_update_msg(struct peer *peer, const u8 *msg) return NULL; } -/*~ This is when channeld asks us for a channel_update for a local channel. - * It does that to fill in the error field when lightningd fails an HTLC and - * sets the UPDATE bit in the error type. lightningd is too important to - * fetch this itself, so channeld does it (channeld has to talk to us for - * other things anyway, so why not?). */ -static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg) -{ - struct short_channel_id scid; - struct chan *chan; - const u8 *update; - struct routing_state *rstate = peer->daemon->rstate; - int direction; - - if (!fromwire_gossipd_get_update(msg, &scid)) { - status_broken("peer %s sent bad gossip_get_update %s", - type_to_string(tmpctx, struct node_id, &peer->id), - tal_hex(tmpctx, msg)); - return false; - } - - /* It's possible that the channel has just closed (though v. unlikely) */ - chan = get_channel(rstate, &scid); - if (!chan) { - status_unusual("peer %s scid %s: unknown channel", - type_to_string(tmpctx, struct node_id, &peer->id), - type_to_string(tmpctx, struct short_channel_id, - &scid)); - update = NULL; - goto out; - } - - /* Since we're going to send it out, make sure it's up-to-date. */ - local_channel_update_latest(peer->daemon, chan); - - if (!local_direction(rstate, chan, &direction)) { - status_peer_broken(&peer->id, "Chan %s is not local?", - type_to_string(tmpctx, struct short_channel_id, - &scid)); - update = NULL; - goto out; - } - - /* It's possible this is zero, if we've never sent a channel_update - * for that channel. */ - if (!is_halfchan_defined(&chan->half[direction])) - update = NULL; - else - update = gossip_store_get(tmpctx, rstate->gs, - chan->half[direction].bcast.index); -out: - status_peer_debug(&peer->id, "schanid %s: %s update", - type_to_string(tmpctx, struct short_channel_id, &scid), - update ? "got" : "no"); - - msg = towire_gossipd_get_update_reply(NULL, update); - daemon_conn_send(peer->dc, take(msg)); - return true; -} - static u8 *handle_node_announce(struct peer *peer, const u8 *msg) { bool was_unknown = false; @@ -780,19 +721,12 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, /* Must be a gossipd_peerd_wire_type asking us to do something. */ switch ((enum gossipd_peerd_wire)fromwire_peektype(msg)) { - case WIRE_GOSSIPD_GET_UPDATE: - ok = handle_get_local_channel_update(peer, msg); - goto handled_cmd; case WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE: ok = handle_local_channel_update(peer->daemon, &peer->id, msg); goto handled_cmd; case WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT: ok = handle_local_channel_announcement(peer->daemon, peer, msg); goto handled_cmd; - - /* These are the ones we send, not them */ - case WIRE_GOSSIPD_GET_UPDATE_REPLY: - break; } if (fromwire_peektype(msg) == WIRE_GOSSIP_STORE_PRIVATE_CHANNEL) { diff --git a/gossipd/gossipd_peerd_wire.csv b/gossipd/gossipd_peerd_wire.csv index 10c48adeaf89..9b86cbf27cc8 100644 --- a/gossipd/gossipd_peerd_wire.csv +++ b/gossipd/gossipd_peerd_wire.csv @@ -2,16 +2,6 @@ #include #include -# Channel daemon can ask for updates for a specific channel, for sending -# errors. -msgtype,gossipd_get_update,3501 -msgdata,gossipd_get_update,short_channel_id,short_channel_id, - -# If channel isn't known, update will be empty. -msgtype,gossipd_get_update_reply,3601 -msgdata,gossipd_get_update_reply,len,u16, -msgdata,gossipd_get_update_reply,update,u8,len - # Send this channel_update. msgtype,gossipd_local_channel_update,3504 msgdata,gossipd_local_channel_update,short_channel_id,short_channel_id, diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 7eff11f33491..0cefa469b1c5 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -88,9 +88,6 @@ bool fromwire_gossipd_get_addrs(const void *p UNNEEDED, struct node_id *id UNNEE /* Generated stub for fromwire_gossipd_get_txout_reply */ bool fromwire_gossipd_get_txout_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct amount_sat *satoshis UNNEEDED, u8 **outscript UNNEEDED) { fprintf(stderr, "fromwire_gossipd_get_txout_reply called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_get_update */ -bool fromwire_gossipd_get_update(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_get_update called!\n"); abort(); } /* Generated stub for fromwire_gossipd_init */ bool fromwire_gossipd_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct feature_set **our_features UNNEEDED, struct node_id *id UNNEEDED, u8 rgb[3] UNNEEDED, u8 alias[32] UNNEEDED, struct wireaddr **announcable UNNEEDED, u32 **dev_gossip_time UNNEEDED, bool *dev_fast_gossip UNNEEDED, bool *dev_fast_gossip_prune UNNEEDED) { fprintf(stderr, "fromwire_gossipd_init called!\n"); abort(); } @@ -199,9 +196,6 @@ void json_object_end(struct json_stream *js UNNEEDED) /* Generated stub for json_object_start */ void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) { fprintf(stderr, "json_object_start called!\n"); abort(); } -/* Generated stub for local_channel_update_latest */ -bool local_channel_update_latest(struct daemon *daemon UNNEEDED, struct chan *chan UNNEEDED) -{ fprintf(stderr, "local_channel_update_latest called!\n"); abort(); } /* Generated stub for local_disable_chan */ void local_disable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) { fprintf(stderr, "local_disable_chan called!\n"); abort(); } @@ -323,9 +317,6 @@ u8 *towire_gossipd_get_addrs_reply(const tal_t *ctx UNNEEDED, const struct wirea /* Generated stub for towire_gossipd_get_txout */ u8 *towire_gossipd_get_txout(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED) { fprintf(stderr, "towire_gossipd_get_txout called!\n"); abort(); } -/* Generated stub for towire_gossipd_get_update_reply */ -u8 *towire_gossipd_get_update_reply(const tal_t *ctx UNNEEDED, const u8 *update UNNEEDED) -{ fprintf(stderr, "towire_gossipd_get_update_reply called!\n"); abort(); } /* Generated stub for towire_gossipd_got_onionmsg_to_us */ u8 *towire_gossipd_got_onionmsg_to_us(const tal_t *ctx UNNEEDED, bool obs2 UNNEEDED, const struct pubkey *node_alias UNNEEDED, const struct secret *self_id UNNEEDED, const struct pubkey *reply_blinding UNNEEDED, const struct pubkey *reply_first_node UNNEEDED, const struct onionmsg_path **reply_path UNNEEDED, const u8 *rawmsg UNNEEDED) { fprintf(stderr, "towire_gossipd_got_onionmsg_to_us called!\n"); abort(); } diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 04fb24d25761..91efa1200d7e 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -493,6 +493,10 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_PING_REPLY: ping_reply(sd, msg); break; + case WIRE_CHANNELD_USED_CHANNEL_UPDATE: + /* This tells gossipd we used it. */ + get_channel_update(sd->channel); + break; #if EXPERIMENTAL_FEATURES case WIRE_CHANNELD_UPGRADED: handle_channel_upgrade(sd->channel, msg); @@ -514,6 +518,7 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_FEERATES: case WIRE_CHANNELD_BLOCKHEIGHT: case WIRE_CHANNELD_SPECIFIC_FEERATES: + case WIRE_CHANNELD_CHANNEL_UPDATE: case WIRE_CHANNELD_DEV_MEMLEAK: case WIRE_CHANNELD_DEV_QUIESCE: /* Replies go to requests. */ @@ -706,7 +711,8 @@ void peer_start_channeld(struct channel *channel, : (u32 *)&ld->dev_disable_commit, NULL), pbases, - reestablish_only); + reestablish_only, + channel->channel_update); /* We don't expect a response: we are triggered by funding_depth_cb. */ subd_send_msg(channel->owner, take(initmsg)); @@ -997,6 +1003,20 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd, return command_still_pending(cmd); } +void channel_replace_update(struct channel *channel, u8 *update TAKES) +{ + tal_free(channel->channel_update); + channel->channel_update = tal_dup_talarr(channel, u8, update); + + /* Keep channeld up-to-date */ + if (!channel->owner || !streq(channel->owner->name, "channeld")) + return; + + subd_send_msg(channel->owner, + take(towire_channeld_channel_update(NULL, + channel->channel_update))); +} + #if DEVELOPER static struct command_result *json_dev_feerate(struct command *cmd, const char *buffer, diff --git a/lightningd/channel_control.h b/lightningd/channel_control.h index ac5a1b88db03..0cb05b7296b9 100644 --- a/lightningd/channel_control.h +++ b/lightningd/channel_control.h @@ -38,4 +38,8 @@ void channel_record_open(struct channel *channel); /* A channel has unrecoverably fallen behind */ void channel_fallen_behind(struct channel *channel, const u8 *msg); + +/* Fresh channel_update for this channel. */ +void channel_replace_update(struct channel *channel, u8 *update TAKES); + #endif /* LIGHTNING_LIGHTNINGD_CHANNEL_CONTROL_H */ diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 9879599db2fd..57acc86ca99f 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -130,8 +131,7 @@ static void handle_local_channel_update(struct lightningd *ld, const u8 *msg) return; } - tal_free(channel->channel_update); - channel->channel_update = tal_steal(channel, update); + channel_replace_update(channel, take(update)); } const u8 *get_channel_update(struct channel *channel) From ae5efefad419cdff40ff3c80c8b9e438ca588469 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 35/51] pytest: fix unlikely flake This only happened once, but it's possible if the node gets the new node announcement while we're querying, we could see both old and new. ``` # Get node_announcements. msgs = l1.query_gossip('gossip_timestamp_filter', genesis_blockhash, '0', '0xFFFFFFFF', # Filter out gossip_timestamp_filter, # channel_announcement and channel_updates. filters=['0109', '0102', '0100']) > assert len(msgs) == 2 E assert 3 == 2 E +3 E -2 ``` Signed-off-by: Rusty Russell --- connectd/multiplex.c | 9 +++++++-- tests/test_gossip.py | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 30c2d1088202..c177effcc21a 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -108,6 +108,8 @@ void setup_peer_gossip_store(struct peer *peer, * unless explicitly requested. */ if (feature_negotiated(our_features, their_features, OPT_GOSSIP_QUERIES)) { + status_peer_debug(&peer->id, "gossip_store: deferring"); + peer->gs.gossip_timer = NULL; peer->gs.active = false; peer->gs.off = 1; @@ -130,14 +132,17 @@ void setup_peer_gossip_store(struct peer *peer, * - SHOULD resume normal operation, as specified in the * following [Rebroadcasting](#rebroadcasting) section. */ - if (feature_offered(their_features, OPT_INITIAL_ROUTING_SYNC)) + if (feature_offered(their_features, OPT_INITIAL_ROUTING_SYNC)) { + status_peer_debug(&peer->id, "gossip_store: initial_routing_sync"); peer->gs.off = 1; - else { + } else { /* During tests, particularly, we find that the gossip_store * moves fast, so make sure it really does start at the end. */ peer->gs.off = find_gossip_store_end(peer->daemon->gossip_store_fd, peer->daemon->gossip_store_end); + status_peer_debug(&peer->id, "gossip_store: off = %zu", + peer->gs.off); } } diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 03312913a8c5..245666b1b689 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1261,6 +1261,7 @@ def test_node_reannounce(node_factory, bitcoind, chainparams): l1.start() wait_for(lambda: only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['alias'] == 'SENIORBEAM') + wait_for(lambda: only_one(l1.rpc.listnodes(l1.info['id'])['nodes'])['alias'] == 'SENIORBEAM') # Get node_announcements. msgs = l1.query_gossip('gossip_timestamp_filter', @@ -1270,6 +1271,7 @@ def test_node_reannounce(node_factory, bitcoind, chainparams): # channel_announcement and channel_updates. filters=['0109', '0102', '0100']) + print("\n\n\n***{}\n\n\n".format(msgs)) assert len(msgs) == 2 assert (bytes("SENIORBEAM", encoding="utf8").hex() in msgs[0] or bytes("SENIORBEAM", encoding="utf8").hex() in msgs[1]) From d336fa7d3dc75c9ef982d1541c6e587cf9bbd08b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 36/51] channeld: send channel updates and announcements via lightningd. We're weaning per-peer daemons off having a direct gossipd connection. Signed-off-by: Rusty Russell --- channeld/channeld.c | 34 ++++--- channeld/channeld_wire.csv | 21 ++++ gossipd/gossip_generation.c | 29 +++--- gossipd/gossip_generation.h | 6 +- gossipd/gossip_store.c | 15 ++- gossipd/gossipd.c | 95 +++++++++++-------- gossipd/gossipd_peerd_wire.csv | 14 --- gossipd/gossipd_wire.csv | 26 +++++ gossipd/routing.c | 58 +++++++---- gossipd/routing.h | 5 +- gossipd/test/run-check_channel_announcement.c | 4 + gossipd/test/run-check_node_announcement.c | 2 +- gossipd/test/run-crc32_of_update.c | 2 +- gossipd/test/run-onion_message.c | 24 +++-- gossipd/test/run-txout_failure.c | 4 + lightningd/channel_control.c | 27 ++++++ lightningd/gossip_control.c | 83 ++++++++++++++++ lightningd/gossip_control.h | 13 +++ 18 files changed, 335 insertions(+), 127 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 50796ce868c0..71fd7c2326e1 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -392,7 +392,9 @@ static void maybe_send_stfu(struct peer *peer) } #endif -/* Create and send channel_update to gossipd (and maybe peer) */ +/* Tell gossipd to create channel_update (then it goes into + * gossip_store, then streams out to peers, or sends it directly if + * it's a private channel) */ static void send_channel_update(struct peer *peer, int disable_flag) { u8 *msg; @@ -405,7 +407,7 @@ static void send_channel_update(struct peer *peer, int disable_flag) assert(peer->short_channel_ids[LOCAL].u64); - msg = towire_gossipd_local_channel_update(NULL, + msg = towire_channeld_local_channel_update(NULL, &peer->short_channel_ids[LOCAL], disable_flag == ROUTING_FLAGS_DISABLED, @@ -414,7 +416,7 @@ static void send_channel_update(struct peer *peer, int disable_flag) peer->fee_base, peer->fee_per_satoshi, advertized_htlc_max(peer->channel)); - wire_sync_write(peer->pps->gossip_fd, take(msg)); + wire_sync_write(MASTER_FD, take(msg)); } /** @@ -430,22 +432,15 @@ static void send_channel_update(struct peer *peer, int disable_flag) static void make_channel_local_active(struct peer *peer) { u8 *msg; - const u8 *ann; const u8 *annfeatures = get_agreed_channelfeatures(tmpctx, peer->our_features, peer->their_features); - ann = private_channel_announcement(tmpctx, - &peer->short_channel_ids[LOCAL], - &peer->node_ids[LOCAL], - &peer->node_ids[REMOTE], - annfeatures); - - /* Tell gossipd about local channel. */ - msg = towire_gossip_store_private_channel(NULL, - peer->channel->funding_sats, - ann); - wire_sync_write(peer->pps->gossip_fd, take(msg)); + /* Tell lightningd to tell gossipd about local channel. */ + msg = towire_channeld_local_private_channel(NULL, + peer->channel->funding_sats, + annfeatures); + wire_sync_write(MASTER_FD, take(msg)); /* Tell gossipd and the other side what parameters we expect should * they route through us */ @@ -560,9 +555,9 @@ static void announce_channel(struct peer *peer) cannounce = create_channel_announcement(tmpctx, peer); - wire_sync_write(peer->pps->gossip_fd, - take(towire_gossipd_local_channel_announcement(NULL, - cannounce))); + wire_sync_write(MASTER_FD, + take(towire_channeld_local_channel_announcement(NULL, + cannounce))); send_channel_update(peer, 0); } @@ -3805,6 +3800,9 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_UPGRADED: case WIRE_CHANNELD_PING_REPLY: case WIRE_CHANNELD_USED_CHANNEL_UPDATE: + case WIRE_CHANNELD_LOCAL_CHANNEL_UPDATE: + case WIRE_CHANNELD_LOCAL_CHANNEL_ANNOUNCEMENT: + case WIRE_CHANNELD_LOCAL_PRIVATE_CHANNEL: break; } diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index 00d9784b7616..4770aea3d542 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -234,6 +234,27 @@ msgdata,channeld_channel_update,msg,u8,len # Tell lightningd we used the latest channel_update for an error. msgtype,channeld_used_channel_update,1102 +# Channeld: tell gossipd to make this channel_update. +msgtype,channeld_local_channel_update,1013 +msgdata,channeld_local_channel_update,short_channel_id,short_channel_id, +msgdata,channeld_local_channel_update,disable,bool, +msgdata,channeld_local_channel_update,cltv_expiry_delta,u16, +msgdata,channeld_local_channel_update,htlc_minimum_msat,amount_msat, +msgdata,channeld_local_channel_update,fee_base_msat,u32, +msgdata,channeld_local_channel_update,fee_proportional_millionths,u32, +msgdata,channeld_local_channel_update,htlc_maximum_msat,amount_msat, + +# Channeld: tell gossipd about our channel_announcement +msgtype,channeld_local_channel_announcement,1014 +msgdata,channeld_local_channel_announcement,len,u16, +msgdata,channeld_local_channel_announcement,cannounce,u8,len + +# Channeld: tell gossipd about this (as-yet) unannounced channel +msgtype,channeld_local_private_channel,1015 +msgdata,channeld_local_private_channel,capacity,amount_sat, +msgdata,channeld_local_private_channel,len,u16, +msgdata,channeld_local_private_channel,features,u8,len + # Ask channeld to quiesce. msgtype,channeld_dev_quiesce,1009 msgtype,channeld_dev_quiesce_reply,1109 diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index adef74e5e262..faf01bb7254f 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -695,11 +694,10 @@ void refresh_local_channel(struct daemon *daemon, sign_timestamp_and_apply_update(daemon, chan, direction, take(update)); } -/* channeld asks us to update the local channel. */ -bool handle_local_channel_update(struct daemon *daemon, - const struct node_id *src, - const u8 *msg) +/* channeld (via lightningd) asks us to update the local channel. */ +void handle_local_channel_update(struct daemon *daemon, const u8 *msg) { + struct node_id id; struct short_channel_id scid; bool disable; u16 cltv_expiry_delta; @@ -710,10 +708,8 @@ bool handle_local_channel_update(struct daemon *daemon, u8 *unsigned_update; const struct half_chan *hc; - /* FIXME: We should get scid from lightningd when setting up the - * connection, so no per-peer daemon can mess with channels other than - * its own! */ if (!fromwire_gossipd_local_channel_update(msg, + &id, &scid, &disable, &cltv_expiry_delta, @@ -721,26 +717,24 @@ bool handle_local_channel_update(struct daemon *daemon, &fee_base_msat, &fee_proportional_millionths, &htlc_maximum)) { - status_peer_broken(src, "bad local_channel_update %s", - tal_hex(tmpctx, msg)); - return false; + master_badmsg(WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE, msg); } chan = get_channel(daemon->rstate, &scid); /* Can theoretically happen if channel just closed. */ if (!chan) { - status_peer_debug(src, "local_channel_update for unknown %s", + status_peer_debug(&id, "local_channel_update for unknown %s", type_to_string(tmpctx, struct short_channel_id, &scid)); - return true; + return; } if (!local_direction(daemon->rstate, chan, &direction)) { - status_peer_broken(src, "bad local_channel_update chan %s", + status_peer_broken(&id, "bad local_channel_update chan %s", type_to_string(tmpctx, struct short_channel_id, &scid)); - return false; + return; } unsigned_update = create_unsigned_update(tmpctx, &scid, direction, @@ -754,7 +748,7 @@ bool handle_local_channel_update(struct daemon *daemon, /* Ignore duplicates. */ if (is_halfchan_defined(hc) && !cupdate_different(daemon->rstate->gs, hc, unsigned_update)) - return true; + return; /* Too early? Defer (don't worry if it's unannounced). */ if (hc && is_chan_public(chan)) { @@ -764,13 +758,12 @@ bool handle_local_channel_update(struct daemon *daemon, if (now < next_time) { defer_update(daemon, next_time - now, chan, direction, take(unsigned_update)); - return true; + return; } } sign_timestamp_and_apply_update(daemon, chan, direction, take(unsigned_update)); - return true; } /* Take update, set/unset disabled flag (and update timestamp). diff --git a/gossipd/gossip_generation.h b/gossipd/gossip_generation.h index 3d8f257aba54..b39cc158b47f 100644 --- a/gossipd/gossip_generation.h +++ b/gossipd/gossip_generation.h @@ -45,10 +45,8 @@ void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direc void refresh_local_channel(struct daemon *daemon, struct chan *chan, int direction); -/* channeld asks us to update the local channel. */ -bool handle_local_channel_update(struct daemon *daemon, - const struct node_id *src, - const u8 *msg); +/* channeld (via lightningd) asks us to update the local channel. */ +void handle_local_channel_update(struct daemon *daemon, const u8 *msg); /* lightningd tells us it used the last channel_update we sent. */ void handle_used_local_channel_update(struct daemon *daemon, const u8 *msg); diff --git a/gossipd/gossip_store.c b/gossipd/gossip_store.c index 408e79adfd36..f06c5a876678 100644 --- a/gossipd/gossip_store.c +++ b/gossipd/gossip_store.c @@ -782,14 +782,25 @@ u32 gossip_store_load(struct routing_state *rstate, struct gossip_store *gs) } switch (fromwire_peektype(msg)) { - case WIRE_GOSSIP_STORE_PRIVATE_CHANNEL: - if (!routing_add_private_channel(rstate, NULL, msg, + case WIRE_GOSSIP_STORE_PRIVATE_CHANNEL: { + u8 *chan_ann; + struct amount_sat sat; + if (!fromwire_gossip_store_private_channel(msg, msg, + &sat, + &chan_ann)) { + bad = "Bad private_channel"; + goto badmsg; + } + + if (!routing_add_private_channel(rstate, NULL, + sat, chan_ann, gs->len)) { bad = "Bad add_private_channel"; goto badmsg; } stats[0]++; break; + } case WIRE_GOSSIP_STORE_CHANNEL_AMOUNT: if (!fromwire_gossip_store_channel_amount(msg, &satoshis)) { diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index a2cd9ad4e34f..e14482372e1f 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -288,31 +289,60 @@ static u8 *handle_node_announce(struct peer *peer, const u8 *msg) return err; } -static bool handle_local_channel_announcement(struct daemon *daemon, - struct peer *peer, - const u8 *msg) +static void handle_local_channel_announcement(struct daemon *daemon, const u8 *msg) { u8 *cannouncement; const u8 *err; + struct node_id id; + struct peer *peer; if (!fromwire_gossipd_local_channel_announcement(msg, msg, - &cannouncement)) { - status_broken("peer %s bad local_channel_announcement %s", - type_to_string(tmpctx, struct node_id, &peer->id), - tal_hex(tmpctx, msg)); - return false; - } + &id, + &cannouncement)) + master_badmsg(WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT, msg); + + /* We treat it OK even if peer has disconnected since (unlikely though!) */ + peer = find_peer(daemon, &id); + if (!peer) + status_broken("Unknown peer %s for local_channel_announcement", + type_to_string(tmpctx, struct node_id, &id)); err = handle_channel_announcement_msg(daemon, peer, cannouncement); if (err) { status_broken("peer %s invalid local_channel_announcement %s (%s)", - type_to_string(tmpctx, struct node_id, &peer->id), + type_to_string(tmpctx, struct node_id, &id), tal_hex(tmpctx, msg), tal_hex(tmpctx, err)); - return false; } +} - return true; + +/* channeld (via lightningd) tells us about (as-yet?) unannounce channel. + * It needs us to put it in gossip_store. */ +static void handle_local_private_channel(struct daemon *daemon, const u8 *msg) +{ + struct node_id id; + struct amount_sat capacity; + u8 *features; + struct short_channel_id scid; + const u8 *cannounce; + + if (!fromwire_gossipd_local_private_channel(msg, msg, + &id, &capacity, &scid, + &features)) + master_badmsg(WIRE_GOSSIPD_LOCAL_PRIVATE_CHANNEL, msg); + + cannounce = private_channel_announcement(tmpctx, + &scid, + &daemon->id, + &id, + features); + + if (!routing_add_private_channel(daemon->rstate, &id, capacity, + cannounce, 0)) { + status_peer_broken(&id, "bad add_private_channel %s", + tal_hex(tmpctx, cannounce)); + } } /* Peer sends obsolete onion msg. */ @@ -644,7 +674,6 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, struct peer *peer) { const u8 *err; - bool ok; /* These are messages relayed from peer */ switch ((enum peer_wire)fromwire_peektype(msg)) { @@ -719,40 +748,17 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, return io_close(conn); } - /* Must be a gossipd_peerd_wire_type asking us to do something. */ - switch ((enum gossipd_peerd_wire)fromwire_peektype(msg)) { - case WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE: - ok = handle_local_channel_update(peer->daemon, &peer->id, msg); - goto handled_cmd; - case WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT: - ok = handle_local_channel_announcement(peer->daemon, peer, msg); - goto handled_cmd; - } - - if (fromwire_peektype(msg) == WIRE_GOSSIP_STORE_PRIVATE_CHANNEL) { - ok = routing_add_private_channel(peer->daemon->rstate, peer, - msg, 0); - goto handled_cmd; - } - /* Anything else should not have been sent to us: close on it */ - status_peer_broken(&peer->id, "unexpected cmd of type %i %s", - fromwire_peektype(msg), - gossipd_peerd_wire_name(fromwire_peektype(msg))); + status_peer_broken(&peer->id, "unexpected cmd of type %i", + fromwire_peektype(msg)); return io_close(conn); - /* Commands should always be OK. */ -handled_cmd: - if (!ok) - return io_close(conn); - goto done; - /* Forwarded messages may be bad, so we have error which the per-peer * daemon will forward to the peer. */ handled_relay: if (err) queue_peer_msg(peer, take(err)); -done: + return daemon_conn_read_next(conn, peer->dc); } @@ -1293,6 +1299,17 @@ static struct io_plan *recv_req(struct io_conn *conn, handle_used_local_channel_update(daemon, msg); goto done; + case WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE: + handle_local_channel_update(daemon, msg); + goto done; + + case WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT: + handle_local_channel_announcement(daemon, msg); + goto done; + + case WIRE_GOSSIPD_LOCAL_PRIVATE_CHANNEL: + handle_local_private_channel(daemon, msg); + goto done; #if DEVELOPER case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE: dev_set_max_scids_encode_size(daemon, msg); diff --git a/gossipd/gossipd_peerd_wire.csv b/gossipd/gossipd_peerd_wire.csv index 9b86cbf27cc8..282712beb4bc 100644 --- a/gossipd/gossipd_peerd_wire.csv +++ b/gossipd/gossipd_peerd_wire.csv @@ -2,17 +2,3 @@ #include #include -# Send this channel_update. -msgtype,gossipd_local_channel_update,3504 -msgdata,gossipd_local_channel_update,short_channel_id,short_channel_id, -msgdata,gossipd_local_channel_update,disable,bool, -msgdata,gossipd_local_channel_update,cltv_expiry_delta,u16, -msgdata,gossipd_local_channel_update,htlc_minimum_msat,amount_msat, -msgdata,gossipd_local_channel_update,fee_base_msat,u32, -msgdata,gossipd_local_channel_update,fee_proportional_millionths,u32, -msgdata,gossipd_local_channel_update,htlc_maximum_msat,amount_msat, - -# Send this channel_announcement -msgtype,gossipd_local_channel_announcement,3506 -msgdata,gossipd_local_channel_announcement,len,u16, -msgdata,gossipd_local_channel_announcement,cannount,u8,len diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index 8e41cd3b13ba..3c2f1cf9ca40 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -112,6 +112,32 @@ msgdata,gossipd_got_local_channel_update,scid,short_channel_id, msgdata,gossipd_got_local_channel_update,len,u16, msgdata,gossipd_got_local_channel_update,channel_update,u8,len +# Send this channel_update. +msgtype,gossipd_local_channel_update,3004 +msgdata,gossipd_local_channel_update,id,node_id, +msgdata,gossipd_local_channel_update,short_channel_id,short_channel_id, +msgdata,gossipd_local_channel_update,disable,bool, +msgdata,gossipd_local_channel_update,cltv_expiry_delta,u16, +msgdata,gossipd_local_channel_update,htlc_minimum_msat,amount_msat, +msgdata,gossipd_local_channel_update,fee_base_msat,u32, +msgdata,gossipd_local_channel_update,fee_proportional_millionths,u32, +msgdata,gossipd_local_channel_update,htlc_maximum_msat,amount_msat, + +# Send this channel_announcement +msgtype,gossipd_local_channel_announcement,3006 +msgdata,gossipd_local_channel_announcement,id,node_id, +msgdata,gossipd_local_channel_announcement,len,u16, +msgdata,gossipd_local_channel_announcement,cannounce,u8,len + +# Tell gossipd about a private channel (to put it in the store) +# cannounce has same structure, dummy sigs. +msgtype,gossipd_local_private_channel,3008 +msgdata,gossipd_local_private_channel,id,node_id, +msgdata,gossipd_local_private_channel,capacity,amount_sat, +msgdata,gossipd_local_private_channel,scid,short_channel_id, +msgdata,gossipd_local_private_channel,len,u16, +msgdata,gossipd_local_private_channel,features,u8,len + # Tell gossipd we used the channel update (in case it was deferred) msgtype,gossipd_used_local_channel_update,3052 msgdata,gossipd_used_local_channel_update,scid,short_channel_id, diff --git a/gossipd/routing.c b/gossipd/routing.c index 58b1d5c789b8..947ab0e86b08 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -1821,23 +1821,18 @@ void route_prune(struct routing_state *rstate) } bool routing_add_private_channel(struct routing_state *rstate, - const struct peer *peer, - const u8 *msg, u64 index) + const struct node_id *id, + struct amount_sat capacity, + const u8 *chan_ann, u64 index) { struct short_channel_id scid; struct node_id node_id[2]; struct pubkey ignorekey; - struct amount_sat sat; struct chan *chan; - u8 *features, *chan_ann; + u8 *features; secp256k1_ecdsa_signature ignoresig; struct bitcoin_blkid chain_hash; - if (!fromwire_gossip_store_private_channel(tmpctx, msg, - &sat, &chan_ann)) - return false; - - if (!fromwire_channel_announcement(tmpctx, chan_ann, &ignoresig, &ignoresig, @@ -1852,21 +1847,46 @@ bool routing_add_private_channel(struct routing_state *rstate, &ignorekey)) return false; - /* Can happen on channeld restart. */ - if (get_channel(rstate, &scid)) { - status_peer_debug(peer ? &peer->id : NULL, - "Attempted to local_add_channel a known channel"); + /* Happens on channeld restart. */ + if (get_channel(rstate, &scid)) return true; - } - status_peer_debug(peer ? &peer->id : NULL, - "local_add_channel %s", - type_to_string(tmpctx, struct short_channel_id, &scid)); + /* Make sure this id (if any) was allowed to create this */ + if (id) { + struct node_id expected[2]; + int cmp = node_id_cmp(&rstate->local_id, id); + + if (cmp < 0) { + expected[0] = rstate->local_id; + expected[1] = *id; + } else if (cmp > 0) { + expected[0] = *id; + expected[1] = rstate->local_id; + } else { + /* lightningd sets id, so this is fatal */ + status_failed(STATUS_FAIL_MASTER_IO, + "private_channel peer was us?"); + } + + if (!node_id_eq(&node_id[0], &expected[0]) + || !node_id_eq(&node_id[1], &expected[1])) { + status_peer_broken(id, "private channel %s<->%s invalid", + type_to_string(tmpctx, struct node_id, + &node_id[0]), + type_to_string(tmpctx, struct node_id, + &node_id[1])); + return false; + } + } /* Create new (unannounced) channel */ - chan = new_chan(rstate, &scid, &node_id[0], &node_id[1], sat); - if (!index) + chan = new_chan(rstate, &scid, &node_id[0], &node_id[1], capacity); + if (!index) { + u8 *msg = towire_gossip_store_private_channel(tmpctx, + capacity, + chan_ann); index = gossip_store_add(rstate->gs, msg, 0, false, NULL); + } chan->bcast.index = index; return true; } diff --git a/gossipd/routing.h b/gossipd/routing.h index e33d6306116b..1641284bb667 100644 --- a/gossipd/routing.h +++ b/gossipd/routing.h @@ -378,8 +378,9 @@ bool routing_add_node_announcement(struct routing_state *rstate, * `announce_depth`. */ bool routing_add_private_channel(struct routing_state *rstate, - const struct peer *peer, - const u8 *msg, u64 index); + const struct node_id *id, + struct amount_sat sat, + const u8 *chan_ann, u64 index); /** * Get the local time. diff --git a/gossipd/test/run-check_channel_announcement.c b/gossipd/test/run-check_channel_announcement.c index 28b29a341031..827bbdd63ebd 100644 --- a/gossipd/test/run-check_channel_announcement.c +++ b/gossipd/test/run-check_channel_announcement.c @@ -144,6 +144,10 @@ void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) /* Generated stub for peer_supplied_good_gossip */ void peer_supplied_good_gossip(struct peer *peer UNNEEDED, size_t amount UNNEEDED) { fprintf(stderr, "peer_supplied_good_gossip called!\n"); abort(); } +/* Generated stub for status_failed */ +void status_failed(enum status_failreason code UNNEEDED, + const char *fmt UNNEEDED, ...) +{ fprintf(stderr, "status_failed called!\n"); abort(); } /* Generated stub for status_fmt */ void status_fmt(enum log_level level UNNEEDED, const struct node_id *peer UNNEEDED, diff --git a/gossipd/test/run-check_node_announcement.c b/gossipd/test/run-check_node_announcement.c index 4104556fade7..25fcdda7abd2 100644 --- a/gossipd/test/run-check_node_announcement.c +++ b/gossipd/test/run-check_node_announcement.c @@ -37,7 +37,7 @@ struct peer *find_peer(struct daemon *daemon UNNEEDED, const struct node_id *id char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED) { fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); } /* Generated stub for fromwire_gossipd_local_channel_update */ -bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *disable UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, struct amount_msat *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, struct amount_msat *htlc_maximum_msat UNNEEDED) +bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct node_id *id UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *disable UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, struct amount_msat *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, struct amount_msat *htlc_maximum_msat UNNEEDED) { fprintf(stderr, "fromwire_gossipd_local_channel_update called!\n"); abort(); } /* Generated stub for fromwire_gossipd_used_local_channel_update */ bool fromwire_gossipd_used_local_channel_update(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED) diff --git a/gossipd/test/run-crc32_of_update.c b/gossipd/test/run-crc32_of_update.c index 7d9b64037473..47a1250a35c9 100644 --- a/gossipd/test/run-crc32_of_update.c +++ b/gossipd/test/run-crc32_of_update.c @@ -58,7 +58,7 @@ char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr bool fromwire_gossipd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED) { fprintf(stderr, "fromwire_gossipd_dev_set_max_scids_encode_size called!\n"); abort(); } /* Generated stub for fromwire_gossipd_local_channel_update */ -bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *disable UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, struct amount_msat *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, struct amount_msat *htlc_maximum_msat UNNEEDED) +bool fromwire_gossipd_local_channel_update(const void *p UNNEEDED, struct node_id *id UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, bool *disable UNNEEDED, u16 *cltv_expiry_delta UNNEEDED, struct amount_msat *htlc_minimum_msat UNNEEDED, u32 *fee_base_msat UNNEEDED, u32 *fee_proportional_millionths UNNEEDED, struct amount_msat *htlc_maximum_msat UNNEEDED) { fprintf(stderr, "fromwire_gossipd_local_channel_update called!\n"); abort(); } /* Generated stub for fromwire_gossipd_used_local_channel_update */ bool fromwire_gossipd_used_local_channel_update(const void *p UNNEEDED, struct short_channel_id *scid UNNEEDED) diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 0cefa469b1c5..91afcd4528dd 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -92,11 +92,14 @@ bool fromwire_gossipd_get_txout_reply(const tal_t *ctx UNNEEDED, const void *p U bool fromwire_gossipd_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct feature_set **our_features UNNEEDED, struct node_id *id UNNEEDED, u8 rgb[3] UNNEEDED, u8 alias[32] UNNEEDED, struct wireaddr **announcable UNNEEDED, u32 **dev_gossip_time UNNEEDED, bool *dev_fast_gossip UNNEEDED, bool *dev_fast_gossip_prune UNNEEDED) { fprintf(stderr, "fromwire_gossipd_init called!\n"); abort(); } /* Generated stub for fromwire_gossipd_local_channel_announcement */ -bool fromwire_gossipd_local_channel_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **cannount UNNEEDED) +bool fromwire_gossipd_local_channel_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u8 **cannounce UNNEEDED) { fprintf(stderr, "fromwire_gossipd_local_channel_announcement called!\n"); abort(); } /* Generated stub for fromwire_gossipd_local_channel_close */ bool fromwire_gossipd_local_channel_close(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED) { fprintf(stderr, "fromwire_gossipd_local_channel_close called!\n"); abort(); } +/* Generated stub for fromwire_gossipd_local_private_channel */ +bool fromwire_gossipd_local_private_channel(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct amount_sat *capacity UNNEEDED, struct short_channel_id *scid UNNEEDED, u8 **features UNNEEDED) +{ fprintf(stderr, "fromwire_gossipd_local_private_channel called!\n"); abort(); } /* Generated stub for fromwire_gossipd_new_blockheight */ bool fromwire_gossipd_new_blockheight(const void *p UNNEEDED, u32 *blockheight UNNEEDED) { fprintf(stderr, "fromwire_gossipd_new_blockheight called!\n"); abort(); } @@ -133,9 +136,6 @@ u32 gossip_store_load(struct routing_state *rstate UNNEEDED, struct gossip_store /* Generated stub for gossip_time_now */ struct timeabs gossip_time_now(const struct routing_state *rstate UNNEEDED) { fprintf(stderr, "gossip_time_now called!\n"); abort(); } -/* Generated stub for gossipd_peerd_wire_name */ -const char *gossipd_peerd_wire_name(int e UNNEEDED) -{ fprintf(stderr, "gossipd_peerd_wire_name called!\n"); abort(); } /* Generated stub for handle_channel_announcement */ u8 *handle_channel_announcement(struct routing_state *rstate UNNEEDED, const u8 *announce TAKES UNNEEDED, @@ -150,9 +150,7 @@ u8 *handle_channel_update(struct routing_state *rstate UNNEEDED, const u8 *updat bool force UNNEEDED) { fprintf(stderr, "handle_channel_update called!\n"); abort(); } /* Generated stub for handle_local_channel_update */ -bool handle_local_channel_update(struct daemon *daemon UNNEEDED, - const struct node_id *src UNNEEDED, - const u8 *msg UNNEEDED) +void handle_local_channel_update(struct daemon *daemon UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "handle_local_channel_update called!\n"); abort(); } /* Generated stub for handle_node_announcement */ u8 *handle_node_announcement(struct routing_state *rstate UNNEEDED, const u8 *node UNNEEDED, @@ -247,6 +245,13 @@ struct chan *next_chan(const struct node *node UNNEEDED, struct chan_map_iter *i /* Generated stub for notleak_ */ void *notleak_(void *ptr UNNEEDED, bool plus_children UNNEEDED) { fprintf(stderr, "notleak_ called!\n"); abort(); } +/* Generated stub for private_channel_announcement */ +const u8 *private_channel_announcement(const tal_t *ctx UNNEEDED, + const struct short_channel_id *scid UNNEEDED, + const struct node_id *local_node_id UNNEEDED, + const struct node_id *remote_node_id UNNEEDED, + const u8 *features UNNEEDED) +{ fprintf(stderr, "private_channel_announcement called!\n"); abort(); } /* Generated stub for query_unknown_channel */ void query_unknown_channel(struct daemon *daemon UNNEEDED, struct peer *peer UNNEEDED, @@ -273,8 +278,9 @@ void route_prune(struct routing_state *rstate UNNEEDED) { fprintf(stderr, "route_prune called!\n"); abort(); } /* Generated stub for routing_add_private_channel */ bool routing_add_private_channel(struct routing_state *rstate UNNEEDED, - const struct peer *peer UNNEEDED, - const u8 *msg UNNEEDED, u64 index UNNEEDED) + const struct node_id *id UNNEEDED, + struct amount_sat sat UNNEEDED, + const u8 *chan_ann UNNEEDED, u64 index UNNEEDED) { fprintf(stderr, "routing_add_private_channel called!\n"); abort(); } /* Generated stub for sanitize_error */ char *sanitize_error(const tal_t *ctx UNNEEDED, const u8 *errmsg UNNEEDED, diff --git a/gossipd/test/run-txout_failure.c b/gossipd/test/run-txout_failure.c index ba7791c329a3..1acfd534d210 100644 --- a/gossipd/test/run-txout_failure.c +++ b/gossipd/test/run-txout_failure.c @@ -109,6 +109,10 @@ void peer_supplied_good_gossip(struct peer *peer UNNEEDED, size_t amount UNNEEDE char *sanitize_error(const tal_t *ctx UNNEEDED, const u8 *errmsg UNNEEDED, struct channel_id *channel_id UNNEEDED) { fprintf(stderr, "sanitize_error called!\n"); abort(); } +/* Generated stub for status_failed */ +void status_failed(enum status_failreason code UNNEEDED, + const char *fmt UNNEEDED, ...) +{ fprintf(stderr, "status_failed called!\n"); abort(); } /* Generated stub for status_fmt */ void status_fmt(enum log_level level UNNEEDED, const struct node_id *peer UNNEEDED, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 91efa1200d7e..7eb25409e5a7 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -401,6 +402,23 @@ static void handle_error_channel(struct channel *channel, forget(channel); } +static void handle_local_private_channel(struct channel *channel, const u8 *msg) +{ + struct amount_sat capacity; + u8 *features; + + if (!fromwire_channeld_local_private_channel(msg, msg, &capacity, + &features)) { + channel_internal_error(channel, + "bad channeld_local_private_channel %s", + tal_hex(channel, msg)); + return; + } + + tell_gossipd_local_private_channel(channel->peer->ld, channel, + capacity, features); +} + static void forget_channel(struct channel *channel, const char *why) { channel->error = towire_errorfmt(channel, &channel->cid, "%s", why); @@ -497,6 +515,15 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) /* This tells gossipd we used it. */ get_channel_update(sd->channel); break; + case WIRE_CHANNELD_LOCAL_CHANNEL_UPDATE: + tell_gossipd_local_channel_update(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_LOCAL_CHANNEL_ANNOUNCEMENT: + tell_gossipd_local_channel_announce(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_LOCAL_PRIVATE_CHANNEL: + handle_local_private_channel(sd->channel, msg); + break; #if EXPERIMENTAL_FEATURES case WIRE_CHANNELD_UPGRADED: handle_channel_upgrade(sd->channel, msg); diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 57acc86ca99f..9fd7640892c2 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -1,5 +1,6 @@ #include "config.h" #include +#include #include #include #include @@ -166,6 +167,9 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_ADDGOSSIP: case WIRE_GOSSIPD_GET_ADDRS: case WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE: + case WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE: + case WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT: + case WIRE_GOSSIPD_LOCAL_PRIVATE_CHANNEL: /* This is a reply, so never gets through to here. */ case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: @@ -258,6 +262,85 @@ void gossipd_notify_spend(struct lightningd *ld, subd_send_msg(ld->gossip, msg); } +/* We unwrap, add the peer id, and send to gossipd. */ +void tell_gossipd_local_channel_update(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct short_channel_id scid; + bool disable; + u16 cltv_expiry_delta; + struct amount_msat htlc_minimum_msat; + u32 fee_base_msat, fee_proportional_millionths; + struct amount_msat htlc_maximum_msat; + + if (!fromwire_channeld_local_channel_update(msg, &scid, &disable, + &cltv_expiry_delta, + &htlc_minimum_msat, + &fee_base_msat, + &fee_proportional_millionths, + &htlc_maximum_msat)) { + channel_internal_error(channel, + "bad channeld_local_channel_update %s", + tal_hex(channel, msg)); + return; + } + + /* As we're shutting down, ignore */ + if (!ld->gossip) + return; + + subd_send_msg(ld->gossip, + take(towire_gossipd_local_channel_update + (NULL, + &channel->peer->id, + &scid, + disable, + cltv_expiry_delta, + htlc_minimum_msat, + fee_base_msat, + fee_proportional_millionths, htlc_maximum_msat))); +} + +void tell_gossipd_local_channel_announce(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + u8 *ann; + if (!fromwire_channeld_local_channel_announcement(msg, msg, &ann)) { + channel_internal_error(channel, + "bad channeld_local_channel_announcement" + " %s", + tal_hex(channel, msg)); + return; + } + + /* As we're shutting down, ignore */ + if (!ld->gossip) + return; + + subd_send_msg(ld->gossip, + take(towire_gossipd_local_channel_announcement + (NULL, &channel->peer->id, ann))); +} + +void tell_gossipd_local_private_channel(struct lightningd *ld, + struct channel *channel, + struct amount_sat capacity, + const u8 *features) +{ + /* As we're shutting down, ignore */ + if (!ld->gossip) + return; + + subd_send_msg(ld->gossip, + take(towire_gossipd_local_private_channel + (NULL, &channel->peer->id, + capacity, + channel->scid, + features))); +} + static struct command_result *json_setleaserates(struct command *cmd, const char *buffer, const jsmntok_t *obj UNNEEDED, diff --git a/lightningd/gossip_control.h b/lightningd/gossip_control.h index 7d6254e291bb..c1d587902158 100644 --- a/lightningd/gossip_control.h +++ b/lightningd/gossip_control.h @@ -5,6 +5,7 @@ #include #include +struct channel; struct lightningd; void gossip_init(struct lightningd *ld, int connectd_fd); @@ -14,4 +15,16 @@ void gossipd_notify_spend(struct lightningd *ld, void gossip_notify_new_block(struct lightningd *ld, u32 blockheight); +/* channeld tells us stuff, we tell gossipd. */ +void tell_gossipd_local_channel_update(struct lightningd *ld, + struct channel *channel, + const u8 *msg); +void tell_gossipd_local_channel_announce(struct lightningd *ld, + struct channel *channel, + const u8 *msg); +void tell_gossipd_local_private_channel(struct lightningd *ld, + struct channel *channel, + struct amount_sat capacity, + const u8 *features); + #endif /* LIGHTNING_LIGHTNINGD_GOSSIP_CONTROL_H */ From ad5a53e1d67dbfd97316f2b04911ac0bdf05a98d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 37/51] channeld: tell gossipd about new channel earlier. We're about to change this to go via lightningd, not direct to gossipd, and connectd will send gossip direct to gossipd. Once we do this, it introduces a race. The peer sends funding_locked then immediately sends an update_channel. channeld used to process the funding_locked from the peer, tell gossipd about the new channel, then finally forward the channel_update. With the new architecture, we can have the channel_update hit gossipd before we've told it about the channel. It ignores the channel_update. Better is to tell gossipd as soon as *we* are ready to send funding_locked; this gives a round trip time at least, before gossipd could get the update. Signed-off-by: Rusty Russell --- channeld/channeld.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index 71fd7c2326e1..f268e02013ff 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -419,17 +419,9 @@ static void send_channel_update(struct peer *peer, int disable_flag) wire_sync_write(MASTER_FD, take(msg)); } -/** - * Add a channel locally and send a channel update to the peer - * - * Send a local_add_channel message to gossipd in order to make the channel - * usable locally, and also tell our peer about our parameters via a - * channel_update message. The peer may accept the update and use the contained - * information to route incoming payments through the channel. The - * channel_update is not preceeded by a channel_announcement and won't make much - * sense to other nodes, so we don't tell gossipd about it. - */ -static void make_channel_local_active(struct peer *peer) +/* Tells gossipd about our new channel, before it sees a + * channel_update from peer */ +static void tell_gossipd_new_channel(struct peer *peer) { u8 *msg; const u8 *annfeatures = get_agreed_channelfeatures(tmpctx, @@ -441,10 +433,6 @@ static void make_channel_local_active(struct peer *peer) peer->channel->funding_sats, annfeatures); wire_sync_write(MASTER_FD, take(msg)); - - /* Tell gossipd and the other side what parameters we expect should - * they route through us */ - send_channel_update(peer, 0); } static void send_announcement_signatures(struct peer *peer) @@ -573,7 +561,9 @@ static void channel_announcement_negotiate(struct peer *peer) if (!peer->channel_local_active) { peer->channel_local_active = true; - make_channel_local_active(peer); + /* Tell gossipd and the other side what parameters we + * expect should they route through us */ + send_channel_update(peer, 0); } /* BOLT #7: @@ -3281,6 +3271,8 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) peer->next_index[LOCAL], type_to_string(tmpctx, struct pubkey, &peer->next_local_per_commit)); + tell_gossipd_new_channel(peer); + msg = towire_funding_locked(NULL, &peer->channel_id, &peer->next_local_per_commit); @@ -4009,6 +4001,11 @@ static void init_channel(struct peer *peer) /* from now we need keep watch over WIRE_CHANNELD_FUNDING_DEPTH */ peer->depth_togo = minimum_depth; + /* Make sure gossipd knows about this channel if we have sent + * funding_locked */ + if (peer->funding_locked[LOCAL]) + tell_gossipd_new_channel(peer); + /* OK, now we can process peer messages. */ if (reconnected) peer_reconnect(peer, &last_remote_per_commit_secret, From 4078ac8a62accf073eea7bc5cca6db6462d9fe02 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 38/51] dualopend: tell lightningd about new channel as soon as it's locked in. Once we send funding_locked, gossipd could start seeing channel_updates from the peer (which get sent so we can use the channel in routehints even before it's announcable). Signed-off-by: Rusty Russell --- lightningd/dual_open_control.c | 23 +++++++++++++++++++++- openingd/dualopend.c | 36 ++++++++++++++++++++++++++++++++++ openingd/dualopend_wire.csv | 6 ++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 62a1fefb5c3c..4e01b299d6b6 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1348,6 +1349,24 @@ static void handle_channel_closed(struct subd *dualopend, "Start closingd"); } +static void handle_local_private_channel(struct subd *dualopend, + const u8 *msg) +{ + struct amount_sat capacity; + u8 *features; + + if (!fromwire_dualopend_local_private_channel(msg, msg, &capacity, + &features)) { + channel_internal_error(dualopend->channel, + "bad dualopend_local_private_channel %s", + tal_hex(msg, msg)); + return; + } + + tell_gossipd_local_private_channel(dualopend->ld, dualopend->channel, + capacity, features); +} + struct channel_send { const struct wally_tx *wtx; struct channel *channel; @@ -2966,7 +2985,9 @@ static unsigned int dual_opend_msg(struct subd *dualopend, case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND: channel_fail_fallen_behind(dualopend, msg); return 0; - + case WIRE_DUALOPEND_LOCAL_PRIVATE_CHANNEL: + handle_local_private_channel(dualopend, msg); + return 0; /* Messages we send */ case WIRE_DUALOPEND_INIT: case WIRE_DUALOPEND_REINIT: diff --git a/openingd/dualopend.c b/openingd/dualopend.c index a67b6e5f2779..51cbab0d8a71 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -3398,6 +3398,38 @@ static void send_funding_locked(struct state *state) billboard_update(state); } +/* FIXME: Maybe cache this? */ +static struct amount_sat channel_size(struct state *state) +{ + u32 funding_outnum; + const u8 *funding_wscript = + bitcoin_redeem_2of2(tmpctx, + &state->our_funding_pubkey, + &state->their_funding_pubkey); + + if (!find_txout(state->tx_state->psbt, + scriptpubkey_p2wsh(tmpctx, funding_wscript), + &funding_outnum)) { + open_err_fatal(state, "Cannot fund txout"); + } + + return psbt_output_get_amount(state->tx_state->psbt, funding_outnum); +} + +static void tell_gossipd_new_channel(struct state *state) +{ + u8 *msg; + const u8 *annfeatures = get_agreed_channelfeatures(tmpctx, + state->our_features, + state->their_features); + + /* Tell lightningd about local channel. */ + msg = towire_dualopend_local_private_channel(NULL, + channel_size(state), + annfeatures); + wire_sync_write(REQ_FD, take(msg)); +} + static u8 *handle_funding_depth(struct state *state, u8 *msg) { u32 depth; @@ -3412,6 +3444,9 @@ static u8 *handle_funding_depth(struct state *state, u8 *msg) /* We check this before we arrive here, but for sanity */ assert(state->minimum_depth <= depth); + /* Tell gossipd the new channel exists before we tell peer. */ + tell_gossipd_new_channel(state); + send_funding_locked(state); if (state->funding_locked[REMOTE]) return towire_dualopend_channel_locked(state); @@ -3669,6 +3704,7 @@ static u8 *handle_master_in(struct state *state) case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND: case WIRE_DUALOPEND_DRY_RUN: case WIRE_DUALOPEND_VALIDATE_LEASE: + case WIRE_DUALOPEND_LOCAL_PRIVATE_CHANNEL: break; } diff --git a/openingd/dualopend_wire.csv b/openingd/dualopend_wire.csv index cd5600e3a2e8..f7305e6e009c 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -237,3 +237,9 @@ msgdata,dualopend_validate_lease,their_pubkey,pubkey, msgtype,dualopend_validate_lease_reply,7127 msgdata,dualopend_validate_lease_reply,err_msg,?wirestring, + +# Tell gossipd about this (as-yet) unannounced channel +msgtype,dualopend_local_private_channel,7015 +msgdata,dualopend_local_private_channel,capacity,amount_sat, +msgdata,dualopend_local_private_channel,len,u16, +msgdata,dualopend_local_private_channel,features,u8,len From 08af613edd4f2625c420d8757eaa2259e0053ed1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 39/51] connectd: temporarily have two fds to gossipd. We want to stream gossip through this, but currently connectd treats the fd as synchronous. While we work on getting rid of that, it's easiest to have two fds. Signed-off-by: Rusty Russell --- connectd/connectd.c | 17 ++++++++++++++++- connectd/connectd.h | 3 +++ lightningd/connect_control.c | 12 +++++++++--- lightningd/connect_control.h | 2 +- lightningd/gossip_control.c | 7 +++++-- lightningd/gossip_control.h | 2 +- lightningd/lightningd.c | 6 +++--- lightningd/test/run-find_my_abspath.c | 4 ++-- 8 files changed, 40 insertions(+), 13 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 3cbfc3c7ffa6..fc0a0123482b 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -52,6 +52,7 @@ * thus may know how to reach certain peers. */ #define HSM_FD 3 #define GOSSIPCTL_FD 4 +#define GOSSIPCTL2_FD 5 /*~ In C convention, constants are UPPERCASE macros. Not everything needs to * be a constant, but it soothes the programmer's conscience to encapsulate @@ -1568,7 +1569,7 @@ static void connect_init(struct daemon *daemon, const u8 *msg) announcable))); #if DEVELOPER if (dev_disconnect) - dev_disconnect_init(5); + dev_disconnect_init(6); #endif } @@ -1967,6 +1968,15 @@ static void master_gone(struct daemon_conn *master UNUSED) exit(2); } +/*~ gossipd sends us gossip to send to the peers. */ +static struct io_plan *recv_gossip(struct io_conn *conn, + const u8 *msg, + struct daemon *daemon) +{ + /* FIXME! */ + return daemon_conn_read_next(conn, daemon->gossipd); +} + /*~ This is a hook used by the memleak code (if DEVELOPER=1): it can't see * pointers inside hash tables, so we give it a hint here. */ #if DEVELOPER @@ -2003,6 +2013,11 @@ int main(int argc, char *argv[]) * our status_ and failed messages. */ status_setup_async(daemon->master); + /* This streams gossip to and from gossipd */ + daemon->gossipd = daemon_conn_new(daemon, GOSSIPCTL2_FD, + recv_gossip, NULL, + daemon); + /* Set up ecdh() function so it uses our HSM fd, and calls * status_failed on error. */ ecdh_hsmd_setup(HSM_FD, status_failed); diff --git a/connectd/connectd.h b/connectd/connectd.h index ff4057538cd7..5e697198d76a 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -117,6 +117,9 @@ struct daemon { /* Connection to main daemon. */ struct daemon_conn *master; + /* Connection to gossip daemon. */ + struct daemon_conn *gossipd; + /* Allow localhost to be considered "public": DEVELOPER-only option, * but for simplicity we don't #if DEVELOPER-wrap it here. */ bool dev_allow_localhost; diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index fe96b555e077..d986fe8bb780 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -406,9 +406,9 @@ static void connect_init_done(struct subd *connectd, io_break(connectd); } -int connectd_init(struct lightningd *ld) +int connectd_init(struct lightningd *ld, int *gossipd_fd2) { - int fds[2]; + int fds[2], fds2[2]; u8 *msg; int hsmfd; struct wireaddr_internal *wireaddrs = ld->proposed_wireaddr; @@ -421,11 +421,16 @@ int connectd_init(struct lightningd *ld) if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) fatal("Could not socketpair for connectd<->gossipd"); + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds2) != 0) + fatal("Could not socketpair for connectd<->gossipd 2"); + hsmfd = hsm_get_global_fd(ld, HSM_CAP_ECDH); ld->connectd = new_global_subd(ld, "lightning_connectd", connectd_wire_name, connectd_msg, - take(&hsmfd), take(&fds[1]), + take(&hsmfd), + take(&fds[1]), + take(&fds2[1]), #if DEVELOPER /* Not take(): we share it */ ld->dev_disconnect_fd >= 0 ? @@ -466,6 +471,7 @@ int connectd_init(struct lightningd *ld) /* Wait for init_reply */ io_loop(NULL, NULL); + *gossipd_fd2 = fds2[0]; return fds[0]; } diff --git a/lightningd/connect_control.h b/lightningd/connect_control.h index 67beb003782b..681c5c7a1ed5 100644 --- a/lightningd/connect_control.h +++ b/lightningd/connect_control.h @@ -7,7 +7,7 @@ struct pubkey; struct wireaddr_internal; /* Returns fd for gossipd to talk to connectd */ -int connectd_init(struct lightningd *ld); +int connectd_init(struct lightningd *ld, int *gossipd_fd2); void connectd_activate(struct lightningd *ld); void try_reconnect(struct channel *channel, u32 seconds_delay, diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 9fd7640892c2..19ac7eb73533 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -219,7 +219,7 @@ static void gossipd_init_done(struct subd *gossipd, /* Create the `gossipd` subdaemon and send the initialization * message */ -void gossip_init(struct lightningd *ld, int connectd_fd) +void gossip_init(struct lightningd *ld, int connectd_fd, int connectd_fd2) { u8 *msg; int hsmfd; @@ -228,7 +228,10 @@ void gossip_init(struct lightningd *ld, int connectd_fd) ld->gossip = new_global_subd(ld, "lightning_gossipd", gossipd_wire_name, gossip_msg, - take(&hsmfd), take(&connectd_fd), NULL); + take(&hsmfd), + take(&connectd_fd), + take(&connectd_fd2), + NULL); if (!ld->gossip) err(1, "Could not subdaemon gossip"); diff --git a/lightningd/gossip_control.h b/lightningd/gossip_control.h index c1d587902158..869f53930aaf 100644 --- a/lightningd/gossip_control.h +++ b/lightningd/gossip_control.h @@ -8,7 +8,7 @@ struct channel; struct lightningd; -void gossip_init(struct lightningd *ld, int connectd_fd); +void gossip_init(struct lightningd *ld, int connectd_fd, int connectd_fd2); void gossipd_notify_spend(struct lightningd *ld, const struct short_channel_id *scid); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 3700816625ea..329316cd1854 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -846,7 +846,7 @@ int main(int argc, char *argv[]) { struct lightningd *ld; u32 min_blockheight, max_blockheight; - int connectd_gossipd_fd; + int connectd_gossipd_fd, connectd_gossipd_fd2; int stop_fd; struct timers *timers; const char *stop_response; @@ -1022,7 +1022,7 @@ int main(int argc, char *argv[]) * which knows (via node_announcement messages) the public * addresses of nodes, so connectd_init hands it one end of a * socket pair, and gives us the other */ - connectd_gossipd_fd = connectd_init(ld); + connectd_gossipd_fd = connectd_init(ld, &connectd_gossipd_fd2); /*~ We do every database operation within a transaction; usually this * is covered by the infrastructure (eg. opening a transaction before @@ -1074,7 +1074,7 @@ int main(int argc, char *argv[]) * channel_announcement, channel_update, node_announcement and gossip * queries. It also hands us the latest channel_updates for our * channels. */ - gossip_init(ld, connectd_gossipd_fd); + gossip_init(ld, connectd_gossipd_fd, connectd_gossipd_fd2); /*~ Create RPC socket: now lightning-cli can send us JSON RPC commands * over a UNIX domain socket specified by `ld->rpc_filename`. */ diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index b0a2469d946a..102ca04fde44 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -26,7 +26,7 @@ void coin_mvts_init_count(struct lightningd *ld UNNEEDED) void connectd_activate(struct lightningd *ld UNNEEDED) { fprintf(stderr, "connectd_activate called!\n"); abort(); } /* Generated stub for connectd_init */ -int connectd_init(struct lightningd *ld UNNEEDED) +int connectd_init(struct lightningd *ld UNNEEDED, int *gossipd_fd2 UNNEEDED) { fprintf(stderr, "connectd_init called!\n"); abort(); } /* Generated stub for daemon_poll */ int daemon_poll(struct pollfd *fds UNNEEDED, nfds_t nfds UNNEEDED, int timeout UNNEEDED) @@ -95,7 +95,7 @@ bool fromwire_status_peer_error(const tal_t *ctx UNNEEDED, const void *p UNNEEDE bool fromwire_status_version(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, wirestring **version UNNEEDED) { fprintf(stderr, "fromwire_status_version called!\n"); abort(); } /* Generated stub for gossip_init */ -void gossip_init(struct lightningd *ld UNNEEDED, int connectd_fd UNNEEDED) +void gossip_init(struct lightningd *ld UNNEEDED, int connectd_fd UNNEEDED, int connectd_fd2 UNNEEDED) { fprintf(stderr, "gossip_init called!\n"); abort(); } /* Generated stub for gossip_notify_new_block */ void gossip_notify_new_block(struct lightningd *ld UNNEEDED, u32 blockheight UNNEEDED) From e1e7e76cf3fd47fa59e28cd57cadae72cf6882e0 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 40/51] gossipd: add routines to send gossip messages to and from connectd. Signed-off-by: Rusty Russell --- connectd/connectd.c | 13 ++- connectd/connectd_gossipd_wire.csv | 12 +++ gossipd/gossipd.c | 143 ++++++++++++++++++++++++++++- gossipd/gossipd.h | 2 + gossipd/test/run-onion_message.c | 6 ++ 5 files changed, 173 insertions(+), 3 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index fc0a0123482b..bea4a0fc1358 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1973,7 +1973,18 @@ static struct io_plan *recv_gossip(struct io_conn *conn, const u8 *msg, struct daemon *daemon) { - /* FIXME! */ + struct node_id dst; + u8 *gossip_msg; + struct peer *peer; + + if (!fromwire_gossipd_send_gossip(msg, msg, &dst, &gossip_msg)) + status_failed(STATUS_FAIL_GOSSIP_IO, "Unknown msg %i", + fromwire_peektype(msg)); + + peer = peer_htable_get(&daemon->peers, &dst); + if (peer) + queue_peer_msg(peer, take(gossip_msg)); + return daemon_conn_read_next(conn, daemon->gossipd); } diff --git a/connectd/connectd_gossipd_wire.csv b/connectd/connectd_gossipd_wire.csv index 5517b450afde..bdb9a75f5292 100644 --- a/connectd/connectd_gossipd_wire.csv +++ b/connectd/connectd_gossipd_wire.csv @@ -11,3 +11,15 @@ msgdata,gossipd_new_peer,gossip_queries_feature,bool, # if success: + gossip fd msgtype,gossipd_new_peer_reply,4100 msgdata,gossipd_new_peer_reply,success,bool, + +# connectd tells gossipd a gossip msg it received for peer. +msgtype,gossipd_recv_gossip,4002 +msgdata,gossipd_recv_gossip,id,node_id, +msgdata,gossipd_recv_gossip,len,u16, +msgdata,gossipd_recv_gossip,msg,byte,len + +# Gossipd asks connectd to send a gossip msg for peer. +msgtype,gossipd_send_gossip,4102 +msgdata,gossipd_send_gossip,id,node_id, +msgdata,gossipd_send_gossip,len,u16, +msgdata,gossipd_send_gossip,msg,byte,len diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index e14482372e1f..576174cfc33d 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -118,10 +118,14 @@ void peer_supplied_good_gossip(struct peer *peer, size_t amount) peer->gossip_counter += amount; } -/* Queue a gossip message for the peer: the subdaemon on the other end simply - * forwards it to the peer. */ +/* Queue a gossip message for the peer: connectd simply forwards it to + * the peer. */ void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) { + u8 *outermsg = towire_gossipd_send_gossip(NULL, &peer->id, msg); + daemon_conn_send(peer->daemon->connectd2, take(outermsg)); + + /* FIXME: backwards compat! */ daemon_conn_send(peer->dc, msg); } @@ -856,6 +860,108 @@ static struct io_plan *handle_get_address(struct io_conn *conn, return daemon_conn_read_next(conn, daemon->master); } +static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg) +{ + struct node_id id; + u8 *msg; + const u8 *err; + struct peer *peer; + + if (!fromwire_gossipd_recv_gossip(outermsg, outermsg, &id, &msg)) { + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Bad gossipd_recv_gossip msg from connectd: %s", + tal_hex(tmpctx, outermsg)); + } + + /* FIXME: happens when peer closes! */ + peer = find_peer(daemon, &id); + if (!peer) { + status_debug("connectd sent gossip msg %s for unknown peer %s", + peer_wire_name(fromwire_peektype(msg)), + type_to_string(tmpctx, struct node_id, &id)); + return; + } + + /* These are messages relayed from peer */ + switch ((enum peer_wire)fromwire_peektype(msg)) { + case WIRE_CHANNEL_ANNOUNCEMENT: + err = handle_channel_announcement_msg(peer->daemon, peer, msg); + goto handled_msg; + case WIRE_CHANNEL_UPDATE: + err = handle_channel_update_msg(peer, msg); + goto handled_msg; + case WIRE_NODE_ANNOUNCEMENT: + err = handle_node_announce(peer, msg); + goto handled_msg; + case WIRE_QUERY_CHANNEL_RANGE: + err = handle_query_channel_range(peer, msg); + goto handled_msg; + case WIRE_REPLY_CHANNEL_RANGE: + err = handle_reply_channel_range(peer, msg); + goto handled_msg; + case WIRE_QUERY_SHORT_CHANNEL_IDS: + err = handle_query_short_channel_ids(peer, msg); + goto handled_msg; + case WIRE_REPLY_SHORT_CHANNEL_IDS_END: + err = handle_reply_short_channel_ids_end(peer, msg); + goto handled_msg; + case WIRE_OBS2_ONION_MESSAGE: + err = handle_obs2_onion_message(peer, msg); + goto handled_msg; + case WIRE_ONION_MESSAGE: + err = handle_onion_message(peer, msg); + goto handled_msg; + + /* These are non-gossip messages (!is_msg_for_gossipd()) */ + case WIRE_WARNING: + case WIRE_INIT: + case WIRE_ERROR: + case WIRE_PING: + case WIRE_PONG: + case WIRE_OPEN_CHANNEL: + case WIRE_ACCEPT_CHANNEL: + case WIRE_FUNDING_CREATED: + case WIRE_FUNDING_SIGNED: + case WIRE_FUNDING_LOCKED: + case WIRE_SHUTDOWN: + case WIRE_CLOSING_SIGNED: + case WIRE_UPDATE_ADD_HTLC: + case WIRE_UPDATE_FULFILL_HTLC: + case WIRE_UPDATE_FAIL_HTLC: + case WIRE_UPDATE_FAIL_MALFORMED_HTLC: + case WIRE_COMMITMENT_SIGNED: + case WIRE_REVOKE_AND_ACK: + case WIRE_UPDATE_FEE: + case WIRE_UPDATE_BLOCKHEIGHT: + case WIRE_CHANNEL_REESTABLISH: + case WIRE_ANNOUNCEMENT_SIGNATURES: + case WIRE_GOSSIP_TIMESTAMP_FILTER: + case WIRE_TX_ADD_INPUT: + case WIRE_TX_REMOVE_INPUT: + case WIRE_TX_ADD_OUTPUT: + case WIRE_TX_REMOVE_OUTPUT: + case WIRE_TX_COMPLETE: + case WIRE_TX_SIGNATURES: + case WIRE_OPEN_CHANNEL2: + case WIRE_ACCEPT_CHANNEL2: + case WIRE_INIT_RBF: + case WIRE_ACK_RBF: +#if EXPERIMENTAL_FEATURES + case WIRE_STFU: +#endif + break; + } + + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "connectd sent unexpected gossip msg %s for peer %s", + peer_wire_name(fromwire_peektype(msg)), + type_to_string(tmpctx, struct node_id, &peer->id)); + +handled_msg: + if (err) + queue_peer_msg(peer, take(err)); +} + /*~ connectd's input handler is very simple. */ static struct io_plan *connectd_req(struct io_conn *conn, const u8 *msg, @@ -867,8 +973,11 @@ static struct io_plan *connectd_req(struct io_conn *conn, case WIRE_GOSSIPD_NEW_PEER: return connectd_new_peer(conn, daemon, msg); + /* This is not for this fd! */ + case WIRE_GOSSIPD_RECV_GOSSIP: /* We send these, don't receive them. */ case WIRE_GOSSIPD_NEW_PEER_REPLY: + case WIRE_GOSSIPD_SEND_GOSSIP: break; } @@ -877,6 +986,33 @@ static struct io_plan *connectd_req(struct io_conn *conn, return io_close(conn); } +/*~ connectd's input handler is very simple. */ +static struct io_plan *connectd_gossip_req(struct io_conn *conn, + const u8 *msg, + struct daemon *daemon) +{ + enum connectd_gossipd_wire t = fromwire_peektype(msg); + + switch (t) { + case WIRE_GOSSIPD_RECV_GOSSIP: + handle_recv_gossip(daemon, msg); + goto handled; + + /* This is not for this fd! */ + case WIRE_GOSSIPD_NEW_PEER: + /* We send these, don't receive them. */ + case WIRE_GOSSIPD_NEW_PEER_REPLY: + case WIRE_GOSSIPD_SEND_GOSSIP: + break; + } + + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Bad msg from connectd2: %s", tal_hex(tmpctx, msg)); + +handled: + return daemon_conn_read_next(conn, daemon->connectd2); +} + /* BOLT #7: * * A node: @@ -1036,6 +1172,9 @@ static void gossip_init(struct daemon *daemon, const u8 *msg) daemon->connectd = daemon_conn_new(daemon, CONNECTD_FD, connectd_req, NULL, daemon); + daemon->connectd2 = daemon_conn_new(daemon, CONNECTD2_FD, + connectd_gossip_req, NULL, daemon); + /* OK, we are ready. */ daemon_conn_send(daemon->master, take(towire_gossipd_init_reply(NULL))); diff --git a/gossipd/gossipd.h b/gossipd/gossipd.h index af1d435ae3e7..75b39b8c67a1 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -9,6 +9,7 @@ #define HSM_FD 3 /* connectd asks us for help finding nodes, and gossip fds for new peers */ #define CONNECTD_FD 4 +#define CONNECTD2_FD 5 struct chan; struct channel_update_timestamps; @@ -32,6 +33,7 @@ struct daemon { /* Connection to connect daemon. */ struct daemon_conn *connectd; + struct daemon_conn *connectd2; /* Routing information */ struct routing_state *rstate; diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 91afcd4528dd..3399a9adc8b5 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -112,6 +112,9 @@ bool fromwire_gossipd_new_peer(const void *p UNNEEDED, struct node_id *id UNNEED /* Generated stub for fromwire_gossipd_outpoint_spent */ bool fromwire_gossipd_outpoint_spent(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED) { fprintf(stderr, "fromwire_gossipd_outpoint_spent called!\n"); abort(); } +/* Generated stub for fromwire_gossipd_recv_gossip */ +bool fromwire_gossipd_recv_gossip(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u8 **msg UNNEEDED) +{ fprintf(stderr, "fromwire_gossipd_recv_gossip called!\n"); abort(); } /* Generated stub for fromwire_gossipd_send_onionmsg */ bool fromwire_gossipd_send_onionmsg(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *obs2 UNNEEDED, struct node_id *id UNNEEDED, u8 **onion UNNEEDED, struct pubkey *blinding UNNEEDED) { fprintf(stderr, "fromwire_gossipd_send_onionmsg called!\n"); abort(); } @@ -332,6 +335,9 @@ u8 *towire_gossipd_init_reply(const tal_t *ctx UNNEEDED) /* Generated stub for towire_gossipd_new_peer_reply */ u8 *towire_gossipd_new_peer_reply(const tal_t *ctx UNNEEDED, bool success UNNEEDED) { fprintf(stderr, "towire_gossipd_new_peer_reply called!\n"); abort(); } +/* Generated stub for towire_gossipd_send_gossip */ +u8 *towire_gossipd_send_gossip(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const u8 *msg UNNEEDED) +{ fprintf(stderr, "towire_gossipd_send_gossip called!\n"); abort(); } /* Generated stub for towire_warningfmt */ u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, const struct channel_id *channel UNNEEDED, From 4248fbed415d1e6c69c3d8d6d29185478e4a4848 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 41/51] connectd: divert gossip messages directly to gossipd. Signed-off-by: Rusty Russell --- connectd/multiplex.c | 13 ++++++++++++- gossipd/gossipd.c | 30 ++++++++---------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/connectd/multiplex.c b/connectd/multiplex.c index c177effcc21a..9a69b9165a88 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +30,7 @@ #include #include #include +#include void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) { @@ -313,7 +316,7 @@ static u8 *maybe_from_gossip_store(const tal_t *ctx, struct peer *peer) return NULL; } -/* We only handle gossip_timestamp_filter for now */ +/* We handle gossip_timestamp_filter, and divert other gossip msgs to gossipd */ static bool handle_message_locally(struct peer *peer, const u8 *msg) { struct bitcoin_blkid chain_hash; @@ -326,6 +329,14 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg) if (!fromwire_gossip_timestamp_filter(msg, &chain_hash, &first_timestamp, ×tamp_range)) { + /* Do we want to divert to gossipd? */ + if (is_msg_for_gossipd(msg)) { + u8 *gmsg = towire_gossipd_recv_gossip(NULL, + &peer->id, msg); + daemon_conn_send(peer->daemon->gossipd, take(gmsg)); + return true; + } + return false; } diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 576174cfc33d..febe6c926268 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -681,27 +681,6 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, /* These are messages relayed from peer */ switch ((enum peer_wire)fromwire_peektype(msg)) { - case WIRE_CHANNEL_ANNOUNCEMENT: - err = handle_channel_announcement_msg(peer->daemon, peer, msg); - goto handled_relay; - case WIRE_CHANNEL_UPDATE: - err = handle_channel_update_msg(peer, msg); - goto handled_relay; - case WIRE_NODE_ANNOUNCEMENT: - err = handle_node_announce(peer, msg); - goto handled_relay; - case WIRE_QUERY_CHANNEL_RANGE: - err = handle_query_channel_range(peer, msg); - goto handled_relay; - case WIRE_REPLY_CHANNEL_RANGE: - err = handle_reply_channel_range(peer, msg); - goto handled_relay; - case WIRE_QUERY_SHORT_CHANNEL_IDS: - err = handle_query_short_channel_ids(peer, msg); - goto handled_relay; - case WIRE_REPLY_SHORT_CHANNEL_IDS_END: - err = handle_reply_short_channel_ids_end(peer, msg); - goto handled_relay; case WIRE_OBS2_ONION_MESSAGE: err = handle_obs2_onion_message(peer, msg); goto handled_relay; @@ -709,7 +688,14 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, err = handle_onion_message(peer, msg); goto handled_relay; - /* These are non-gossip messages (!is_msg_for_gossipd()) */ + /* These are not sent by peer (connectd sends us gossip msgs) */ + case WIRE_CHANNEL_ANNOUNCEMENT: + case WIRE_CHANNEL_UPDATE: + case WIRE_NODE_ANNOUNCEMENT: + case WIRE_QUERY_CHANNEL_RANGE: + case WIRE_REPLY_CHANNEL_RANGE: + case WIRE_QUERY_SHORT_CHANNEL_IDS: + case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_WARNING: case WIRE_INIT: case WIRE_ERROR: From c7c0bef483a5afee174bb9431deeee74c03d22c3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 42/51] gossipd: send all gossip msgs directly to connectd, not peer. Signed-off-by: Rusty Russell --- gossipd/gossipd.c | 12 ++++++------ gossipd/queries.c | 22 +++++++++++++++++++--- gossipd/queries.h | 4 ++-- gossipd/test/run-onion_message.c | 2 +- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index febe6c926268..3f8e9f60bfff 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -125,8 +125,8 @@ void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) u8 *outermsg = towire_gossipd_send_gossip(NULL, &peer->id, msg); daemon_conn_send(peer->daemon->connectd2, take(outermsg)); - /* FIXME: backwards compat! */ - daemon_conn_send(peer->dc, msg); + if (taken(msg)) + tal_free(msg); } /*~ We have a helper for messages from the store. */ @@ -797,11 +797,10 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, list_add_tail(&peer->daemon->peers, &peer->list); tal_add_destructor(peer, destroy_peer); - /* This is the new connection: calls maybe_send_query_responses when - * nothing else to send. */ + /* This is the new connection. */ peer->dc = daemon_conn_new(daemon, fds[0], peer_msg_in, - maybe_send_query_responses, peer); + NULL, peer); /* Free peer if conn closed (destroy_peer closes conn if peer freed) */ tal_steal(peer->dc, peer); @@ -1156,7 +1155,8 @@ static void gossip_init(struct daemon *daemon, const u8 *msg) /* connectd is already started, and uses this fd to ask us things. */ daemon->connectd = daemon_conn_new(daemon, CONNECTD_FD, - connectd_req, NULL, daemon); + connectd_req, + maybe_send_query_responses, daemon); daemon->connectd2 = daemon_conn_new(daemon, CONNECTD2_FD, connectd_gossip_req, NULL, daemon); diff --git a/gossipd/queries.c b/gossipd/queries.c index ccd8e2dc6cca..436ee9b2c4b4 100644 --- a/gossipd/queries.c +++ b/gossipd/queries.c @@ -335,8 +335,8 @@ const u8 *handle_query_short_channel_ids(struct peer *peer, const u8 *msg) peer->scid_query_idx = 0; peer->scid_query_nodes = tal_arr(peer, struct node_id, 0); - /* Notify the daemon_conn-write loop to invoke create_next_scid_reply */ - daemon_conn_wake(peer->dc); + /* Notify the daemon_conn-write loop to invoke maybe_send_query_responses_peer */ + daemon_conn_wake(peer->daemon->connectd); return NULL; } @@ -985,7 +985,7 @@ static void uniquify_node_ids(struct node_id **ids) /* We are fairly careful to avoid the peer DoSing us with channel queries: * this routine sends information about a single short_channel_id, unless * it's finished all of them. */ -void maybe_send_query_responses(struct peer *peer) +static bool maybe_send_query_responses_peer(struct peer *peer) { struct routing_state *rstate = peer->daemon->rstate; size_t i, num; @@ -1119,6 +1119,22 @@ void maybe_send_query_responses(struct peer *peer) peer->scid_query_nodes = tal_free(peer->scid_query_nodes); peer->scid_query_nodes_idx = 0; } + return sent; +} + +void maybe_send_query_responses(struct daemon *daemon) +{ + /* Rotate through, so we don't favor a single peer. */ + struct list_head used; + struct peer *p; + + list_head_init(&used); + while ((p = list_pop(&daemon->peers, struct peer, list)) != NULL) { + list_add(&used, &p->list); + if (maybe_send_query_responses_peer(p)) + break; + } + list_append_list(&daemon->peers, &used); } bool query_channel_range(struct daemon *daemon, diff --git a/gossipd/queries.h b/gossipd/queries.h index 14ea121ae64e..1e4019f11115 100644 --- a/gossipd/queries.h +++ b/gossipd/queries.h @@ -16,8 +16,8 @@ const u8 *handle_reply_short_channel_ids_end(struct peer *peer, const u8 *msg); const u8 *handle_query_channel_range(struct peer *peer, const u8 *msg); const u8 *handle_reply_channel_range(struct peer *peer, const u8 *msg); -/* This called when the peer is idle. */ -void maybe_send_query_responses(struct peer *peer); +/* This called when the connectd is idle. */ +void maybe_send_query_responses(struct daemon *daemon); /* BOLT #7: * diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c index 3399a9adc8b5..92882e53d001 100644 --- a/gossipd/test/run-onion_message.c +++ b/gossipd/test/run-onion_message.c @@ -210,7 +210,7 @@ void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) void maybe_send_own_node_announce(struct daemon *daemon UNNEEDED, bool startup UNNEEDED) { fprintf(stderr, "maybe_send_own_node_announce called!\n"); abort(); } /* Generated stub for maybe_send_query_responses */ -void maybe_send_query_responses(struct peer *peer UNNEEDED) +void maybe_send_query_responses(struct daemon *daemon UNNEEDED) { fprintf(stderr, "maybe_send_query_responses called!\n"); abort(); } /* Generated stub for memleak_find_allocations */ struct htable *memleak_find_allocations(const tal_t *ctx UNNEEDED, From e3e8718fed81d1abfc6a2f9dd2bd5fd0702ab250 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 43/51] connectd: handle pings and pongs. Signed-off-by: Rusty Russell Changelog-Changed: JSON_RPC: `ping` now works with connected peers, even without a channel. --- channeld/channeld.c | 133 +---------------------- channeld/channeld_wire.csv | 11 -- connectd/Makefile | 1 + connectd/connectd.c | 5 + connectd/connectd.h | 16 +++ connectd/connectd_wire.csv | 12 +++ connectd/multiplex.c | 199 ++++++++++++++++++++++++++++++++--- connectd/multiplex.h | 3 + lightningd/Makefile | 2 +- lightningd/channel_control.c | 5 - lightningd/connect_control.c | 2 + lightningd/ping.c | 82 +++------------ lightningd/ping.h | 9 -- 13 files changed, 237 insertions(+), 243 deletions(-) delete mode 100644 lightningd/ping.h diff --git a/channeld/channeld.c b/channeld/channeld.c index f268e02013ff..0ee694949045 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -50,15 +49,6 @@ #define MASTER_FD STDIN_FILENO #define HSM_FD 5 -enum pong_expect_type { - /* We weren't expecting a ping reply */ - PONG_UNEXPECTED = 0, - /* We were expecting a ping reply due to ping command */ - PONG_EXPECTED_COMMAND = 1, - /* We were expecting a ping reply due to ping timer */ - PONG_EXPECTED_PROBING = 2, -}; - struct peer { struct per_peer_state *pps; bool funding_locked[NUM_SIDES]; @@ -110,12 +100,6 @@ struct peer { u64 commit_timer_attempts; u32 commit_msec; - /* Random ping timer, to detect dead connections. */ - struct oneshot *ping_timer; - - /* Are we expecting a pong? */ - enum pong_expect_type expecting_pong; - /* The feerate we want. */ u32 desired_feerate; @@ -1075,29 +1059,6 @@ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx, return htlc_sigs; } -/* Mutual recursion */ -static void send_ping(struct peer *peer); - -static void set_ping_timer(struct peer *peer) -{ - peer->ping_timer = new_reltimer(&peer->timers, peer, - time_from_sec(15 + pseudorand(30)), - send_ping, peer); -} - -static void send_ping(struct peer *peer) -{ - /* Already have a ping in flight? */ - if (peer->expecting_pong != PONG_UNEXPECTED) { - status_debug("Last ping unreturned: hanging up"); - exit(0); - } - - peer_write(peer->pps, take(make_ping(NULL, 1, 0))); - peer->expecting_pong = PONG_EXPECTED_PROBING; - set_ping_timer(peer); -} - /* Peer protocol doesn't want sighash flags. */ static secp256k1_ecdsa_signature *raw_sigs(const tal_t *ctx, const struct bitcoin_signature *sigs) @@ -2170,29 +2131,6 @@ static void handle_unexpected_reestablish(struct peer *peer, const u8 *msg) &channel_id)); } -static void handle_ping_reply(struct peer *peer, const u8 *msg) -{ - u8 *ignored; - size_t i; - - /* We print this out because we asked for pong, so can't spam us... */ - if (!fromwire_pong(msg, msg, &ignored)) - status_unusual("Got malformed ping reply %s", - tal_hex(tmpctx, msg)); - - /* We print this because dev versions of c-lightning embed - * version here: see check_ping_make_pong! */ - for (i = 0; i < tal_count(ignored); i++) { - if (ignored[i] < ' ' || ignored[i] == 127) - break; - } - status_debug("Got pong %zu bytes (%.*s...)", - tal_count(ignored), (int)i, (char *)ignored); - wire_sync_write(MASTER_FD, - take(towire_channeld_ping_reply(NULL, true, - tal_bytelen(msg)))); -} - static void peer_in(struct peer *peer, const u8 *msg) { enum peer_wire type = fromwire_peektype(msg); @@ -2285,19 +2223,6 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_INIT_RBF: case WIRE_ACK_RBF: break; - case WIRE_PONG: - switch (peer->expecting_pong) { - case PONG_EXPECTED_COMMAND: - handle_ping_reply(peer, msg); - /* fall thru */ - case PONG_EXPECTED_PROBING: - peer->expecting_pong = PONG_UNEXPECTED; - return; - case PONG_UNEXPECTED: - status_debug("Unexpected pong?"); - return; - } - abort(); case WIRE_CHANNEL_REESTABLISH: handle_unexpected_reestablish(peer, msg); @@ -2313,6 +2238,7 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_GOSSIP_TIMESTAMP_FILTER: case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_PING: + case WIRE_PONG: case WIRE_WARNING: case WIRE_ERROR: case WIRE_OBS2_ONION_MESSAGE: @@ -3600,57 +3526,6 @@ static void handle_send_error(struct peer *peer, const u8 *msg) take(towire_channeld_send_error_reply(NULL))); } -static void handle_send_ping(struct peer *peer, const u8 *msg) -{ - u8 *ping; - u16 len, num_pong_bytes; - - if (!fromwire_channeld_ping(msg, &num_pong_bytes, &len)) - master_badmsg(WIRE_CHANNELD_PING, msg); - - /* We're not supposed to send another ping until previous replied */ - if (peer->expecting_pong != PONG_UNEXPECTED) { - wire_sync_write(MASTER_FD, - take(towire_channeld_ping_reply(NULL, false, 0))); - return; - } - - /* It should never ask for an oversize ping. */ - ping = make_ping(NULL, num_pong_bytes, len); - if (tal_count(ping) > 65535) - status_failed(STATUS_FAIL_MASTER_IO, "Oversize ping"); - - peer_write(peer->pps, take(ping)); - - /* Since we're doing this manually, kill and restart timer. */ - status_debug("sending ping expecting %sresponse", - num_pong_bytes >= 65532 ? "no " : ""); - - /* BOLT #1: - * - * A node receiving a `ping` message: - *... - * - if `num_pong_bytes` is less than 65532: - * - MUST respond by sending a `pong` message, with `byteslen` equal - * to `num_pong_bytes`. - * - otherwise (`num_pong_bytes` is **not** less than 65532): - * - MUST ignore the `ping`. - */ - if (num_pong_bytes >= 65532) { - wire_sync_write(MASTER_FD, - take(towire_channeld_ping_reply(NULL, - true, 0))); - return; - } - - /* We'll respond to lightningd once the pong comes in */ - peer->expecting_pong = PONG_EXPECTED_COMMAND; - - /* Restart our timed pings now. */ - tal_free(peer->ping_timer); - set_ping_timer(peer); -} - #if DEVELOPER static void handle_dev_reenable_commit(struct peer *peer) { @@ -3749,9 +3624,6 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_SEND_ERROR: handle_send_error(peer, msg); return; - case WIRE_CHANNELD_PING: - handle_send_ping(peer, msg); - return; case WIRE_CHANNELD_CHANNEL_UPDATE: handle_channel_update(peer, msg); return; @@ -3790,7 +3662,6 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_SEND_ERROR_REPLY: case WIRE_CHANNELD_DEV_QUIESCE_REPLY: case WIRE_CHANNELD_UPGRADED: - case WIRE_CHANNELD_PING_REPLY: case WIRE_CHANNELD_USED_CHANNEL_UPDATE: case WIRE_CHANNELD_LOCAL_CHANNEL_UPDATE: case WIRE_CHANNELD_LOCAL_CHANNEL_ANNOUNCEMENT: @@ -4036,10 +3907,8 @@ int main(int argc, char *argv[]) status_setup_sync(MASTER_FD); peer = tal(NULL, struct peer); - peer->expecting_pong = PONG_UNEXPECTED; timers_init(&peer->timers, time_mono()); peer->commit_timer = NULL; - set_ping_timer(peer); peer->have_sigs[LOCAL] = peer->have_sigs[REMOTE] = false; peer->announce_depth_reached = false; peer->channel_local_active = false; diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index 4770aea3d542..a444125ce069 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -266,14 +266,3 @@ msgdata,channeld_upgraded,new_type,channel_type, # Tell peer about our latest and greatest blockheight. msgtype,channeld_blockheight,1012 msgdata,channeld_blockheight,blockheight,u32, - -# Ping/pong test. Waits for a reply if it expects one. -msgtype,channeld_ping,1030 -msgdata,channeld_ping,num_pong_bytes,u16, -msgdata,channeld_ping,len,u16, - -msgtype,channeld_ping_reply,1130 -# False if we there was already a ping in progress. -msgdata,channeld_ping_reply,sent,bool, -# 0 == no pong expected, otherwise length of pong. -msgdata,channeld_ping_reply,totlen,u16, diff --git a/connectd/Makefile b/connectd/Makefile index fdf21e23e484..779a354a8c51 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -57,6 +57,7 @@ CONNECTD_COMMON_OBJS := \ common/msg_queue.o \ common/node_id.o \ common/onionreply.o \ + common/ping.o \ common/per_peer_state.o \ common/psbt_open.o \ common/pseudorand.o \ diff --git a/connectd/connectd.c b/connectd/connectd.c index bea4a0fc1358..b3cf27cbe25c 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1932,6 +1932,10 @@ static struct io_plan *recv_req(struct io_conn *conn, peer_final_msg(conn, daemon, msg); goto out; + case WIRE_CONNECTD_PING: + send_manual_ping(daemon, msg); + goto out; + case WIRE_CONNECTD_DEV_MEMLEAK: #if DEVELOPER dev_connect_memleak(daemon, msg); @@ -1944,6 +1948,7 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_CONNECTD_RECONNECTED: case WIRE_CONNECTD_CONNECT_FAILED: case WIRE_CONNECTD_DEV_MEMLEAK_REPLY: + case WIRE_CONNECTD_PING_REPLY: break; } diff --git a/connectd/connectd.h b/connectd/connectd.h index 5e697198d76a..93814efc5e3c 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -27,6 +27,16 @@ struct gossip_state { size_t off; }; +/*~ We need to know if we were expecting a pong, and why */ +enum pong_expect_type { + /* We weren't expecting a ping reply */ + PONG_UNEXPECTED = 0, + /* We were expecting a ping reply due to ping command */ + PONG_EXPECTED_COMMAND = 1, + /* We were expecting a ping reply due to ping timer */ + PONG_EXPECTED_PROBING = 2, +}; + /*~ We keep a hash table (ccan/htable) of peers, which tells us what peers are * already connected (by peer->id). */ struct peer { @@ -61,6 +71,12 @@ struct peer { /* We stream from the gossip_store for them, when idle */ struct gossip_state gs; + + /* Are we expecting a pong? */ + enum pong_expect_type expecting_pong; + + /* Random ping timer, to detect dead connections. */ + struct oneshot *ping_timer; }; /*~ The HTABLE_DEFINE_TYPE() macro needs a keyof() function to extract the key: diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index deee01f4f4a3..b3f8f5b175e1 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -82,3 +82,15 @@ msgtype,connectd_dev_memleak,2033 msgtype,connectd_dev_memleak_reply,2133 msgdata,connectd_dev_memleak_reply,leak,bool, + +# Ping/pong test. Waits for a reply if it expects one. +msgtype,connectd_ping,2030 +msgdata,connectd_ping,id,node_id, +msgdata,connectd_ping,num_pong_bytes,u16, +msgdata,connectd_ping,len,u16, + +msgtype,connectd_ping_reply,2130 +# False if we there was already a ping in progress. +msgdata,connectd_ping_reply,sent,bool, +# 0 == no pong expected, otherwise length of pong. +msgdata,connectd_ping_reply,totlen,u16, diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 9a69b9165a88..1ad4ff022d88 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -13,12 +13,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -316,34 +318,107 @@ static u8 *maybe_from_gossip_store(const tal_t *ctx, struct peer *peer) return NULL; } -/* We handle gossip_timestamp_filter, and divert other gossip msgs to gossipd */ -static bool handle_message_locally(struct peer *peer, const u8 *msg) +/* Mutual recursion */ +static void send_ping(struct peer *peer); + +static void set_ping_timer(struct peer *peer) +{ + peer->ping_timer = new_reltimer(&peer->daemon->timers, peer, + time_from_sec(15 + pseudorand(30)), + send_ping, peer); +} + +static void send_ping(struct peer *peer) +{ + /* Already have a ping in flight? */ + if (peer->expecting_pong != PONG_UNEXPECTED) { + status_peer_debug(&peer->id, "Last ping unreturned: hanging up"); + if (peer->to_peer) + io_close(peer->to_peer); + return; + } + + queue_peer_msg(peer, take(make_ping(NULL, 1, 0))); + peer->expecting_pong = PONG_EXPECTED_PROBING; + set_ping_timer(peer); +} + +static void handle_ping_in(struct peer *peer, const u8 *msg) +{ + u8 *pong; + + if (!check_ping_make_pong(NULL, msg, &pong)) { + send_warning(peer, "Invalid ping %s", tal_hex(msg, msg)); + return; + } + + if (pong) + queue_peer_msg(peer, take(pong)); +} + +static void handle_ping_reply(struct peer *peer, const u8 *msg) +{ + u8 *ignored; + size_t i; + + /* We print this out because we asked for pong, so can't spam us... */ + if (!fromwire_pong(msg, msg, &ignored)) + status_peer_unusual(&peer->id, "Got malformed ping reply %s", + tal_hex(tmpctx, msg)); + + /* We print this because dev versions of c-lightning embed + * version here: see check_ping_make_pong! */ + for (i = 0; i < tal_count(ignored); i++) { + if (ignored[i] < ' ' || ignored[i] == 127) + break; + } + status_debug("Got pong %zu bytes (%.*s...)", + tal_count(ignored), (int)i, (char *)ignored); + daemon_conn_send(peer->daemon->master, + take(towire_connectd_ping_reply(NULL, true, + tal_bytelen(msg)))); +} + +static void handle_pong_in(struct peer *peer, const u8 *msg) +{ + switch (peer->expecting_pong) { + case PONG_EXPECTED_COMMAND: + handle_ping_reply(peer, msg); + /* fall thru */ + case PONG_EXPECTED_PROBING: + peer->expecting_pong = PONG_UNEXPECTED; + return; + case PONG_UNEXPECTED: + status_debug("Unexpected pong?"); + return; + } + abort(); +} + +/* Forward to gossipd */ +static void handle_gossip_in(struct peer *peer, const u8 *msg) +{ + u8 *gmsg = towire_gossipd_recv_gossip(NULL, &peer->id, msg); + daemon_conn_send(peer->daemon->gossipd, take(gmsg)); +} + +static void handle_gossip_timetamp_filter_in(struct peer *peer, const u8 *msg) { struct bitcoin_blkid chain_hash; u32 first_timestamp, timestamp_range; - /* We remember these so we don't rexmit them */ - if (is_msg_gossip_broadcast(msg)) - gossip_rcvd_filter_add(peer->gs.grf, msg); - if (!fromwire_gossip_timestamp_filter(msg, &chain_hash, &first_timestamp, ×tamp_range)) { - /* Do we want to divert to gossipd? */ - if (is_msg_for_gossipd(msg)) { - u8 *gmsg = towire_gossipd_recv_gossip(NULL, - &peer->id, msg); - daemon_conn_send(peer->daemon->gossipd, take(gmsg)); - return true; - } - - return false; + send_warning(peer, "gossip_timestamp_filter invalid: %s", + tal_hex(tmpctx, msg)); + return; } if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain_hash)) { send_warning(peer, "gossip_timestamp_filter for bad chain: %s", tal_hex(tmpctx, msg)); - return true; + return; } peer->gs.timestamp_min = first_timestamp; @@ -360,8 +435,35 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg) /* We send immediately the first time, after that we wait. */ if (!peer->gs.gossip_timer) wake_gossip(peer); +} - return true; +/* We handle pings and gossip messages. */ +static bool handle_message_locally(struct peer *peer, const u8 *msg) +{ + enum peer_wire type = fromwire_peektype(msg); + + /* We remember these so we don't rexmit them */ + if (is_msg_gossip_broadcast(msg)) + gossip_rcvd_filter_add(peer->gs.grf, msg); + + if (type == WIRE_GOSSIP_TIMESTAMP_FILTER) { + handle_gossip_timetamp_filter_in(peer, msg); + return true; + } else if (type == WIRE_PING) { + handle_ping_in(peer, msg); + return true; + } else if (type == WIRE_PONG) { + handle_pong_in(peer, msg); + return true; + } + + /* Do we want to divert to gossipd? */ + if (is_msg_for_gossipd(msg)) { + handle_gossip_in(peer, msg); + return true; + } + + return false; } static struct io_plan *write_to_peer(struct io_conn *peer_conn, @@ -564,3 +666,66 @@ void multiplex_final_msg(struct peer *peer, const u8 *final_msg TAKES) if (!peer->to_subd) io_wake(peer->peer_outq); } + +/* Lightningd says to send a ping */ +void send_manual_ping(struct daemon *daemon, const u8 *msg) +{ + u8 *ping; + struct node_id id; + u16 len, num_pong_bytes; + struct peer *peer; + + if (!fromwire_connectd_ping(msg, &id, &num_pong_bytes, &len)) + master_badmsg(WIRE_CONNECTD_PING, msg); + + peer = peer_htable_get(&daemon->peers, &id); + if (!peer) { + daemon_conn_send(daemon->master, + take(towire_connectd_ping_reply(NULL, + false, 0))); + return; + } + + /* We're not supposed to send another ping until previous replied */ + if (peer->expecting_pong != PONG_UNEXPECTED) { + daemon_conn_send(daemon->master, + take(towire_connectd_ping_reply(NULL, + false, 0))); + return; + } + + /* It should never ask for an oversize ping. */ + ping = make_ping(NULL, num_pong_bytes, len); + if (tal_count(ping) > 65535) + status_failed(STATUS_FAIL_MASTER_IO, "Oversize ping"); + + queue_peer_msg(peer, take(ping)); + + status_debug("sending ping expecting %sresponse", + num_pong_bytes >= 65532 ? "no " : ""); + + /* BOLT #1: + * + * A node receiving a `ping` message: + *... + * - if `num_pong_bytes` is less than 65532: + * - MUST respond by sending a `pong` message, with `byteslen` equal + * to `num_pong_bytes`. + * - otherwise (`num_pong_bytes` is **not** less than 65532): + * - MUST ignore the `ping`. + */ + if (num_pong_bytes >= 65532) { + daemon_conn_send(daemon->master, + take(towire_connectd_ping_reply(NULL, + true, 0))); + return; + } + + /* We'll respond to lightningd once the pong comes in */ + peer->expecting_pong = PONG_EXPECTED_COMMAND; + + /* Since we're doing this manually, kill and restart timer. */ + tal_free(peer->ping_timer); + set_ping_timer(peer); +} + diff --git a/connectd/multiplex.h b/connectd/multiplex.h index 524e4829966a..3694c2b13d9c 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -27,4 +27,7 @@ void queue_peer_msg(struct peer *peer, const u8 *msg TAKES); void setup_peer_gossip_store(struct peer *peer, const struct feature_set *our_features, const u8 *their_features); + +/* When lightningd says to send a ping */ +void send_manual_ping(struct daemon *daemon, const u8 *msg); #endif /* LIGHTNING_CONNECTD_MULTIPLEX_H */ diff --git a/lightningd/Makefile b/lightningd/Makefile index 24c57250ae19..f9d4e7396cbf 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -30,7 +30,6 @@ LIGHTNINGD_SRC := \ lightningd/pay.c \ lightningd/peer_control.c \ lightningd/peer_htlcs.c \ - lightningd/ping.c \ lightningd/plugin.c \ lightningd/plugin_control.c \ lightningd/plugin_hook.c \ @@ -41,6 +40,7 @@ LIGHTNINGD_SRC := \ LIGHTNINGD_SRC_NOHDR := \ lightningd/datastore.c \ + lightningd/ping.c \ lightningd/offer.c \ lightningd/signmessage.c diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 7eb25409e5a7..a63775bb893c 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -21,7 +21,6 @@ #include #include #include -#include #include static void update_feerates(struct lightningd *ld, struct channel *channel) @@ -508,9 +507,6 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_SEND_ERROR_REPLY: handle_error_channel(sd->channel, msg); break; - case WIRE_CHANNELD_PING_REPLY: - ping_reply(sd, msg); - break; case WIRE_CHANNELD_USED_CHANNEL_UPDATE: /* This tells gossipd we used it. */ get_channel_update(sd->channel); @@ -554,7 +550,6 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_DEV_MEMLEAK_REPLY: case WIRE_CHANNELD_SEND_ERROR: case WIRE_CHANNELD_DEV_QUIESCE_REPLY: - case WIRE_CHANNELD_PING: break; } diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index d986fe8bb780..71a95459440d 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -366,10 +366,12 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_PEER_DISCONNECTED: case WIRE_CONNECTD_DEV_MEMLEAK: case WIRE_CONNECTD_PEER_FINAL_MSG: + case WIRE_CONNECTD_PING: /* This is a reply, so never gets through to here. */ case WIRE_CONNECTD_INIT_REPLY: case WIRE_CONNECTD_ACTIVATE_REPLY: case WIRE_CONNECTD_DEV_MEMLEAK_REPLY: + case WIRE_CONNECTD_PING_REPLY: break; case WIRE_CONNECTD_RECONNECTED: diff --git a/lightningd/ping.c b/lightningd/ping.c index e97351595ae7..144dbe8fac47 100644 --- a/lightningd/ping.c +++ b/lightningd/ping.c @@ -1,83 +1,39 @@ #include "config.h" -#include #include #include #include +#include #include #include #include #include -#include #include -struct ping_command { - struct list_node list; - struct node_id id; - struct command *cmd; -}; - -static struct ping_command *find_ping_cmd(struct lightningd *ld, - const struct node_id *id) -{ - struct ping_command *i; - - list_for_each(&ld->ping_commands, i, list) { - if (node_id_eq(id, &i->id)) - return i; - } - return NULL; -} - -static void destroy_ping_command(struct ping_command *pc) -{ - list_del(&pc->list); -} - -static struct ping_command *new_ping_command(const tal_t *ctx, - struct lightningd *ld, - const struct node_id *peer_id, - struct command *cmd) -{ - struct ping_command *pc = tal(ctx, struct ping_command); - - pc->id = *peer_id; - pc->cmd = cmd; - list_add_tail(&ld->ping_commands, &pc->list); - tal_add_destructor(pc, destroy_ping_command); - - return pc; -} - -void ping_reply(struct subd *channeld, const u8 *msg) +static void ping_reply(struct subd *connectd, + const u8 *msg, const int *fds, + struct command *cmd) { u16 totlen; bool sent; - struct ping_command *pc; - struct channel *c = channeld->channel; - log_debug(channeld->log, "Got ping reply!"); - pc = find_ping_cmd(channeld->ld, &c->peer->id); - if (!pc) { - log_broken(channeld->log, "Unexpected ping reply?"); - return; - } + log_debug(connectd->log, "Got ping reply!"); - if (!fromwire_channeld_ping_reply(msg, &sent, &totlen)) { - log_broken(channeld->log, "Malformed ping reply %s", + if (!fromwire_connectd_ping_reply(msg, &sent, &totlen)) { + log_broken(connectd->log, "Malformed ping reply %s", tal_hex(tmpctx, msg)); - was_pending(command_fail(pc->cmd, LIGHTNINGD, + was_pending(command_fail(cmd, LIGHTNINGD, "Bad reply message")); return; } if (!sent) - was_pending(command_fail(pc->cmd, LIGHTNINGD, + was_pending(command_fail(cmd, LIGHTNINGD, "Ping already pending")); else { - struct json_stream *response = json_stream_success(pc->cmd); + struct json_stream *response = json_stream_success(cmd); json_add_num(response, "totlen", totlen); - was_pending(command_success(pc->cmd, response)); + was_pending(command_success(cmd, response)); } } @@ -88,8 +44,6 @@ static struct command_result *json_ping(struct command *cmd, { unsigned int *len, *pongbytes; struct node_id *id; - struct peer *peer; - struct channel *channel; u8 *msg; if (!param(cmd, buffer, params, @@ -124,19 +78,11 @@ static struct command_result *json_ping(struct command *cmd, "pongbytes %u > 65535", *pongbytes); } - peer = peer_by_id(cmd->ld, id); - if (!peer) + if (!peer_by_id(cmd->ld, id)) return command_fail(cmd, LIGHTNINGD, "Peer not connected"); - channel = peer_active_channel(peer); - if (!channel || !channel->owner || channel->state != CHANNELD_NORMAL) - return command_fail(cmd, LIGHTNINGD, "Peer bad state"); - - /* parent is cmd, so when we complete cmd, we free this. */ - new_ping_command(cmd, cmd->ld, id, cmd); - - msg = towire_channeld_ping(NULL, *pongbytes, *len); - subd_send_msg(channel->owner, take(msg)); + msg = towire_connectd_ping(NULL, id, *pongbytes, *len); + subd_req(cmd, cmd->ld->connectd, take(msg), -1, 0, ping_reply, cmd); return command_still_pending(cmd); } diff --git a/lightningd/ping.h b/lightningd/ping.h deleted file mode 100644 index fec5c90ee242..000000000000 --- a/lightningd/ping.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef LIGHTNING_LIGHTNINGD_PING_H -#define LIGHTNING_LIGHTNINGD_PING_H -#include "config.h" -#include - -struct subd; -void ping_reply(struct subd *subd, const u8 *msg); - -#endif /* LIGHTNING_LIGHTNINGD_PING_H */ From 23ca389b9fb492572290990d61fed3b9e49113ec Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 44/51] connectd: handle onion messages. Signed-off-by: Rusty Russell --- connectd/Makefile | 6 + connectd/connectd.c | 6 + connectd/connectd_wire.csv | 22 ++ connectd/multiplex.c | 7 + connectd/onion_message.c | 345 ++++++++++++++++++ connectd/onion_message.h | 15 + connectd/test/run-onion_message.c | 488 +++++++++++++++++++++++++ gossipd/Makefile | 6 - gossipd/gossipd.c | 356 +----------------- gossipd/gossipd_wire.csv | 19 - gossipd/test/run-onion_message.c | 585 ------------------------------ lightningd/connect_control.c | 6 + lightningd/gossip_control.c | 5 - lightningd/onion_message.c | 12 +- wire/peer_wire.c | 4 +- 15 files changed, 907 insertions(+), 975 deletions(-) create mode 100644 connectd/onion_message.c create mode 100644 connectd/onion_message.h create mode 100644 connectd/test/run-onion_message.c delete mode 100644 gossipd/test/run-onion_message.c diff --git a/connectd/Makefile b/connectd/Makefile index 779a354a8c51..8b1ea8907606 100644 --- a/connectd/Makefile +++ b/connectd/Makefile @@ -7,6 +7,7 @@ CONNECTD_HEADERS := connectd/connectd_wiregen.h \ connectd/handshake.h \ connectd/multiplex.h \ connectd/netaddress.h \ + connectd/onion_message.h \ connectd/tor_autoservice.h \ connectd/tor.h @@ -41,6 +42,8 @@ CONNECTD_COMMON_OBJS := \ common/bech32_util.o \ common/bigsize.o \ common/bip32.o \ + common/blinding.o \ + common/blindedpath.o \ common/channel_id.o \ common/cryptomsg.o \ common/daemon.o \ @@ -49,6 +52,7 @@ CONNECTD_COMMON_OBJS := \ common/dev_disconnect.o \ common/ecdh_hsmd.o \ common/features.o \ + common/hmac.o \ common/status_wiregen.o \ common/gossip_store.o \ common/gossip_rcvd_filter.o \ @@ -56,12 +60,14 @@ CONNECTD_COMMON_OBJS := \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ + common/onion.o \ common/onionreply.o \ common/ping.o \ common/per_peer_state.o \ common/psbt_open.o \ common/pseudorand.o \ common/setup.o \ + common/sphinx.o \ common/status.o \ common/status_wire.o \ common/subdaemon.o \ diff --git a/connectd/connectd.c b/connectd/connectd.c index b3cf27cbe25c..2f7ce123dd48 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1936,6 +1937,10 @@ static struct io_plan *recv_req(struct io_conn *conn, send_manual_ping(daemon, msg); goto out; + case WIRE_CONNECTD_SEND_ONIONMSG: + onionmsg_req(daemon, msg); + goto out; + case WIRE_CONNECTD_DEV_MEMLEAK: #if DEVELOPER dev_connect_memleak(daemon, msg); @@ -1949,6 +1954,7 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_CONNECTD_CONNECT_FAILED: case WIRE_CONNECTD_DEV_MEMLEAK_REPLY: case WIRE_CONNECTD_PING_REPLY: + case WIRE_CONNECTD_GOT_ONIONMSG_TO_US: break; } diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index b3f8f5b175e1..52dae09d0c54 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -3,6 +3,7 @@ #include #include #include +#include msgtype,connectd_init,2000 msgdata,connectd_init,chainparams,chainparams, @@ -94,3 +95,24 @@ msgtype,connectd_ping_reply,2130 msgdata,connectd_ping_reply,sent,bool, # 0 == no pong expected, otherwise length of pong. msgdata,connectd_ping_reply,totlen,u16, + +# We tell lightningd we got an onionmsg +msgtype,connectd_got_onionmsg_to_us,2145 +msgdata,connectd_got_onionmsg_to_us,obs2,bool, +msgdata,connectd_got_onionmsg_to_us,node_alias,pubkey, +msgdata,connectd_got_onionmsg_to_us,self_id,?secret, +msgdata,connectd_got_onionmsg_to_us,reply_blinding,?pubkey, +msgdata,connectd_got_onionmsg_to_us,reply_first_node,?pubkey, +msgdata,connectd_got_onionmsg_to_us,reply_path_len,u16, +msgdata,connectd_got_onionmsg_to_us,reply_path,onionmsg_path,reply_path_len +msgdata,connectd_got_onionmsg_to_us,rawmsg_len,u16, +msgdata,connectd_got_onionmsg_to_us,rawmsg,u8,rawmsg_len + +# Lightningd tells us to send an onion message. +msgtype,connectd_send_onionmsg,2041 +msgdata,connectd_send_onionmsg,obs2,bool, +msgdata,connectd_send_onionmsg,id,node_id, +msgdata,connectd_send_onionmsg,onion_len,u16, +msgdata,connectd_send_onionmsg,onion,u8,onion_len +msgdata,connectd_send_onionmsg,blinding,pubkey, + diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 1ad4ff022d88..06e7cf050f8c 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -455,6 +456,12 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg) } else if (type == WIRE_PONG) { handle_pong_in(peer, msg); return true; + } else if (type == WIRE_OBS2_ONION_MESSAGE) { + handle_obs2_onion_message(peer->daemon, peer, msg); + return true; + } else if (type == WIRE_ONION_MESSAGE) { + handle_onion_message(peer->daemon, peer, msg); + return true; } /* Do we want to divert to gossipd? */ diff --git a/connectd/onion_message.c b/connectd/onion_message.c new file mode 100644 index 000000000000..f19594899172 --- /dev/null +++ b/connectd/onion_message.c @@ -0,0 +1,345 @@ +/*~ This contains all the code to handle onion messages. */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Peer sends obsolete onion msg. */ +void handle_obs2_onion_message(struct daemon *daemon, + struct peer *peer, const u8 *msg) +{ + enum onion_wire badreason; + struct onionpacket *op; + struct pubkey blinding, ephemeral; + struct route_step *rs; + u8 *onion; + struct tlv_obs2_onionmsg_payload *om; + struct secret ss, onion_ss; + const u8 *cursor; + size_t max, maxlen; + + /* Ignore unless explicitly turned on. */ + if (!feature_offered(daemon->our_features->bits[NODE_ANNOUNCE_FEATURE], + OPT_ONION_MESSAGES)) + return; + + /* FIXME: ratelimit! */ + if (!fromwire_obs2_onion_message(msg, msg, &blinding, &onion)) { + queue_peer_msg(peer, + towire_warningfmt(NULL, NULL, + "Bad onion_message")); + return; + } + + /* We unwrap the onion now. */ + op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason); + if (!op) { + status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s", + onion_wire_name(badreason)); + return; + } + + ephemeral = op->ephemeralkey; + if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) { + status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket"); + return; + } + + /* Now get onion shared secret and parse it. */ + ecdh(&ephemeral, &onion_ss); + rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); + if (!rs) { + status_peer_debug(&peer->id, + "onion msg: can't process onionpacket ss=%s", + type_to_string(tmpctx, struct secret, &onion_ss)); + return; + } + + /* The raw payload is prepended with length in the modern onion. */ + cursor = rs->raw_payload; + max = tal_bytelen(rs->raw_payload); + maxlen = fromwire_bigsize(&cursor, &max); + if (!cursor) { + status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + if (maxlen > max) { + status_peer_debug(&peer->id, "onion msg: overlong hop payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + + om = tlv_obs2_onionmsg_payload_new(msg); + if (!fromwire_obs2_onionmsg_payload(&cursor, &maxlen, om)) { + status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + + if (rs->nextcase == ONION_END) { + struct pubkey *reply_blinding, *first_node_id, me, alias; + const struct onionmsg_path **reply_path; + struct secret *self_id; + u8 *omsg; + + if (!pubkey_from_node_id(&me, &daemon->id)) { + status_broken("Failed to convert own id"); + return; + } + + /* Final enctlv is actually optional */ + if (!om->enctlv) { + alias = me; + self_id = NULL; + } else if (!decrypt_obs2_final_enctlv(tmpctx, &blinding, &ss, + om->enctlv, &me, &alias, + &self_id)) { + status_peer_debug(&peer->id, + "onion msg: failed to decrypt enctlv" + " %s", tal_hex(tmpctx, om->enctlv)); + return; + } + + if (om->reply_path) { + first_node_id = &om->reply_path->first_node_id; + reply_blinding = &om->reply_path->blinding; + reply_path = cast_const2(const struct onionmsg_path **, + om->reply_path->path); + } else { + first_node_id = NULL; + reply_blinding = NULL; + reply_path = NULL; + } + + /* We re-marshall here by policy, before handing to lightningd */ + omsg = tal_arr(tmpctx, u8, 0); + towire_tlvstream_raw(&omsg, om->fields); + daemon_conn_send(daemon->master, + take(towire_connectd_got_onionmsg_to_us(NULL, + true, /* obs2 */ + &alias, self_id, + reply_blinding, + first_node_id, + reply_path, + omsg))); + } else { + struct pubkey next_node, next_blinding; + struct peer *next_peer; + struct node_id next_node_id; + + /* This fails as expected if no enctlv. */ + if (!decrypt_obs2_enctlv(&blinding, &ss, om->enctlv, &next_node, + &next_blinding)) { + status_peer_debug(&peer->id, + "onion msg: invalid enctlv %s", + tal_hex(tmpctx, om->enctlv)); + return; + } + + /* Even though lightningd checks for valid ids, there's a race + * where it might vanish before we read this command. */ + node_id_from_pubkey(&next_node_id, &next_node); + next_peer = peer_htable_get(&daemon->peers, &next_node_id); + if (!next_peer) { + status_peer_debug(&peer->id, + "onion msg: unknown next peer %s", + type_to_string(tmpctx, + struct pubkey, + &next_node)); + return; + } + queue_peer_msg(next_peer, + take(towire_obs2_onion_message(NULL, + &next_blinding, + serialize_onionpacket(tmpctx, rs->next)))); + } +} + +void onionmsg_req(struct daemon *daemon, const u8 *msg) +{ + struct node_id id; + u8 *onionmsg; + struct pubkey blinding; + struct peer *peer; + bool obs2; + + if (!fromwire_connectd_send_onionmsg(msg, msg, &obs2, &id, &onionmsg, &blinding)) + master_badmsg(WIRE_CONNECTD_SEND_ONIONMSG, msg); + + /* Even though lightningd checks for valid ids, there's a race + * where it might vanish before we read this command. */ + peer = peer_htable_get(&daemon->peers, &id); + if (peer) { + u8 *omsg; + if (obs2) + omsg = towire_obs2_onion_message(NULL, &blinding, onionmsg); + else + omsg = towire_onion_message(NULL, &blinding, onionmsg); + queue_peer_msg(peer, take(omsg)); + } +} + +/* Peer sends an onion msg. */ +void handle_onion_message(struct daemon *daemon, + struct peer *peer, const u8 *msg) +{ + enum onion_wire badreason; + struct onionpacket *op; + struct pubkey blinding, ephemeral; + struct route_step *rs; + u8 *onion; + struct tlv_onionmsg_payload *om; + struct secret ss, onion_ss; + const u8 *cursor; + size_t max, maxlen; + + /* Ignore unless explicitly turned on. */ + if (!feature_offered(daemon->our_features->bits[NODE_ANNOUNCE_FEATURE], + OPT_ONION_MESSAGES)) + return; + + /* FIXME: ratelimit! */ + if (!fromwire_onion_message(msg, msg, &blinding, &onion)) { + queue_peer_msg(peer, + towire_warningfmt(NULL, NULL, + "Bad onion_message")); + return; + } + + /* We unwrap the onion now. */ + op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason); + if (!op) { + status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s", + onion_wire_name(badreason)); + return; + } + + ephemeral = op->ephemeralkey; + if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) { + status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket"); + return; + } + + /* Now get onion shared secret and parse it. */ + ecdh(&ephemeral, &onion_ss); + rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); + if (!rs) { + status_peer_debug(&peer->id, + "onion msg: can't process onionpacket ss=%s", + type_to_string(tmpctx, struct secret, &onion_ss)); + return; + } + + /* The raw payload is prepended with length in the modern onion. */ + cursor = rs->raw_payload; + max = tal_bytelen(rs->raw_payload); + maxlen = fromwire_bigsize(&cursor, &max); + if (!cursor) { + status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + if (maxlen > max) { + status_peer_debug(&peer->id, "onion msg: overlong hop payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + + om = tlv_onionmsg_payload_new(msg); + if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) { + status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s", + tal_hex(tmpctx, rs->raw_payload)); + return; + } + + if (rs->nextcase == ONION_END) { + struct pubkey *reply_blinding, *first_node_id, me, alias; + const struct onionmsg_path **reply_path; + struct secret *self_id; + u8 *omsg; + + if (!pubkey_from_node_id(&me, &daemon->id)) { + status_broken("Failed to convert own id"); + return; + } + + /* Final enctlv is actually optional */ + if (!om->encrypted_data_tlv) { + alias = me; + self_id = NULL; + } else if (!decrypt_final_enctlv(tmpctx, &blinding, &ss, + om->encrypted_data_tlv, &me, &alias, + &self_id)) { + status_peer_debug(&peer->id, + "onion msg: failed to decrypt enctlv" + " %s", tal_hex(tmpctx, om->encrypted_data_tlv)); + return; + } + + if (om->reply_path) { + first_node_id = &om->reply_path->first_node_id; + reply_blinding = &om->reply_path->blinding; + reply_path = cast_const2(const struct onionmsg_path **, + om->reply_path->path); + } else { + first_node_id = NULL; + reply_blinding = NULL; + reply_path = NULL; + } + + /* We re-marshall here by policy, before handing to lightningd */ + omsg = tal_arr(tmpctx, u8, 0); + towire_tlvstream_raw(&omsg, om->fields); + daemon_conn_send(daemon->master, + take(towire_connectd_got_onionmsg_to_us(NULL, + false, /* !obs2 */ + &alias, self_id, + reply_blinding, + first_node_id, + reply_path, + omsg))); + } else { + struct pubkey next_node, next_blinding; + struct peer *next_peer; + struct node_id next_node_id; + + /* This fails as expected if no enctlv. */ + if (!decrypt_enctlv(&blinding, &ss, om->encrypted_data_tlv, &next_node, + &next_blinding)) { + status_peer_debug(&peer->id, + "onion msg: invalid enctlv %s", + tal_hex(tmpctx, om->encrypted_data_tlv)); + return; + } + + /* FIXME: Handle short_channel_id! */ + node_id_from_pubkey(&next_node_id, &next_node); + next_peer = peer_htable_get(&daemon->peers, &next_node_id); + if (!next_peer) { + status_peer_debug(&peer->id, + "onion msg: unknown next peer %s", + type_to_string(tmpctx, + struct pubkey, + &next_node)); + return; + } + queue_peer_msg(next_peer, + take(towire_onion_message(NULL, + &next_blinding, + serialize_onionpacket(tmpctx, rs->next)))); + } +} + diff --git a/connectd/onion_message.h b/connectd/onion_message.h new file mode 100644 index 000000000000..22fc9bb8b4a4 --- /dev/null +++ b/connectd/onion_message.h @@ -0,0 +1,15 @@ +#ifndef LIGHTNING_CONNECTD_ONION_MESSAGE_H +#define LIGHTNING_CONNECTD_ONION_MESSAGE_H +#include "config.h" +#include + +/* Various messages come in from peer */ +void handle_obs2_onion_message(struct daemon *daemon, + struct peer *peer, const u8 *msg); +void handle_onion_message(struct daemon *daemon, + struct peer *peer, const u8 *msg); + +/* Lightningd tells us to send an onion message */ +void onionmsg_req(struct daemon *daemon, const u8 *msg); + +#endif /* LIGHTNING_CONNECTD_ONION_MESSAGE_H */ diff --git a/connectd/test/run-onion_message.c b/connectd/test/run-onion_message.c new file mode 100644 index 000000000000..ab00545a8c19 --- /dev/null +++ b/connectd/test/run-onion_message.c @@ -0,0 +1,488 @@ +#include "config.h" +#include "../onion_message.c" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* AUTOGENERATED MOCKS START */ +/* Generated stub for amount_asset_is_main */ +bool amount_asset_is_main(struct amount_asset *asset UNNEEDED) +{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); } +/* Generated stub for amount_asset_to_sat */ +struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED) +{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); } +/* Generated stub for amount_sat */ +struct amount_sat amount_sat(u64 satoshis UNNEEDED) +{ fprintf(stderr, "amount_sat called!\n"); abort(); } +/* Generated stub for amount_sat_add */ + bool amount_sat_add(struct amount_sat *val UNNEEDED, + struct amount_sat a UNNEEDED, + struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_add called!\n"); abort(); } +/* Generated stub for amount_sat_eq */ +bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); } +/* Generated stub for amount_sat_greater_eq */ +bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); } +/* Generated stub for amount_sat_sub */ + bool amount_sat_sub(struct amount_sat *val UNNEEDED, + struct amount_sat a UNNEEDED, + struct amount_sat b UNNEEDED) +{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); } +/* Generated stub for amount_sat_to_asset */ +struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u8 *asset UNNEEDED) +{ fprintf(stderr, "amount_sat_to_asset called!\n"); abort(); } +/* Generated stub for amount_tx_fee */ +struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED) +{ fprintf(stderr, "amount_tx_fee 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 decrypt_enctlv */ +bool decrypt_enctlv(const struct pubkey *blinding UNNEEDED, + const struct secret *ss UNNEEDED, + const u8 *enctlv UNNEEDED, + struct pubkey *next_node UNNEEDED, + struct pubkey *next_blinding) + +{ fprintf(stderr, "decrypt_enctlv called!\n"); abort(); } +/* Generated stub for decrypt_final_enctlv */ +bool decrypt_final_enctlv(const tal_t *ctx UNNEEDED, + const struct pubkey *blinding UNNEEDED, + const struct secret *ss UNNEEDED, + const u8 *enctlv UNNEEDED, + const struct pubkey *my_id UNNEEDED, + struct pubkey *alias UNNEEDED, + struct secret **path_id) + +{ fprintf(stderr, "decrypt_final_enctlv called!\n"); abort(); } +/* Generated stub for decrypt_obs2_enctlv */ +bool decrypt_obs2_enctlv(const struct pubkey *blinding UNNEEDED, + const struct secret *ss UNNEEDED, + const u8 *enctlv UNNEEDED, + struct pubkey *next_node UNNEEDED, + struct pubkey *next_blinding) + +{ fprintf(stderr, "decrypt_obs2_enctlv called!\n"); abort(); } +/* Generated stub for decrypt_obs2_final_enctlv */ +bool decrypt_obs2_final_enctlv(const tal_t *ctx UNNEEDED, + const struct pubkey *blinding UNNEEDED, + const struct secret *ss UNNEEDED, + const u8 *enctlv UNNEEDED, + const struct pubkey *my_id UNNEEDED, + struct pubkey *alias UNNEEDED, + struct secret **self_id) + +{ fprintf(stderr, "decrypt_obs2_final_enctlv called!\n"); abort(); } +/* Generated stub for ecdh */ +void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) +{ fprintf(stderr, "ecdh called!\n"); abort(); } +/* Generated stub for fromwire */ +const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED) +{ fprintf(stderr, "fromwire called!\n"); abort(); } +/* Generated stub for fromwire_bigsize */ +bigsize_t fromwire_bigsize(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_bigsize called!\n"); abort(); } +/* Generated stub for fromwire_bool */ +bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_bool called!\n"); abort(); } +/* Generated stub for fromwire_connectd_send_onionmsg */ +bool fromwire_connectd_send_onionmsg(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *obs2 UNNEEDED, struct node_id *id UNNEEDED, u8 **onion UNNEEDED, struct pubkey *blinding UNNEEDED) +{ fprintf(stderr, "fromwire_connectd_send_onionmsg called!\n"); abort(); } +/* Generated stub for fromwire_fail */ +void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_fail called!\n"); abort(); } +/* Generated stub for fromwire_obs2_onion_message */ +bool fromwire_obs2_onion_message(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *blinding UNNEEDED, u8 **onionmsg UNNEEDED) +{ fprintf(stderr, "fromwire_obs2_onion_message called!\n"); abort(); } +/* Generated stub for fromwire_obs2_onionmsg_payload */ +bool fromwire_obs2_onionmsg_payload(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, + struct tlv_obs2_onionmsg_payload * record UNNEEDED) +{ fprintf(stderr, "fromwire_obs2_onionmsg_payload called!\n"); abort(); } +/* Generated stub for fromwire_onion_message */ +bool fromwire_onion_message(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *blinding UNNEEDED, u8 **onionmsg UNNEEDED) +{ fprintf(stderr, "fromwire_onion_message called!\n"); abort(); } +/* Generated stub for fromwire_onionmsg_payload */ +bool fromwire_onionmsg_payload(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, + struct tlv_onionmsg_payload * record UNNEEDED) +{ fprintf(stderr, "fromwire_onionmsg_payload called!\n"); abort(); } +/* Generated stub for fromwire_secp256k1_ecdsa_signature */ +void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, + secp256k1_ecdsa_signature *signature UNNEEDED) +{ fprintf(stderr, "fromwire_secp256k1_ecdsa_signature called!\n"); abort(); } +/* Generated stub for fromwire_sha256 */ +void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED) +{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); } +/* Generated stub for fromwire_tal_arrn */ +u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED, + const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); } +/* Generated stub for fromwire_u16 */ +u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); } +/* Generated stub for fromwire_u32 */ +u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); } +/* Generated stub for fromwire_u64 */ +u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for fromwire_u8 */ +u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); } +/* Generated stub for fromwire_u8_array */ +void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); } +/* Generated stub for master_badmsg */ +void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) +{ fprintf(stderr, "master_badmsg called!\n"); abort(); } +/* Generated stub for node_id_from_pubkey */ +void node_id_from_pubkey(struct node_id *id UNNEEDED, const struct pubkey *key UNNEEDED) +{ fprintf(stderr, "node_id_from_pubkey called!\n"); abort(); } +/* Generated stub for onion_wire_name */ +const char *onion_wire_name(int e UNNEEDED) +{ fprintf(stderr, "onion_wire_name called!\n"); abort(); } +/* Generated stub for parse_onionpacket */ +struct onionpacket *parse_onionpacket(const tal_t *ctx UNNEEDED, + const u8 *src UNNEEDED, + const size_t srclen UNNEEDED, + enum onion_wire *failcode UNNEEDED) +{ fprintf(stderr, "parse_onionpacket called!\n"); abort(); } +/* Generated stub for process_onionpacket */ +struct route_step *process_onionpacket( + const tal_t * ctx UNNEEDED, + const struct onionpacket *packet UNNEEDED, + const struct secret *shared_secret UNNEEDED, + const u8 *assocdata UNNEEDED, + const size_t assocdatalen UNNEEDED, + bool has_realm + ) +{ fprintf(stderr, "process_onionpacket called!\n"); abort(); } +/* Generated stub for pubkey_from_node_id */ +bool pubkey_from_node_id(struct pubkey *key UNNEEDED, const struct node_id *id UNNEEDED) +{ fprintf(stderr, "pubkey_from_node_id called!\n"); abort(); } +/* Generated stub for queue_peer_msg */ +void queue_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) +{ fprintf(stderr, "queue_peer_msg called!\n"); abort(); } +/* Generated stub for serialize_onionpacket */ +u8 *serialize_onionpacket( + const tal_t *ctx UNNEEDED, + const struct onionpacket *packet UNNEEDED) +{ fprintf(stderr, "serialize_onionpacket 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 subkey_from_hmac */ +void subkey_from_hmac(const char *prefix UNNEEDED, + const struct secret *base UNNEEDED, + struct secret *key UNNEEDED) +{ fprintf(stderr, "subkey_from_hmac called!\n"); abort(); } +/* Generated stub for tlv_obs2_onionmsg_payload_new */ +struct tlv_obs2_onionmsg_payload *tlv_obs2_onionmsg_payload_new(const tal_t *ctx UNNEEDED) +{ fprintf(stderr, "tlv_obs2_onionmsg_payload_new called!\n"); abort(); } +/* Generated stub for tlv_onionmsg_payload_new */ +struct tlv_onionmsg_payload *tlv_onionmsg_payload_new(const tal_t *ctx UNNEEDED) +{ fprintf(stderr, "tlv_onionmsg_payload_new called!\n"); abort(); } +/* Generated stub for towire */ +void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "towire called!\n"); abort(); } +/* Generated stub for towire_bool */ +void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED) +{ fprintf(stderr, "towire_bool called!\n"); abort(); } +/* Generated stub for towire_connectd_got_onionmsg_to_us */ +u8 *towire_connectd_got_onionmsg_to_us(const tal_t *ctx UNNEEDED, bool obs2 UNNEEDED, const struct pubkey *node_alias UNNEEDED, const struct secret *self_id UNNEEDED, const struct pubkey *reply_blinding UNNEEDED, const struct pubkey *reply_first_node UNNEEDED, const struct onionmsg_path **reply_path UNNEEDED, const u8 *rawmsg UNNEEDED) +{ fprintf(stderr, "towire_connectd_got_onionmsg_to_us called!\n"); abort(); } +/* Generated stub for towire_obs2_onion_message */ +u8 *towire_obs2_onion_message(const tal_t *ctx UNNEEDED, const struct pubkey *blinding UNNEEDED, const u8 *onionmsg UNNEEDED) +{ fprintf(stderr, "towire_obs2_onion_message called!\n"); abort(); } +/* Generated stub for towire_onion_message */ +u8 *towire_onion_message(const tal_t *ctx UNNEEDED, const struct pubkey *blinding UNNEEDED, const u8 *onionmsg UNNEEDED) +{ fprintf(stderr, "towire_onion_message called!\n"); abort(); } +/* Generated stub for towire_secp256k1_ecdsa_signature */ +void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED, + const secp256k1_ecdsa_signature *signature UNNEEDED) +{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); } +/* Generated stub for towire_sha256 */ +void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED) +{ fprintf(stderr, "towire_sha256 called!\n"); abort(); } +/* Generated stub for towire_tlvstream_raw */ +void towire_tlvstream_raw(u8 **pptr UNNEEDED, struct tlv_field *fields UNNEEDED) +{ fprintf(stderr, "towire_tlvstream_raw called!\n"); abort(); } +/* Generated stub for towire_u16 */ +void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) +{ fprintf(stderr, "towire_u16 called!\n"); abort(); } +/* Generated stub for towire_u32 */ +void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) +{ fprintf(stderr, "towire_u32 called!\n"); abort(); } +/* Generated stub for towire_u64 */ +void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) +{ fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u8 */ +void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) +{ fprintf(stderr, "towire_u8 called!\n"); abort(); } +/* Generated stub for towire_u8_array */ +void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_u8_array called!\n"); abort(); } +/* Generated stub for towire_warningfmt */ +u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, + const struct channel_id *channel UNNEEDED, + const char *fmt UNNEEDED, ...) +{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); } +/* Generated stub for unblind_onion */ +bool unblind_onion(const struct pubkey *blinding UNNEEDED, + void (*ecdh)(const struct pubkey *point UNNEEDED, struct secret *ss) UNNEEDED, + struct pubkey *onion_key UNNEEDED, + struct secret *ss) + +{ fprintf(stderr, "unblind_onion called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +/* Updated each time, as we pretend to be Alice, Bob, Carol */ +static const struct privkey *mykey; + +static void test_ecdh(const struct pubkey *point, struct secret *ss) +{ + if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey, + mykey->secret.data, NULL, NULL) != 1) + abort(); +} + +static void json_strfield(const char *name, const char *val) +{ + printf("\t\"%s\": \"%s\",\n", name, val); +} + +static void json_onionmsg_payload(const struct tlv_obs2_onionmsg_payload *om) +{ + if (om->reply_path) { + printf("\t\"reply_path\": {\n"); + json_strfield("first_node_id", + type_to_string(tmpctx, struct pubkey, + &om->reply_path->first_node_id)); + json_strfield("blinding", + type_to_string(tmpctx, struct pubkey, + &om->reply_path->blinding)); + printf("\t\"path\": [\n"); + for (size_t i = 0; i < tal_count(om->reply_path->path); i++) { + json_strfield("node_id", + type_to_string(tmpctx, struct pubkey, + &om->reply_path->path[i]->node_id)); + json_strfield("encrypted_recipient_data", + tal_hex(tmpctx, + om->reply_path->path[i]->encrypted_recipient_data)); + } + printf("]}\n"); + } + if (om->invoice) + json_strfield("invoice", tal_hex(tmpctx, om->invoice)); + if (om->invoice_request) + json_strfield("invoice_request", + tal_hex(tmpctx, om->invoice_request)); + if (om->invoice_error) + json_strfield("invoice_error", + tal_hex(tmpctx, om->invoice_error)); +} + +/* Return next onion (and updates blinding), or NULL */ +static u8 *json_test(const char *testname, + const u8 *data, + const struct privkey *me, + const struct privkey *blinding_priv, + struct pubkey *blinding) +{ + struct pubkey my_id, next_node; + struct secret ss, onion_ss; + struct pubkey ephemeral; + struct route_step *rs; + const u8 *cursor; + size_t max, maxlen; + struct onionpacket *op; + struct tlv_obs2_onionmsg_payload *om; + + op = parse_onionpacket(tmpctx, data, tal_bytelen(data), NULL); + assert(op); + + pubkey_from_privkey(me, &my_id); + printf("{"); + json_strfield("test name", testname); + json_strfield("reader_privkey", + type_to_string(tmpctx, struct privkey, me)); + json_strfield("reader_id", + type_to_string(tmpctx, struct pubkey, &my_id)); + + if (blinding_priv) + json_strfield("blinding_privkey", + type_to_string(tmpctx, struct privkey, + blinding_priv)); + json_strfield("blinding", + type_to_string(tmpctx, struct pubkey, blinding)); + printf("\"onionmsg\": {\n"); + json_strfield("raw", tal_hex(tmpctx, data)); + json_strfield("version", tal_fmt(tmpctx, "%i", op->version)); + json_strfield("public_key", + type_to_string(tmpctx, struct pubkey, &op->ephemeralkey)); + json_strfield("hop_payloads", + tal_hex(tmpctx, op->routinginfo)); + json_strfield("hmac", + tal_hexstr(tmpctx, &op->hmac, sizeof(op->hmac))); + printf("},\n"); + + ephemeral = op->ephemeralkey; + + /* Set this for test_ecdh */ + mykey = me; + assert(unblind_onion(blinding, test_ecdh, &ephemeral, &ss)); + json_strfield("ECDH shared secret", + type_to_string(tmpctx, struct secret, &ss)); + /* Reproduce internal calc from unblind_onion */ + { + struct secret hmac; + subkey_from_hmac("blinded_node_id", &ss, &hmac); + json_strfield("HMAC256(\\\"blinded_node_id\\\", ss(i)) * k(i)", + type_to_string(tmpctx, struct secret, &hmac)); + } + json_strfield("Tweaked onion pubkey", + type_to_string(tmpctx, struct pubkey, &ephemeral)); + + /* Now get onion shared secret and parse it. */ + test_ecdh(&ephemeral, &onion_ss); + json_strfield("onion shared secret", + type_to_string(tmpctx, struct secret, &onion_ss)); + rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); + assert(rs); + + printf("\"onion contents\": {\n"); + json_strfield("raw", tal_hex(tmpctx, rs->raw_payload)); + + cursor = rs->raw_payload; + max = tal_bytelen(rs->raw_payload); + maxlen = fromwire_bigsize(&cursor, &max); + json_strfield("length", tal_fmt(tmpctx, "%zu", maxlen)); + json_strfield("rawtlv", tal_hexstr(tmpctx, cursor, maxlen)); + json_strfield("hmac", tal_hexstr(tmpctx, rs->next->hmac.bytes, + sizeof(rs->next->hmac.bytes))); + om = tlv_obs2_onionmsg_payload_new(tmpctx); + assert(fromwire_obs2_onionmsg_payload(&cursor, &maxlen, om)); + + json_onionmsg_payload(om); + + /* We expect one of these. */ + assert(om->enctlv); + + printf("\t\"encrypted_data_tlv\": {\n"); + json_strfield("raw", tal_hex(tmpctx, om->enctlv)); + + if (rs->nextcase == ONION_END) { + struct secret *self_id; + struct pubkey alias; + assert(decrypt_obs2_final_enctlv(tmpctx, + blinding, &ss, + om->enctlv, + &my_id, &alias, &self_id)); + if (self_id) { + json_strfield("self_id", + type_to_string(tmpctx, struct secret, + self_id)); + } + printf("}\n"); + return NULL; + } else { + assert(decrypt_obs2_enctlv(blinding, &ss, om->enctlv, &next_node, + blinding)); + json_strfield("next_node", + type_to_string(tmpctx, struct pubkey, &next_node)); + json_strfield("next_blinding", + type_to_string(tmpctx, struct pubkey, + blinding)); + printf("}"); + printf("},\n"); + return serialize_onionpacket(tmpctx, rs->next); + } +} + +int main(int argc, char *argv[]) +{ + struct onionpacket *op; + u8 *data; + struct privkey alice, bob, carol, dave, blinding_priv; + struct pubkey alice_id, bob_id, carol_id, dave_id; + struct pubkey blinding; + + common_setup(argv[0]); + + memset(&alice, 'A', sizeof(alice)); + memset(&bob, 'B', sizeof(bob)); + memset(&carol, 'C', sizeof(carol)); + memset(&dave, 'D', sizeof(dave)); + pubkey_from_privkey(&alice, &alice_id); + pubkey_from_privkey(&bob, &bob_id); + pubkey_from_privkey(&carol, &carol_id); + pubkey_from_privkey(&dave, &dave_id); + + /* ThomasH sends via email: + * + * { + * "version":0, + * "public_key": + * "0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", + * "hop_payloads": + * "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a", + * "hmac": "564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac" + * } + */ + op = tal(tmpctx, struct onionpacket); + op->version = 0; + assert(pubkey_from_hexstr("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", strlen("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967"), &op->ephemeralkey)); + assert(hex_decode("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac", + strlen("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac"), + &op->hmac, sizeof(op->hmac))); + op->routinginfo = tal_hexdata(op, "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a", + strlen("37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a")); + + data = serialize_onionpacket(tmpctx, op); + printf("[\n"); + + memset(&blinding_priv, 5, sizeof(blinding_priv)); + pubkey_from_privkey(&blinding_priv, &blinding); + + data = json_test("onion message for Alice", + data, + &alice, + &blinding_priv, + &blinding); + + data = json_test("onion message for Bob", + data, + &bob, + NULL, + &blinding); + + data = json_test("onion message for Carol", + data, + &carol, + NULL, + &blinding); + + data = json_test("onion message for Dave", + data, + &dave, + NULL, + &blinding); + + assert(!data); + printf("]\n"); + + common_shutdown(); + return 0; +} diff --git a/gossipd/Makefile b/gossipd/Makefile index 13c8eada0abb..6fbb6a7e450c 100644 --- a/gossipd/Makefile +++ b/gossipd/Makefile @@ -34,8 +34,6 @@ GOSSIPD_COMMON_OBJS := \ common/bech32_util.o \ common/bigsize.o \ common/bip32.o \ - common/blinding.o \ - common/blindedpath.o \ common/channel_id.o \ common/cryptomsg.o \ common/daemon.o \ @@ -45,7 +43,6 @@ GOSSIPD_COMMON_OBJS := \ common/dev_disconnect.o \ common/ecdh_hsmd.o \ common/features.o \ - common/hmac.o \ common/status_wiregen.o \ common/gossip_rcvd_filter.o \ common/key_derive.o \ @@ -53,8 +50,6 @@ GOSSIPD_COMMON_OBJS := \ common/memleak.o \ common/msg_queue.o \ common/node_id.o \ - common/onion.o \ - common/onionreply.o \ common/per_peer_state.o \ common/ping.o \ common/psbt_open.o \ @@ -62,7 +57,6 @@ GOSSIPD_COMMON_OBJS := \ common/private_channel_announcement.o \ common/random_select.o \ common/setup.o \ - common/sphinx.o \ common/status.o \ common/status_wire.o \ common/subdaemon.o \ diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 3f8e9f60bfff..8828c3673480 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -13,15 +13,12 @@ #include "config.h" #include #include -#include -#include #include #include #include #include #include #include -#include #include #include #include @@ -349,327 +346,6 @@ static void handle_local_private_channel(struct daemon *daemon, const u8 *msg) } } -/* Peer sends obsolete onion msg. */ -static u8 *handle_obs2_onion_message(struct peer *peer, const u8 *msg) -{ - enum onion_wire badreason; - struct onionpacket *op; - struct pubkey blinding, ephemeral; - struct route_step *rs; - u8 *onion; - struct tlv_obs2_onionmsg_payload *om; - struct secret ss, onion_ss; - const u8 *cursor; - size_t max, maxlen; - - /* Ignore unless explicitly turned on. */ - if (!feature_offered(peer->daemon->our_features->bits[NODE_ANNOUNCE_FEATURE], - OPT_ONION_MESSAGES)) - return NULL; - - /* FIXME: ratelimit! */ - if (!fromwire_obs2_onion_message(msg, msg, &blinding, &onion)) - return towire_warningfmt(peer, NULL, "Bad onion_message"); - - /* We unwrap the onion now. */ - op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason); - if (!op) { - status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s", - onion_wire_name(badreason)); - return NULL; - } - - ephemeral = op->ephemeralkey; - if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) { - status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket"); - return NULL; - } - - /* Now get onion shared secret and parse it. */ - ecdh(&ephemeral, &onion_ss); - rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); - if (!rs) { - status_peer_debug(&peer->id, - "onion msg: can't process onionpacket ss=%s", - type_to_string(tmpctx, struct secret, &onion_ss)); - return NULL; - } - - /* The raw payload is prepended with length in the modern onion. */ - cursor = rs->raw_payload; - max = tal_bytelen(rs->raw_payload); - maxlen = fromwire_bigsize(&cursor, &max); - if (!cursor) { - status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - if (maxlen > max) { - status_peer_debug(&peer->id, "onion msg: overlong hop payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - - om = tlv_obs2_onionmsg_payload_new(msg); - if (!fromwire_obs2_onionmsg_payload(&cursor, &maxlen, om)) { - status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - - if (rs->nextcase == ONION_END) { - struct pubkey *reply_blinding, *first_node_id, me, alias; - const struct onionmsg_path **reply_path; - struct secret *self_id; - u8 *omsg; - - if (!pubkey_from_node_id(&me, &peer->daemon->id)) { - status_broken("Failed to convert own id"); - return NULL; - } - - /* Final enctlv is actually optional */ - if (!om->enctlv) { - alias = me; - self_id = NULL; - } else if (!decrypt_obs2_final_enctlv(tmpctx, &blinding, &ss, - om->enctlv, &me, &alias, - &self_id)) { - status_peer_debug(&peer->id, - "onion msg: failed to decrypt enctlv" - " %s", tal_hex(tmpctx, om->enctlv)); - return NULL; - } - - if (om->reply_path) { - first_node_id = &om->reply_path->first_node_id; - reply_blinding = &om->reply_path->blinding; - reply_path = cast_const2(const struct onionmsg_path **, - om->reply_path->path); - } else { - first_node_id = NULL; - reply_blinding = NULL; - reply_path = NULL; - } - - /* We re-marshall here by policy, before handing to lightningd */ - omsg = tal_arr(tmpctx, u8, 0); - towire_tlvstream_raw(&omsg, om->fields); - daemon_conn_send(peer->daemon->master, - take(towire_gossipd_got_onionmsg_to_us(NULL, - true, /* obs2 */ - &alias, self_id, - reply_blinding, - first_node_id, - reply_path, - omsg))); - } else { - struct pubkey next_node, next_blinding; - struct peer *next_peer; - struct node_id next_node_id; - - /* This fails as expected if no enctlv. */ - if (!decrypt_obs2_enctlv(&blinding, &ss, om->enctlv, &next_node, - &next_blinding)) { - status_peer_debug(&peer->id, - "onion msg: invalid enctlv %s", - tal_hex(tmpctx, om->enctlv)); - return NULL; - } - - /* Even though lightningd checks for valid ids, there's a race - * where it might vanish before we read this command. */ - node_id_from_pubkey(&next_node_id, &next_node); - next_peer = find_peer(peer->daemon, &next_node_id); - if (!next_peer) { - status_peer_debug(&peer->id, - "onion msg: unknown next peer %s", - type_to_string(tmpctx, - struct pubkey, - &next_node)); - return NULL; - } - queue_peer_msg(next_peer, - take(towire_obs2_onion_message(NULL, - &next_blinding, - serialize_onionpacket(tmpctx, rs->next)))); - } - - return NULL; -} - -static void onionmsg_req(struct daemon *daemon, const u8 *msg) -{ - struct node_id id; - u8 *onionmsg; - struct pubkey blinding; - struct peer *peer; - bool obs2; - - if (!fromwire_gossipd_send_onionmsg(msg, msg, &obs2, &id, &onionmsg, &blinding)) - master_badmsg(WIRE_GOSSIPD_SEND_ONIONMSG, msg); - - /* Even though lightningd checks for valid ids, there's a race - * where it might vanish before we read this command. */ - peer = find_peer(daemon, &id); - if (peer) { - u8 *omsg; - if (obs2) - omsg = towire_obs2_onion_message(NULL, &blinding, onionmsg); - else - omsg = towire_onion_message(NULL, &blinding, onionmsg); - queue_peer_msg(peer, take(omsg)); - } -} - -/* Peer sends an onion msg. */ -static u8 *handle_onion_message(struct peer *peer, const u8 *msg) -{ - enum onion_wire badreason; - struct onionpacket *op; - struct pubkey blinding, ephemeral; - struct route_step *rs; - u8 *onion; - struct tlv_onionmsg_payload *om; - struct secret ss, onion_ss; - const u8 *cursor; - size_t max, maxlen; - - /* Ignore unless explicitly turned on. */ - if (!feature_offered(peer->daemon->our_features->bits[NODE_ANNOUNCE_FEATURE], - OPT_ONION_MESSAGES)) - return NULL; - - /* FIXME: ratelimit! */ - if (!fromwire_onion_message(msg, msg, &blinding, &onion)) - return towire_warningfmt(peer, NULL, "Bad onion_message"); - - /* We unwrap the onion now. */ - op = parse_onionpacket(tmpctx, onion, tal_bytelen(onion), &badreason); - if (!op) { - status_peer_debug(&peer->id, "onion msg: can't parse onionpacket: %s", - onion_wire_name(badreason)); - return NULL; - } - - ephemeral = op->ephemeralkey; - if (!unblind_onion(&blinding, ecdh, &ephemeral, &ss)) { - status_peer_debug(&peer->id, "onion msg: can't unblind onionpacket"); - return NULL; - } - - /* Now get onion shared secret and parse it. */ - ecdh(&ephemeral, &onion_ss); - rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); - if (!rs) { - status_peer_debug(&peer->id, - "onion msg: can't process onionpacket ss=%s", - type_to_string(tmpctx, struct secret, &onion_ss)); - return NULL; - } - - /* The raw payload is prepended with length in the modern onion. */ - cursor = rs->raw_payload; - max = tal_bytelen(rs->raw_payload); - maxlen = fromwire_bigsize(&cursor, &max); - if (!cursor) { - status_peer_debug(&peer->id, "onion msg: Invalid hop payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - if (maxlen > max) { - status_peer_debug(&peer->id, "onion msg: overlong hop payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - - om = tlv_onionmsg_payload_new(msg); - if (!fromwire_onionmsg_payload(&cursor, &maxlen, om)) { - status_peer_debug(&peer->id, "onion msg: invalid onionmsg_payload %s", - tal_hex(tmpctx, rs->raw_payload)); - return NULL; - } - - if (rs->nextcase == ONION_END) { - struct pubkey *reply_blinding, *first_node_id, me, alias; - const struct onionmsg_path **reply_path; - struct secret *self_id; - u8 *omsg; - - if (!pubkey_from_node_id(&me, &peer->daemon->id)) { - status_broken("Failed to convert own id"); - return NULL; - } - - /* Final enctlv is actually optional */ - if (!om->encrypted_data_tlv) { - alias = me; - self_id = NULL; - } else if (!decrypt_final_enctlv(tmpctx, &blinding, &ss, - om->encrypted_data_tlv, &me, &alias, - &self_id)) { - status_peer_debug(&peer->id, - "onion msg: failed to decrypt enctlv" - " %s", tal_hex(tmpctx, om->encrypted_data_tlv)); - return NULL; - } - - if (om->reply_path) { - first_node_id = &om->reply_path->first_node_id; - reply_blinding = &om->reply_path->blinding; - reply_path = cast_const2(const struct onionmsg_path **, - om->reply_path->path); - } else { - first_node_id = NULL; - reply_blinding = NULL; - reply_path = NULL; - } - - /* We re-marshall here by policy, before handing to lightningd */ - omsg = tal_arr(tmpctx, u8, 0); - towire_tlvstream_raw(&omsg, om->fields); - daemon_conn_send(peer->daemon->master, - take(towire_gossipd_got_onionmsg_to_us(NULL, - false, /* !obs2 */ - &alias, self_id, - reply_blinding, - first_node_id, - reply_path, - omsg))); - } else { - struct pubkey next_node, next_blinding; - struct peer *next_peer; - struct node_id next_node_id; - - /* This fails as expected if no enctlv. */ - if (!decrypt_enctlv(&blinding, &ss, om->encrypted_data_tlv, &next_node, - &next_blinding)) { - status_peer_debug(&peer->id, - "onion msg: invalid enctlv %s", - tal_hex(tmpctx, om->encrypted_data_tlv)); - return NULL; - } - - /* FIXME: Handle short_channel_id! */ - node_id_from_pubkey(&next_node_id, &next_node); - next_peer = find_peer(peer->daemon, &next_node_id); - if (!next_peer) { - status_peer_debug(&peer->id, - "onion msg: unknown next peer %s", - type_to_string(tmpctx, - struct pubkey, - &next_node)); - return NULL; - } - queue_peer_msg(next_peer, - take(towire_onion_message(NULL, - &next_blinding, - serialize_onionpacket(tmpctx, rs->next)))); - } - - return NULL; -} - /*~ This is where the per-peer daemons send us messages. It's either forwarded * gossip, or a request for information. We deliberately use non-overlapping * message types so we can distinguish them. */ @@ -677,17 +353,8 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, const u8 *msg, struct peer *peer) { - const u8 *err; - /* These are messages relayed from peer */ switch ((enum peer_wire)fromwire_peektype(msg)) { - case WIRE_OBS2_ONION_MESSAGE: - err = handle_obs2_onion_message(peer, msg); - goto handled_relay; - case WIRE_ONION_MESSAGE: - err = handle_onion_message(peer, msg); - goto handled_relay; - /* These are not sent by peer (connectd sends us gossip msgs) */ case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_CHANNEL_UPDATE: @@ -729,6 +396,8 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, case WIRE_ACCEPT_CHANNEL2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: + case WIRE_OBS2_ONION_MESSAGE: + case WIRE_ONION_MESSAGE: #if EXPERIMENTAL_FEATURES case WIRE_STFU: #endif @@ -742,14 +411,6 @@ static struct io_plan *peer_msg_in(struct io_conn *conn, status_peer_broken(&peer->id, "unexpected cmd of type %i", fromwire_peektype(msg)); return io_close(conn); - - /* Forwarded messages may be bad, so we have error which the per-peer - * daemon will forward to the peer. */ -handled_relay: - if (err) - queue_peer_msg(peer, take(err)); - - return daemon_conn_read_next(conn, peer->dc); } /*~ This is where connectd tells us about a new peer, and we hand back an fd for @@ -890,12 +551,6 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg) case WIRE_REPLY_SHORT_CHANNEL_IDS_END: err = handle_reply_short_channel_ids_end(peer, msg); goto handled_msg; - case WIRE_OBS2_ONION_MESSAGE: - err = handle_obs2_onion_message(peer, msg); - goto handled_msg; - case WIRE_ONION_MESSAGE: - err = handle_onion_message(peer, msg); - goto handled_msg; /* These are non-gossip messages (!is_msg_for_gossipd()) */ case WIRE_WARNING: @@ -931,6 +586,8 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg) case WIRE_ACCEPT_CHANNEL2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: + case WIRE_OBS2_ONION_MESSAGE: + case WIRE_ONION_MESSAGE: #if EXPERIMENTAL_FEATURES case WIRE_STFU: #endif @@ -1460,16 +1117,11 @@ static struct io_plan *recv_req(struct io_conn *conn, break; #endif /* !DEVELOPER */ - case WIRE_GOSSIPD_SEND_ONIONMSG: - onionmsg_req(daemon, msg); - goto done; - /* We send these, we don't receive them */ case WIRE_GOSSIPD_INIT_REPLY: case WIRE_GOSSIPD_GET_TXOUT: case WIRE_GOSSIPD_DEV_MEMLEAK_REPLY: case WIRE_GOSSIPD_DEV_COMPACT_STORE_REPLY: - case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: case WIRE_GOSSIPD_ADDGOSSIP_REPLY: case WIRE_GOSSIPD_GET_ADDRS_REPLY: case WIRE_GOSSIPD_GOT_LOCAL_CHANNEL_UPDATE: diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index 3c2f1cf9ca40..712aee5c52ff 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -66,25 +66,6 @@ msgdata,gossipd_dev_compact_store_reply,success,bool, msgtype,gossipd_new_blockheight,3026 msgdata,gossipd_new_blockheight,blockheight,u32, -msgtype,gossipd_got_onionmsg_to_us,3145 -msgdata,gossipd_got_onionmsg_to_us,obs2,bool, -msgdata,gossipd_got_onionmsg_to_us,node_alias,pubkey, -msgdata,gossipd_got_onionmsg_to_us,self_id,?secret, -msgdata,gossipd_got_onionmsg_to_us,reply_blinding,?pubkey, -msgdata,gossipd_got_onionmsg_to_us,reply_first_node,?pubkey, -msgdata,gossipd_got_onionmsg_to_us,reply_path_len,u16, -msgdata,gossipd_got_onionmsg_to_us,reply_path,onionmsg_path,reply_path_len -msgdata,gossipd_got_onionmsg_to_us,rawmsg_len,u16, -msgdata,gossipd_got_onionmsg_to_us,rawmsg,u8,rawmsg_len - -# Lightningd tells us to send an onion message. -msgtype,gossipd_send_onionmsg,3041 -msgdata,gossipd_send_onionmsg,obs2,bool, -msgdata,gossipd_send_onionmsg,id,node_id, -msgdata,gossipd_send_onionmsg,onion_len,u16, -msgdata,gossipd_send_onionmsg,onion,u8,onion_len -msgdata,gossipd_send_onionmsg,blinding,pubkey, - # Lightningd tells us to inject a gossip message (for addgossip RPC) msgtype,gossipd_addgossip,3044 msgdata,gossipd_addgossip,len,u16, diff --git a/gossipd/test/run-onion_message.c b/gossipd/test/run-onion_message.c deleted file mode 100644 index 92882e53d001..000000000000 --- a/gossipd/test/run-onion_message.c +++ /dev/null @@ -1,585 +0,0 @@ -#include "config.h" -int unused_main(int argc, char *argv[]); -#define main unused_main -#include "../gossipd.c" -#undef main -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if DEVELOPER -bool dev_suppress_gossip; - -/* Generated stub for dev_set_max_scids_encode_size */ -void dev_set_max_scids_encode_size(struct daemon *daemon UNNEEDED, - const u8 *msg UNNEEDED) -{ fprintf(stderr, "dev_set_max_scids_encode_size called!\n"); abort(); } -/* Generated stub for dump_memleak */ -bool dump_memleak(struct htable *memtable UNNEEDED, - void (*print)(const char *fmt UNNEEDED, ...)) -{ fprintf(stderr, "dump_memleak called!\n"); abort(); } -/* Generated stub for memleak_status_broken */ -void memleak_status_broken(const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "memleak_status_broken called!\n"); abort(); } -#endif - -/* AUTOGENERATED MOCKS START */ -/* Generated stub for add_to_txout_failures */ -void add_to_txout_failures(struct routing_state *rstate UNNEEDED, - const struct short_channel_id *scid UNNEEDED) -{ fprintf(stderr, "add_to_txout_failures called!\n"); abort(); } -/* Generated stub for daemon_conn_new_ */ -struct daemon_conn *daemon_conn_new_(const tal_t *ctx UNNEEDED, int fd UNNEEDED, - struct io_plan *(*recv)(struct io_conn * UNNEEDED, - const u8 * UNNEEDED, - void *) UNNEEDED, - void (*outq_empty)(void *) UNNEEDED, - void *arg UNNEEDED) -{ fprintf(stderr, "daemon_conn_new_ called!\n"); abort(); } -/* Generated stub for daemon_conn_read_next */ -struct io_plan *daemon_conn_read_next(struct io_conn *conn UNNEEDED, - struct daemon_conn *dc UNNEEDED) -{ fprintf(stderr, "daemon_conn_read_next 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 daemon_conn_send_fd */ -void daemon_conn_send_fd(struct daemon_conn *dc UNNEEDED, int fd UNNEEDED) -{ fprintf(stderr, "daemon_conn_send_fd called!\n"); abort(); } -/* Generated stub for daemon_shutdown */ -void daemon_shutdown(void) -{ fprintf(stderr, "daemon_shutdown called!\n"); abort(); } -/* Generated stub for ecdh */ -void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) -{ fprintf(stderr, "ecdh called!\n"); abort(); } -/* Generated stub for ecdh_hsmd_setup */ -void ecdh_hsmd_setup(int hsm_fd UNNEEDED, - void (*failed)(enum status_failreason UNNEEDED, - const char *fmt UNNEEDED, ...)) -{ fprintf(stderr, "ecdh_hsmd_setup called!\n"); abort(); } -/* Generated stub for first_chan */ -struct chan *first_chan(const struct node *node UNNEEDED, struct chan_map_iter *i UNNEEDED) -{ fprintf(stderr, "first_chan called!\n"); abort(); } -/* Generated stub for fmt_wireaddr_without_port */ -char *fmt_wireaddr_without_port(const tal_t *ctx UNNEEDED, const struct wireaddr *a UNNEEDED) -{ fprintf(stderr, "fmt_wireaddr_without_port called!\n"); abort(); } -/* Generated stub for free_chan */ -void free_chan(struct routing_state *rstate UNNEEDED, struct chan *chan UNNEEDED) -{ fprintf(stderr, "free_chan called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_addgossip */ -bool fromwire_gossipd_addgossip(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **msg UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_addgossip called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_dev_set_time */ -bool fromwire_gossipd_dev_set_time(const void *p UNNEEDED, u32 *dev_gossip_time UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_dev_set_time called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_dev_suppress */ -bool fromwire_gossipd_dev_suppress(const void *p UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_dev_suppress called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_get_addrs */ -bool fromwire_gossipd_get_addrs(const void *p UNNEEDED, struct node_id *id UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_get_addrs called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_get_txout_reply */ -bool fromwire_gossipd_get_txout_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct amount_sat *satoshis UNNEEDED, u8 **outscript UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_get_txout_reply called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_init */ -bool fromwire_gossipd_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct feature_set **our_features UNNEEDED, struct node_id *id UNNEEDED, u8 rgb[3] UNNEEDED, u8 alias[32] UNNEEDED, struct wireaddr **announcable UNNEEDED, u32 **dev_gossip_time UNNEEDED, bool *dev_fast_gossip UNNEEDED, bool *dev_fast_gossip_prune UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_init called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_local_channel_announcement */ -bool fromwire_gossipd_local_channel_announcement(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u8 **cannounce UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_local_channel_announcement called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_local_channel_close */ -bool fromwire_gossipd_local_channel_close(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_local_channel_close called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_local_private_channel */ -bool fromwire_gossipd_local_private_channel(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct amount_sat *capacity UNNEEDED, struct short_channel_id *scid UNNEEDED, u8 **features UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_local_private_channel called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_new_blockheight */ -bool fromwire_gossipd_new_blockheight(const void *p UNNEEDED, u32 *blockheight UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_new_blockheight called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_new_lease_rates */ -bool fromwire_gossipd_new_lease_rates(const void *p UNNEEDED, struct lease_rates *rates UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_new_lease_rates called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_new_peer */ -bool fromwire_gossipd_new_peer(const void *p UNNEEDED, struct node_id *id UNNEEDED, bool *gossip_queries_feature UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_new_peer called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_outpoint_spent */ -bool fromwire_gossipd_outpoint_spent(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_outpoint_spent called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_recv_gossip */ -bool fromwire_gossipd_recv_gossip(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, u8 **msg UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_recv_gossip called!\n"); abort(); } -/* Generated stub for fromwire_gossipd_send_onionmsg */ -bool fromwire_gossipd_send_onionmsg(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, bool *obs2 UNNEEDED, struct node_id *id UNNEEDED, u8 **onion UNNEEDED, struct pubkey *blinding UNNEEDED) -{ fprintf(stderr, "fromwire_gossipd_send_onionmsg called!\n"); abort(); } -/* Generated stub for fromwire_wireaddr_array */ -struct wireaddr *fromwire_wireaddr_array(const tal_t *ctx UNNEEDED, const u8 *ser UNNEEDED) -{ fprintf(stderr, "fromwire_wireaddr_array called!\n"); abort(); } -/* Generated stub for get_node */ -struct node *get_node(struct routing_state *rstate UNNEEDED, - const struct node_id *id UNNEEDED) -{ fprintf(stderr, "get_node called!\n"); abort(); } -/* Generated stub for gossip_store_compact */ -bool gossip_store_compact(struct gossip_store *gs UNNEEDED) -{ fprintf(stderr, "gossip_store_compact 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_load */ -u32 gossip_store_load(struct routing_state *rstate UNNEEDED, struct gossip_store *gs UNNEEDED) -{ fprintf(stderr, "gossip_store_load called!\n"); abort(); } -/* Generated stub for gossip_time_now */ -struct timeabs gossip_time_now(const struct routing_state *rstate UNNEEDED) -{ fprintf(stderr, "gossip_time_now called!\n"); abort(); } -/* Generated stub for handle_channel_announcement */ -u8 *handle_channel_announcement(struct routing_state *rstate UNNEEDED, - const u8 *announce TAKES UNNEEDED, - u32 current_blockheight UNNEEDED, - const struct short_channel_id **scid UNNEEDED, - struct peer *peer UNNEEDED) -{ fprintf(stderr, "handle_channel_announcement called!\n"); abort(); } -/* Generated stub for handle_channel_update */ -u8 *handle_channel_update(struct routing_state *rstate UNNEEDED, const u8 *update TAKES UNNEEDED, - struct peer *peer UNNEEDED, - struct short_channel_id *unknown_scid UNNEEDED, - bool force UNNEEDED) -{ fprintf(stderr, "handle_channel_update called!\n"); abort(); } -/* Generated stub for handle_local_channel_update */ -void handle_local_channel_update(struct daemon *daemon UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_local_channel_update called!\n"); abort(); } -/* Generated stub for handle_node_announcement */ -u8 *handle_node_announcement(struct routing_state *rstate UNNEEDED, const u8 *node UNNEEDED, - struct peer *peer UNNEEDED, bool *was_unknown UNNEEDED) -{ fprintf(stderr, "handle_node_announcement called!\n"); abort(); } -/* Generated stub for handle_pending_cannouncement */ -bool handle_pending_cannouncement(struct daemon *daemon UNNEEDED, - struct routing_state *rstate UNNEEDED, - const struct short_channel_id *scid UNNEEDED, - const struct amount_sat sat UNNEEDED, - const u8 *txscript UNNEEDED) -{ fprintf(stderr, "handle_pending_cannouncement called!\n"); abort(); } -/* Generated stub for handle_query_channel_range */ -const u8 *handle_query_channel_range(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_query_channel_range called!\n"); abort(); } -/* Generated stub for handle_query_short_channel_ids */ -const u8 *handle_query_short_channel_ids(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_query_short_channel_ids called!\n"); abort(); } -/* Generated stub for handle_reply_channel_range */ -const u8 *handle_reply_channel_range(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_reply_channel_range called!\n"); abort(); } -/* Generated stub for handle_reply_short_channel_ids_end */ -const u8 *handle_reply_short_channel_ids_end(struct peer *peer UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_reply_short_channel_ids_end called!\n"); abort(); } -/* Generated stub for handle_used_local_channel_update */ -void handle_used_local_channel_update(struct daemon *daemon UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "handle_used_local_channel_update called!\n"); abort(); } -/* Generated stub for json_add_member */ -void json_add_member(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, - bool quote UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "json_add_member called!\n"); abort(); } -/* Generated stub for json_member_direct */ -char *json_member_direct(struct json_stream *js UNNEEDED, - const char *fieldname UNNEEDED, size_t extra UNNEEDED) -{ fprintf(stderr, "json_member_direct called!\n"); abort(); } -/* Generated stub for json_object_end */ -void json_object_end(struct json_stream *js UNNEEDED) -{ fprintf(stderr, "json_object_end called!\n"); abort(); } -/* Generated stub for json_object_start */ -void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED) -{ fprintf(stderr, "json_object_start called!\n"); abort(); } -/* Generated stub for local_disable_chan */ -void local_disable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) -{ fprintf(stderr, "local_disable_chan called!\n"); abort(); } -/* Generated stub for local_enable_chan */ -void local_enable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED) -{ fprintf(stderr, "local_enable_chan called!\n"); abort(); } -/* Generated stub for master_badmsg */ -void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg) -{ fprintf(stderr, "master_badmsg called!\n"); abort(); } -/* Generated stub for maybe_send_own_node_announce */ -void maybe_send_own_node_announce(struct daemon *daemon UNNEEDED, bool startup UNNEEDED) -{ fprintf(stderr, "maybe_send_own_node_announce called!\n"); abort(); } -/* Generated stub for maybe_send_query_responses */ -void maybe_send_query_responses(struct daemon *daemon UNNEEDED) -{ fprintf(stderr, "maybe_send_query_responses called!\n"); abort(); } -/* Generated stub for memleak_find_allocations */ -struct htable *memleak_find_allocations(const tal_t *ctx UNNEEDED, - const void *exclude1 UNNEEDED, - const void *exclude2 UNNEEDED) -{ fprintf(stderr, "memleak_find_allocations called!\n"); abort(); } -/* Generated stub for memleak_remove_region */ -void memleak_remove_region(struct htable *memtable UNNEEDED, - const void *p UNNEEDED, size_t bytelen UNNEEDED) -{ fprintf(stderr, "memleak_remove_region called!\n"); abort(); } -/* Generated stub for new_onionreply */ -struct onionreply *new_onionreply(const tal_t *ctx UNNEEDED, const u8 *contents TAKES UNNEEDED) -{ fprintf(stderr, "new_onionreply called!\n"); abort(); } -/* Generated stub for new_reltimer_ */ -struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, - const tal_t *ctx UNNEEDED, - struct timerel expire UNNEEDED, - void (*cb)(void *) UNNEEDED, void *arg UNNEEDED) -{ fprintf(stderr, "new_reltimer_ called!\n"); abort(); } -/* Generated stub for new_routing_state */ -struct routing_state *new_routing_state(const tal_t *ctx UNNEEDED, - const struct node_id *local_id UNNEEDED, - struct list_head *peers UNNEEDED, - struct timers *timers UNNEEDED, - const u32 *dev_gossip_time TAKES UNNEEDED, - bool dev_fast_gossip UNNEEDED, - bool dev_fast_gossip_prune UNNEEDED) -{ fprintf(stderr, "new_routing_state called!\n"); abort(); } -/* Generated stub for new_seeker */ -struct seeker *new_seeker(struct daemon *daemon UNNEEDED) -{ fprintf(stderr, "new_seeker called!\n"); abort(); } -/* Generated stub for next_chan */ -struct chan *next_chan(const struct node *node UNNEEDED, struct chan_map_iter *i UNNEEDED) -{ fprintf(stderr, "next_chan 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 private_channel_announcement */ -const u8 *private_channel_announcement(const tal_t *ctx UNNEEDED, - const struct short_channel_id *scid UNNEEDED, - const struct node_id *local_node_id UNNEEDED, - const struct node_id *remote_node_id UNNEEDED, - const u8 *features UNNEEDED) -{ fprintf(stderr, "private_channel_announcement called!\n"); abort(); } -/* Generated stub for query_unknown_channel */ -void query_unknown_channel(struct daemon *daemon UNNEEDED, - struct peer *peer UNNEEDED, - const struct short_channel_id *id UNNEEDED) -{ fprintf(stderr, "query_unknown_channel called!\n"); abort(); } -/* Generated stub for query_unknown_node */ -void query_unknown_node(struct seeker *seeker UNNEEDED, struct peer *peer UNNEEDED) -{ fprintf(stderr, "query_unknown_node called!\n"); abort(); } -/* Generated stub for refresh_local_channel */ -void refresh_local_channel(struct daemon *daemon UNNEEDED, - struct chan *chan UNNEEDED, int direction UNNEEDED) -{ fprintf(stderr, "refresh_local_channel called!\n"); abort(); } -/* Generated stub for remove_channel_from_store */ -void remove_channel_from_store(struct routing_state *rstate UNNEEDED, - struct chan *chan UNNEEDED) -{ fprintf(stderr, "remove_channel_from_store called!\n"); abort(); } -/* Generated stub for remove_unknown_scid */ -bool remove_unknown_scid(struct seeker *seeker UNNEEDED, - const struct short_channel_id *scid UNNEEDED, - bool found UNNEEDED) -{ fprintf(stderr, "remove_unknown_scid called!\n"); abort(); } -/* Generated stub for route_prune */ -void route_prune(struct routing_state *rstate UNNEEDED) -{ fprintf(stderr, "route_prune called!\n"); abort(); } -/* Generated stub for routing_add_private_channel */ -bool routing_add_private_channel(struct routing_state *rstate UNNEEDED, - const struct node_id *id UNNEEDED, - struct amount_sat sat UNNEEDED, - const u8 *chan_ann UNNEEDED, u64 index UNNEEDED) -{ fprintf(stderr, "routing_add_private_channel called!\n"); abort(); } -/* Generated stub for sanitize_error */ -char *sanitize_error(const tal_t *ctx UNNEEDED, const u8 *errmsg UNNEEDED, - struct channel_id *channel_id UNNEEDED) -{ fprintf(stderr, "sanitize_error called!\n"); abort(); } -/* Generated stub for seeker_setup_peer_gossip */ -void seeker_setup_peer_gossip(struct seeker *seeker UNNEEDED, struct peer *peer UNNEEDED) -{ fprintf(stderr, "seeker_setup_peer_gossip called!\n"); abort(); } -/* Generated stub for status_failed */ -void status_failed(enum status_failreason code UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "status_failed 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 status_setup_async */ -void status_setup_async(struct daemon_conn *master UNNEEDED) -{ fprintf(stderr, "status_setup_async called!\n"); abort(); } -/* Generated stub for subdaemon_setup */ -void subdaemon_setup(int argc UNNEEDED, char *argv[]) -{ fprintf(stderr, "subdaemon_setup called!\n"); abort(); } -/* Generated stub for timer_expired */ -void timer_expired(struct timer *timer UNNEEDED) -{ fprintf(stderr, "timer_expired called!\n"); abort(); } -/* Generated stub for towire_gossipd_addgossip_reply */ -u8 *towire_gossipd_addgossip_reply(const tal_t *ctx UNNEEDED, const wirestring *err UNNEEDED) -{ fprintf(stderr, "towire_gossipd_addgossip_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_dev_compact_store_reply */ -u8 *towire_gossipd_dev_compact_store_reply(const tal_t *ctx UNNEEDED, bool success UNNEEDED) -{ fprintf(stderr, "towire_gossipd_dev_compact_store_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_dev_memleak_reply */ -u8 *towire_gossipd_dev_memleak_reply(const tal_t *ctx UNNEEDED, bool leak UNNEEDED) -{ fprintf(stderr, "towire_gossipd_dev_memleak_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_get_addrs_reply */ -u8 *towire_gossipd_get_addrs_reply(const tal_t *ctx UNNEEDED, const struct wireaddr *addrs UNNEEDED) -{ fprintf(stderr, "towire_gossipd_get_addrs_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_get_txout */ -u8 *towire_gossipd_get_txout(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED) -{ fprintf(stderr, "towire_gossipd_get_txout called!\n"); abort(); } -/* Generated stub for towire_gossipd_got_onionmsg_to_us */ -u8 *towire_gossipd_got_onionmsg_to_us(const tal_t *ctx UNNEEDED, bool obs2 UNNEEDED, const struct pubkey *node_alias UNNEEDED, const struct secret *self_id UNNEEDED, const struct pubkey *reply_blinding UNNEEDED, const struct pubkey *reply_first_node UNNEEDED, const struct onionmsg_path **reply_path UNNEEDED, const u8 *rawmsg UNNEEDED) -{ fprintf(stderr, "towire_gossipd_got_onionmsg_to_us called!\n"); abort(); } -/* Generated stub for towire_gossipd_init_reply */ -u8 *towire_gossipd_init_reply(const tal_t *ctx UNNEEDED) -{ fprintf(stderr, "towire_gossipd_init_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_new_peer_reply */ -u8 *towire_gossipd_new_peer_reply(const tal_t *ctx UNNEEDED, bool success UNNEEDED) -{ fprintf(stderr, "towire_gossipd_new_peer_reply called!\n"); abort(); } -/* Generated stub for towire_gossipd_send_gossip */ -u8 *towire_gossipd_send_gossip(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "towire_gossipd_send_gossip called!\n"); abort(); } -/* Generated stub for towire_warningfmt */ -u8 *towire_warningfmt(const tal_t *ctx UNNEEDED, - const struct channel_id *channel UNNEEDED, - const char *fmt UNNEEDED, ...) -{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); } -/* AUTOGENERATED MOCKS END */ - -/* Updated each time, as we pretend to be Alice, Bob, Carol */ -static const struct privkey *mykey; - -static void test_ecdh(const struct pubkey *point, struct secret *ss) -{ - if (secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey, - mykey->secret.data, NULL, NULL) != 1) - abort(); -} - -static void json_strfield(const char *name, const char *val) -{ - printf("\t\"%s\": \"%s\",\n", name, val); -} - -static void json_onionmsg_payload(const struct tlv_obs2_onionmsg_payload *om) -{ - if (om->reply_path) { - printf("\t\"reply_path\": {\n"); - json_strfield("first_node_id", - type_to_string(tmpctx, struct pubkey, - &om->reply_path->first_node_id)); - json_strfield("blinding", - type_to_string(tmpctx, struct pubkey, - &om->reply_path->blinding)); - printf("\t\"path\": [\n"); - for (size_t i = 0; i < tal_count(om->reply_path->path); i++) { - json_strfield("node_id", - type_to_string(tmpctx, struct pubkey, - &om->reply_path->path[i]->node_id)); - json_strfield("encrypted_recipient_data", - tal_hex(tmpctx, - om->reply_path->path[i]->encrypted_recipient_data)); - } - printf("]}\n"); - } - if (om->invoice) - json_strfield("invoice", tal_hex(tmpctx, om->invoice)); - if (om->invoice_request) - json_strfield("invoice_request", - tal_hex(tmpctx, om->invoice_request)); - if (om->invoice_error) - json_strfield("invoice_error", - tal_hex(tmpctx, om->invoice_error)); -} - -/* Return next onion (and updates blinding), or NULL */ -static u8 *json_test(const char *testname, - const u8 *data, - const struct privkey *me, - const struct privkey *blinding_priv, - struct pubkey *blinding) -{ - struct pubkey my_id, next_node; - struct secret ss, onion_ss; - struct pubkey ephemeral; - struct route_step *rs; - const u8 *cursor; - size_t max, maxlen; - struct onionpacket *op; - struct tlv_obs2_onionmsg_payload *om; - - op = parse_onionpacket(tmpctx, data, tal_bytelen(data), NULL); - assert(op); - - pubkey_from_privkey(me, &my_id); - printf("{"); - json_strfield("test name", testname); - json_strfield("reader_privkey", - type_to_string(tmpctx, struct privkey, me)); - json_strfield("reader_id", - type_to_string(tmpctx, struct pubkey, &my_id)); - - if (blinding_priv) - json_strfield("blinding_privkey", - type_to_string(tmpctx, struct privkey, - blinding_priv)); - json_strfield("blinding", - type_to_string(tmpctx, struct pubkey, blinding)); - printf("\"onionmsg\": {\n"); - json_strfield("raw", tal_hex(tmpctx, data)); - json_strfield("version", tal_fmt(tmpctx, "%i", op->version)); - json_strfield("public_key", - type_to_string(tmpctx, struct pubkey, &op->ephemeralkey)); - json_strfield("hop_payloads", - tal_hex(tmpctx, op->routinginfo)); - json_strfield("hmac", - tal_hexstr(tmpctx, &op->hmac, sizeof(op->hmac))); - printf("},\n"); - - ephemeral = op->ephemeralkey; - - /* Set this for test_ecdh */ - mykey = me; - assert(unblind_onion(blinding, test_ecdh, &ephemeral, &ss)); - json_strfield("ECDH shared secret", - type_to_string(tmpctx, struct secret, &ss)); - /* Reproduce internal calc from unblind_onion */ - { - struct secret hmac; - subkey_from_hmac("blinded_node_id", &ss, &hmac); - json_strfield("HMAC256(\\\"blinded_node_id\\\", ss(i)) * k(i)", - type_to_string(tmpctx, struct secret, &hmac)); - } - json_strfield("Tweaked onion pubkey", - type_to_string(tmpctx, struct pubkey, &ephemeral)); - - /* Now get onion shared secret and parse it. */ - test_ecdh(&ephemeral, &onion_ss); - json_strfield("onion shared secret", - type_to_string(tmpctx, struct secret, &onion_ss)); - rs = process_onionpacket(tmpctx, op, &onion_ss, NULL, 0, false); - assert(rs); - - printf("\"onion contents\": {\n"); - json_strfield("raw", tal_hex(tmpctx, rs->raw_payload)); - - cursor = rs->raw_payload; - max = tal_bytelen(rs->raw_payload); - maxlen = fromwire_bigsize(&cursor, &max); - json_strfield("length", tal_fmt(tmpctx, "%zu", maxlen)); - json_strfield("rawtlv", tal_hexstr(tmpctx, cursor, maxlen)); - json_strfield("hmac", tal_hexstr(tmpctx, rs->next->hmac.bytes, - sizeof(rs->next->hmac.bytes))); - om = tlv_obs2_onionmsg_payload_new(tmpctx); - assert(fromwire_obs2_onionmsg_payload(&cursor, &maxlen, om)); - - json_onionmsg_payload(om); - - /* We expect one of these. */ - assert(om->enctlv); - - printf("\t\"encrypted_data_tlv\": {\n"); - json_strfield("raw", tal_hex(tmpctx, om->enctlv)); - - if (rs->nextcase == ONION_END) { - struct secret *self_id; - struct pubkey alias; - assert(decrypt_obs2_final_enctlv(tmpctx, - blinding, &ss, - om->enctlv, - &my_id, &alias, &self_id)); - if (self_id) { - json_strfield("self_id", - type_to_string(tmpctx, struct secret, - self_id)); - } - printf("}\n"); - return NULL; - } else { - assert(decrypt_obs2_enctlv(blinding, &ss, om->enctlv, &next_node, - blinding)); - json_strfield("next_node", - type_to_string(tmpctx, struct pubkey, &next_node)); - json_strfield("next_blinding", - type_to_string(tmpctx, struct pubkey, - blinding)); - printf("}"); - printf("},\n"); - return serialize_onionpacket(tmpctx, rs->next); - } -} - -int main(int argc, char *argv[]) -{ - struct onionpacket *op; - u8 *data; - struct privkey alice, bob, carol, dave, blinding_priv; - struct pubkey alice_id, bob_id, carol_id, dave_id; - struct pubkey blinding; - - common_setup(argv[0]); - - memset(&alice, 'A', sizeof(alice)); - memset(&bob, 'B', sizeof(bob)); - memset(&carol, 'C', sizeof(carol)); - memset(&dave, 'D', sizeof(dave)); - pubkey_from_privkey(&alice, &alice_id); - pubkey_from_privkey(&bob, &bob_id); - pubkey_from_privkey(&carol, &carol_id); - pubkey_from_privkey(&dave, &dave_id); - - /* ThomasH sends via email: - * - * { - * "version":0, - * "public_key": - * "0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", - * "hop_payloads": - * "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a", - * "hmac": "564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac" - * } - */ - op = tal(tmpctx, struct onionpacket); - op->version = 0; - assert(pubkey_from_hexstr("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967", strlen("0256b328b30c8bf5839e24058747879408bdb36241dc9c2e7c619faa12b2920967"), &op->ephemeralkey)); - assert(hex_decode("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac", - strlen("564bb85911bea8f90d306f4acdafa1c0887619ac72606b11e6b2765734d810ac"), - &op->hmac, sizeof(op->hmac))); - op->routinginfo = tal_hexdata(op, "37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a", - strlen("37df67dcefdb678725cb8074d3224dfe235ba3f22f71ac8a2c9d1398b1175295b1dd3f14c02d698021e8a8856637306c6f195e01494eb8dc636b4462367533a84786b8592e580086cdf0f1c58b77eb68703a2fb82ecc2e91307a25b6d5e4045174551b1c867264d3905e4f05b2e5bcfed7e7276660bf7e956bce5afa395e7e4c15883b856bc93dd9d6a968838ef51314d38dd41e5ab84b8846dca3c61d87e55780e7a7da336a965a4652263413cdef41daa68f7bb7cd4d566c19a1c4eece369c47e604575f38e7a246a985c3441b60ae33c564395bb7a4bbe28325ccdb07503285dacf90b5e09f4e455fb42459741f9d497000298b99f1e70adc28f59a1be85a96952f27b6a6c5d6a08822b4f5cae05daa6c2ce2f8ca5fdd4e8f0df46b94791b3159fe8eace11bcf8d58be425b49ce2b47c007affefd5cea785c1996ad805f8c8c5ca79f15ab26e2bd4080b1d74328e7ce5bd2a579c71a6bd25f33f2ce475a2cfbe67ed1f4eb8fbd86920f41d573488abe059166aabbc3be187c435423ead6a5473994e0246efe76e419893aa2d7566b2645f3496d97585de9c92b8c5a5226398cc459ce84abc02fe2b45b5ecaf21961730d4a34bbe6fdfe720e71e3d81a494c01080d8039360d534c6ee5a3c47a1874e526969add9126b30d9192f85ba45bcfd7029cc7560f0e25e14b5deaa805360c4967705e85325ac055922863470f5397e8404022488caebf9204acd6cb02a11088aebf7e497b4ff1172f0a9c6bf980914cc4eb42fc78b457add549abf1134f84922b217502938b42d10b35079f44c5168d4c3e9fe7ca8094ef72ed73ef84f1d3530b6b3545f9f4f013e7e8cbcf2619f57754a7380ce6a9532ee14c55990faa43df6c09530a314b5f4ce597f5ec9b776e8597ce258ac47dac43bd3ac9e52788ff3a66b7dc07cd1bc3e6d197339d85fa8d3d6c3054dd1a5e416c714b544de6eb55209e40e3cac412a51748370160d2d73b6d97abd62f7bae70df27cd199c511fa693019c5717d471e934906b98cd974fda4dd1cb5e2d721044a0be2bdf24d0971e09f2f39488fe389fc5230699b4df7cec7447e5be4ea49bd7c3fe1a5ec7358510dc1dd9c1a8da68c0863188d80549e49f7c00f57d2009b2427b2aed1569603fc247734039469f9fdf3ddd3a22fa95c5d8066a468327a02b474c9915419af82c8edc67686984767fe7885207c6820f6c2e57cb8fd0bcb9981ebc8065c74e970a5d593c3b73ee25a0877ca096a9f7edfee6d43bd817c7d415fea9abb6f206c61aa36942df9318762a76b9da26d0d41a0ae9eee042a175f82dc134bf6f2d46a218db358d6852940e6e30df4a58ac6cb409e7ce99afe1e3f42768bd617af4d0a235d0ba0dd5075f9cc091784395d30e7e42d4e006db21bea9b45d1f122b75c051e84e2281573ef54ebad053218fff0cc28ea89a06adc218d4134f407654990592e75462f5ee4a463c1e46425222d48761162da8049613cafd7ecc52ff8024e9d58512b958e3a3d12dede84e1441247700bca0f992875349448b430683c756438fd4e91f3d44f3cf624ed21f3c63cf92615ecc201d0cd3159b1b3fccd8f29d2daba9ac5ba87b1dd2f83323a2b2d3176b803ce9c7bdc4bae615925eb22a213df1eeb2f8ff95586536caf042d565984aacf1425a120a5d8d7a9cbb70bf4852e116b89ff5b198d672220af2be4246372e7c3836cf50d732212a3e3346ff92873ace57fa687b2b1aab3e8dc6cb9f93f865d998cff0a1680d9012a9597c90a070e525f66226cc287814f4ac4157b15a0b25aa110946cd69fd404fafd5656669bfd1d9e509eabc004c5a")); - - data = serialize_onionpacket(tmpctx, op); - printf("[\n"); - - memset(&blinding_priv, 5, sizeof(blinding_priv)); - pubkey_from_privkey(&blinding_priv, &blinding); - - data = json_test("onion message for Alice", - data, - &alice, - &blinding_priv, - &blinding); - - data = json_test("onion message for Bob", - data, - &bob, - NULL, - &blinding); - - data = json_test("onion message for Carol", - data, - &carol, - NULL, - &blinding); - - data = json_test("onion message for Dave", - data, - &dave, - NULL, - &blinding); - - assert(!data); - printf("]\n"); - - common_shutdown(); - return 0; -} diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 71a95459440d..bba057152592 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -367,6 +368,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_DEV_MEMLEAK: case WIRE_CONNECTD_PEER_FINAL_MSG: case WIRE_CONNECTD_PING: + case WIRE_CONNECTD_SEND_ONIONMSG: /* This is a reply, so never gets through to here. */ case WIRE_CONNECTD_INIT_REPLY: case WIRE_CONNECTD_ACTIVATE_REPLY: @@ -387,6 +389,10 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_CONNECT_FAILED: connect_failed(connectd->ld, msg); break; + + case WIRE_CONNECTD_GOT_ONIONMSG_TO_US: + handle_onionmsg_to_us(connectd->ld, msg); + break; } return 0; } diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 19ac7eb73533..66108ddb2e2d 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -163,7 +162,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_DEV_COMPACT_STORE: case WIRE_GOSSIPD_DEV_SET_TIME: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT: - case WIRE_GOSSIPD_SEND_ONIONMSG: case WIRE_GOSSIPD_ADDGOSSIP: case WIRE_GOSSIPD_GET_ADDRS: case WIRE_GOSSIPD_USED_LOCAL_CHANNEL_UPDATE: @@ -178,9 +176,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds) case WIRE_GOSSIPD_GET_ADDRS_REPLY: break; - case WIRE_GOSSIPD_GOT_ONIONMSG_TO_US: - handle_onionmsg_to_us(gossip->ld, msg); - break; case WIRE_GOSSIPD_GET_TXOUT: get_txout(gossip, msg); break; diff --git a/lightningd/onion_message.c b/lightningd/onion_message.c index e6e51f5ebccd..fec95b7ca547 100644 --- a/lightningd/onion_message.c +++ b/lightningd/onion_message.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -150,7 +150,7 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg) payload = tal(tmpctx, struct onion_message_hook_payload); payload->our_alias = tal(payload, struct pubkey); - if (!fromwire_gossipd_got_onionmsg_to_us(payload, msg, + if (!fromwire_connectd_got_onionmsg_to_us(payload, msg, &obs2, payload->our_alias, &self_id, @@ -198,7 +198,7 @@ void handle_onionmsg_to_us(struct lightningd *ld, const u8 *msg) } tal_free(submsg); - /* Make sure gossipd gets this right. */ + /* Make sure connectd gets this right. */ if (payload->reply_path && (!payload->reply_blinding || !payload->reply_first_node)) { log_broken(ld->log, @@ -277,7 +277,7 @@ static struct command_result *json_sendonionmessage2(struct command *cmd, return command_fail(cmd, LIGHTNINGD, "experimental-onion-messages not enabled"); - /* Sanity check first; gossipd doesn't bother telling us if peer + /* Sanity check first; connectd doesn't bother telling us if peer * can't be reached. */ if (!peer_by_id(cmd->ld, first_id)) return command_fail(cmd, LIGHTNINGD, "Unknown first peer"); @@ -300,8 +300,8 @@ static struct command_result *json_sendonionmessage2(struct command *cmd, return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Creating onion failed (tlvs too long?)"); - subd_send_msg(cmd->ld->gossip, - take(towire_gossipd_send_onionmsg(NULL, obs2, first_id, + subd_send_msg(cmd->ld->connectd, + take(towire_connectd_send_onionmsg(NULL, obs2, first_id, serialize_onionpacket(tmpctx, op), blinding))); diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 1ed291db5c35..35089e48f1d7 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -65,8 +65,6 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_QUERY_CHANNEL_RANGE: case WIRE_REPLY_CHANNEL_RANGE: - case WIRE_OBS2_ONION_MESSAGE: - case WIRE_ONION_MESSAGE: return true; case WIRE_WARNING: case WIRE_INIT: @@ -101,6 +99,8 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_ACCEPT_CHANNEL2: case WIRE_INIT_RBF: case WIRE_ACK_RBF: + case WIRE_OBS2_ONION_MESSAGE: + case WIRE_ONION_MESSAGE: #if EXPERIMENTAL_FEATURES case WIRE_STFU: #endif From ef6364dcfc5f6045b4ea055f75ab4702bc13b6cd Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:06:59 +1030 Subject: [PATCH 45/51] connectd: handle custom messages. This is neater than what we had before, and slightly more general. Signed-off-by: Rusty Russell Changelog-Changed: JSON_RPC: `sendcustommsg` now works with any connected peer, even when shutting down a channel. --- channeld/channeld.c | 46 +----- closingd/closingd.c | 10 -- connectd/connectd.c | 5 + connectd/connectd_wire.csv | 12 ++ connectd/multiplex.c | 14 ++ connectd/multiplex.h | 3 + lightningd/channel_control.c | 10 -- lightningd/closing_control.c | 10 -- lightningd/connect_control.c | 141 +++++++++++++++++ lightningd/dual_open_control.c | 10 -- lightningd/opening_control.c | 10 -- lightningd/peer_control.c | 164 -------------------- lightningd/peer_control.h | 3 - lightningd/subd.c | 4 +- lightningd/test/run-invoice-select-inchan.c | 8 - openingd/dualopend.c | 56 +------ openingd/openingd.c | 32 ---- wallet/test/run-wallet.c | 20 --- wire/Makefile | 2 - wire/common_wire.csv | 10 -- 20 files changed, 180 insertions(+), 390 deletions(-) delete mode 100644 wire/common_wire.csv diff --git a/channeld/channeld.c b/channeld/channeld.c index 0ee694949045..bdb1609f8f52 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include @@ -2029,23 +2028,6 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown) billboard_update(peer); } -/* Try to handle a custommsg Returns true if it was a custom message and has - * been handled, false if the message was not handled. - */ -static bool channeld_handle_custommsg(const u8 *msg) -{ - enum peer_wire type = fromwire_peektype(msg); - if (type % 2 == 1 && !peer_wire_is_defined(type)) { - /* The message is not part of the messages we know how to - * handle. Assuming this is a custommsg, we just forward it to the - * master. */ - wire_sync_write(MASTER_FD, take(towire_custommsg_in(NULL, msg))); - return true; - } else { - return false; - } -} - static void handle_unexpected_tx_sigs(struct peer *peer, const u8 *msg) { const struct witness_stack **ws; @@ -2140,9 +2122,6 @@ static void peer_in(struct peer *peer, const u8 *msg) */ bool soft_error = peer->funding_locked[REMOTE] || peer->funding_locked[LOCAL]; - if (channeld_handle_custommsg(msg)) - return; - /* Since LND seems to send errors which aren't actually fatal events, * we treat errors here as soft. */ if (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, soft_error, msg)) @@ -2813,8 +2792,7 @@ static void peer_reconnect(struct peer *peer, do { clean_tmpctx(); msg = peer_read(tmpctx, peer->pps); - } while (channeld_handle_custommsg(msg) || - handle_peer_gossip_or_error(peer->pps, &peer->channel_id, soft_error, + } while (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, soft_error, msg) || capture_premature_msg(&premature_msgs, msg)); @@ -3569,17 +3547,6 @@ static void handle_dev_quiesce(struct peer *peer, const u8 *msg) #endif /* EXPERIMENTAL_FEATURES */ #endif /* DEVELOPER */ -/* We were told to send a custommsg to the peer by `lightningd`. All the - * verification is done on the side of `lightningd` so we should be good to - * just forward it here. */ -static void channeld_send_custommsg(struct peer *peer, const u8 *msg) -{ - u8 *inner; - if (!fromwire_custommsg_out(tmpctx, msg, &inner)) - master_badmsg(WIRE_CUSTOMMSG_OUT, msg); - peer_write(peer->pps, take(inner)); -} - static void req_in(struct peer *peer, const u8 *msg) { enum channeld_wire t = fromwire_peektype(msg); @@ -3668,17 +3635,6 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_LOCAL_PRIVATE_CHANNEL: break; } - - /* Now handle common messages. */ - switch ((enum common_wire)t) { - case WIRE_CUSTOMMSG_OUT: - channeld_send_custommsg(peer, msg); - return; - /* We send these. */ - case WIRE_CUSTOMMSG_IN: - break; - } - master_badmsg(-1, msg); } diff --git a/closingd/closingd.c b/closingd/closingd.c index 9fb74e4ba899..e013b5781dce 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -127,15 +126,6 @@ static u8 *closing_read_peer_msg(const tal_t *ctx, handle_gossip_msg(pps, take(msg)); continue; } - /* Handle custommsgs */ - enum peer_wire type = fromwire_peektype(msg); - if (type % 2 == 1 && !peer_wire_is_defined(type)) { - /* The message is not part of the messages we know - * how to handle. Assume is custommsg, forward it - * to master. */ - wire_sync_write(REQ_FD, take(towire_custommsg_in(NULL, msg))); - continue; - } if (!handle_peer_gossip_or_error(pps, channel_id, false, msg)) return msg; } diff --git a/connectd/connectd.c b/connectd/connectd.c index 2f7ce123dd48..68e8fe71d991 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1941,6 +1941,10 @@ static struct io_plan *recv_req(struct io_conn *conn, onionmsg_req(daemon, msg); goto out; + case WIRE_CONNECTD_CUSTOMMSG_OUT: + send_custommsg(daemon, msg); + goto out; + case WIRE_CONNECTD_DEV_MEMLEAK: #if DEVELOPER dev_connect_memleak(daemon, msg); @@ -1955,6 +1959,7 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_CONNECTD_DEV_MEMLEAK_REPLY: case WIRE_CONNECTD_PING_REPLY: case WIRE_CONNECTD_GOT_ONIONMSG_TO_US: + case WIRE_CONNECTD_CUSTOMMSG_IN: break; } diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index 52dae09d0c54..01c03335cb32 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -116,3 +116,15 @@ msgdata,connectd_send_onionmsg,onion_len,u16, msgdata,connectd_send_onionmsg,onion,u8,onion_len msgdata,connectd_send_onionmsg,blinding,pubkey, +# A custom message that we got from a peer and don't know how to handle, so we +# forward it to the master for further handling. +msgtype,connectd_custommsg_in,2110 +msgdata,connectd_custommsg_in,id,node_id, +msgdata,connectd_custommsg_in,msg_len,u16, +msgdata,connectd_custommsg_in,msg,u8,msg_len + +# A custom message that the lightningd tells us to send to the peer. +msgtype,connectd_custommsg_out,2011 +msgdata,connectd_custommsg_out,id,node_id, +msgdata,connectd_custommsg_out,msg_len,u16, +msgdata,connectd_custommsg_out,msg,u8,msg_len diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 06e7cf050f8c..246efb081998 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -736,3 +736,17 @@ void send_manual_ping(struct daemon *daemon, const u8 *msg) set_ping_timer(peer); } +void send_custommsg(struct daemon *daemon, const u8 *msg) +{ + struct node_id id; + u8 *custommsg; + struct peer *peer; + + if (!fromwire_connectd_custommsg_out(tmpctx, msg, &id, &custommsg)) + master_badmsg(WIRE_CONNECTD_CUSTOMMSG_OUT, msg); + + /* Races can happen: this might be gone by now. */ + peer = peer_htable_get(&daemon->peers, &id); + if (peer) + queue_peer_msg(peer, take(custommsg)); +} diff --git a/connectd/multiplex.h b/connectd/multiplex.h index 3694c2b13d9c..7b8db8bcd209 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -30,4 +30,7 @@ void setup_peer_gossip_store(struct peer *peer, /* When lightningd says to send a ping */ void send_manual_ping(struct daemon *daemon, const u8 *msg); + +/* When lightningd says to send a custom message (from a plugin) */ +void send_custommsg(struct daemon *daemon, const u8 *msg); #endif /* LIGHTNING_CONNECTD_MULTIPLEX_H */ diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index a63775bb893c..49c8406d6f30 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -21,7 +21,6 @@ #include #include #include -#include static void update_feerates(struct lightningd *ld, struct channel *channel) { @@ -553,15 +552,6 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) break; } - switch ((enum common_wire)t) { - case WIRE_CUSTOMMSG_IN: - handle_custommsg_in(sd->ld, sd->node_id, msg); - break; - /* We send these. */ - case WIRE_CUSTOMMSG_OUT: - break; - } - return 0; } diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index 0b297cbc5ea8..0d2a0c249c8c 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -37,7 +37,6 @@ #include #include #include -#include struct close_command { /* Inside struct lightningd close_commands. */ @@ -335,15 +334,6 @@ static unsigned closing_msg(struct subd *sd, const u8 *msg, const int *fds UNUSE break; } - switch ((enum common_wire)t) { - case WIRE_CUSTOMMSG_IN: - handle_custommsg_in(sd->ld, sd->node_id, msg); - break; - /* We send these. */ - case WIRE_CUSTOMMSG_OUT: - break; - } - return 0; } diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index bba057152592..6e839a4aaf41 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -21,6 +21,7 @@ #include #include #include +#include struct connect { struct list_node list; @@ -355,6 +356,63 @@ static void peer_please_disconnect(struct lightningd *ld, const u8 *msg) } } +struct custommsg_payload { + struct node_id peer_id; + u8 *msg; +}; + +static bool custommsg_cb(struct custommsg_payload *payload, + const char *buffer, const jsmntok_t *toks) +{ + const jsmntok_t *t_res; + + if (!toks || !buffer) + return true; + + t_res = json_get_member(buffer, toks, "result"); + + /* fail */ + if (!t_res || !json_tok_streq(buffer, t_res, "continue")) + fatal("Plugin returned an invalid response to the " + "custommsg hook: %s", buffer); + + /* call next hook */ + return true; +} + +static void custommsg_final(struct custommsg_payload *payload STEALS) +{ + tal_steal(tmpctx, payload); +} + +static void custommsg_payload_serialize(struct custommsg_payload *payload, + struct json_stream *stream, + struct plugin *plugin) +{ + json_add_hex_talarr(stream, "payload", payload->msg); + json_add_node_id(stream, "peer_id", &payload->peer_id); +} + +REGISTER_PLUGIN_HOOK(custommsg, + custommsg_cb, + custommsg_final, + custommsg_payload_serialize, + struct custommsg_payload *); + +static void handle_custommsg_in(struct lightningd *ld, const u8 *msg) +{ + struct custommsg_payload *p = tal(NULL, struct custommsg_payload); + + if (!fromwire_connectd_custommsg_in(p, msg, &p->peer_id, &p->msg)) { + log_broken(ld->log, "Malformed custommsg: %s", + tal_hex(tmpctx, msg)); + tal_free(p); + return; + } + + plugin_hook_call_custommsg(ld, p); +} + static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fds) { enum connectd_wire t = fromwire_peektype(msg); @@ -369,6 +427,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_PEER_FINAL_MSG: case WIRE_CONNECTD_PING: case WIRE_CONNECTD_SEND_ONIONMSG: + case WIRE_CONNECTD_CUSTOMMSG_OUT: /* This is a reply, so never gets through to here. */ case WIRE_CONNECTD_INIT_REPLY: case WIRE_CONNECTD_ACTIVATE_REPLY: @@ -393,6 +452,10 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd case WIRE_CONNECTD_GOT_ONIONMSG_TO_US: handle_onionmsg_to_us(connectd->ld, msg); break; + + case WIRE_CONNECTD_CUSTOMMSG_IN: + handle_custommsg_in(connectd->ld, msg); + break; } return 0; } @@ -503,3 +566,81 @@ void connectd_activate(struct lightningd *ld) io_loop(NULL, NULL); } +static struct command_result *json_sendcustommsg(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct json_stream *response; + struct node_id *dest; + struct peer *peer; + u8 *msg; + int type; + + if (!param(cmd, buffer, params, + p_req("node_id", param_node_id, &dest), + p_req("msg", param_bin_from_hex, &msg), + NULL)) + return command_param_failed(); + + type = fromwire_peektype(msg); + if (peer_wire_is_defined(type)) { + return command_fail( + cmd, JSONRPC2_INVALID_REQUEST, + "Cannot send messages of type %d (%s). It is not possible " + "to send messages that have a type managed internally " + "since that might cause issues with the internal state " + "tracking.", + type, peer_wire_name(type)); + } + + if (type % 2 == 0) { + return command_fail( + cmd, JSONRPC2_INVALID_REQUEST, + "Cannot send even-typed %d custom message. Currently " + "custom messages are limited to odd-numbered message " + "types, as even-numbered types might result in " + "disconnections.", + type); + } + + peer = peer_by_id(cmd->ld, dest); + if (!peer) { + return command_fail(cmd, JSONRPC2_INVALID_REQUEST, + "No such peer: %s", + type_to_string(cmd, struct node_id, dest)); + } + + subd_send_msg(cmd->ld->connectd, + take(towire_connectd_custommsg_out(cmd, dest, msg))); + + response = json_stream_success(cmd); + json_add_string(response, "status", + "Message sent to connectd for delivery"); + + return command_success(cmd, response); +} + +static const struct json_command sendcustommsg_command = { + "sendcustommsg", + "utility", + json_sendcustommsg, + "Send a custom message to the peer with the given {node_id}", + .verbose = "sendcustommsg node_id hexcustommsg", +}; + +AUTODATA(json_command, &sendcustommsg_command); + +#ifdef COMPAT_V0100 +#ifdef DEVELOPER +static const struct json_command dev_sendcustommsg_command = { + "dev-sendcustommsg", + "utility", + json_sendcustommsg, + "Send a custom message to the peer with the given {node_id}", + .verbose = "dev-sendcustommsg node_id hexcustommsg", +}; + +AUTODATA(json_command, &dev_sendcustommsg_command); +#endif /* DEVELOPER */ +#endif /* COMPAT_V0100 */ diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 4e01b299d6b6..290bc6b3cfe9 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -30,7 +30,6 @@ #include #include #include -#include struct commit_rcvd { struct channel *channel; @@ -3005,15 +3004,6 @@ static unsigned int dual_opend_msg(struct subd *dualopend, break; } - switch ((enum common_wire)t) { - case WIRE_CUSTOMMSG_IN: - handle_custommsg_in(dualopend->ld, dualopend->node_id, msg); - return 0; - /* We send these. */ - case WIRE_CUSTOMMSG_OUT: - break; - } - log_broken(dualopend->log, "Unexpected msg %s: %s", dualopend_wire_name(t), tal_hex(tmpctx, msg)); tal_free(dualopend); diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 441658de8d7b..0fcbb115b89b 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -27,7 +27,6 @@ #include #include #include -#include void json_add_uncommitted_channel(struct json_stream *response, const struct uncommitted_channel *uc) @@ -886,15 +885,6 @@ static unsigned int openingd_msg(struct subd *openingd, break; } - switch ((enum common_wire)t) { - case WIRE_CUSTOMMSG_IN: - handle_custommsg_in(openingd->ld, openingd->node_id, msg); - return 0; - /* We send these. */ - case WIRE_CUSTOMMSG_OUT: - break; - } - log_broken(openingd->log, "Unexpected msg %s: %s", openingd_wire_name(t), tal_hex(tmpctx, msg)); tal_free(openingd); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index afeb63660b12..a5b28d5a42fc 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -64,7 +64,6 @@ #include #include #include -#include #include #include @@ -2413,167 +2412,4 @@ void peer_dev_memleak(struct command *cmd) { peer_memleak_req_next(cmd, NULL); } - #endif /* DEVELOPER */ - -struct custommsg_payload { - struct node_id peer_id; - const u8 *msg; -}; - -static bool custommsg_cb(struct custommsg_payload *payload, - const char *buffer, const jsmntok_t *toks) -{ - const jsmntok_t *t_res; - - if (!toks || !buffer) - return true; - - t_res = json_get_member(buffer, toks, "result"); - - /* fail */ - if (!t_res || !json_tok_streq(buffer, t_res, "continue")) - fatal("Plugin returned an invalid response to the " - "custommsg hook: %s", buffer); - - /* call next hook */ - return true; -} - -static void custommsg_final(struct custommsg_payload *payload STEALS) -{ - tal_steal(tmpctx, payload); -} - -static void custommsg_payload_serialize(struct custommsg_payload *payload, - struct json_stream *stream, - struct plugin *plugin) -{ - json_add_hex_talarr(stream, "payload", payload->msg); - json_add_node_id(stream, "peer_id", &payload->peer_id); -} - -REGISTER_PLUGIN_HOOK(custommsg, - custommsg_cb, - custommsg_final, - custommsg_payload_serialize, - struct custommsg_payload *); - -void handle_custommsg_in(struct lightningd *ld, const struct node_id *peer_id, - const u8 *msg) -{ - struct custommsg_payload *p = tal(NULL, struct custommsg_payload); - u8 *custommsg; - - if (!fromwire_custommsg_in(NULL, msg, &custommsg)) { - log_broken(ld->log, "Malformed custommsg from peer %s: %s", - type_to_string(tmpctx, struct node_id, peer_id), - tal_hex(tmpctx, msg)); - return; - } - - p->peer_id = *peer_id; - p->msg = tal_steal(p, custommsg); - plugin_hook_call_custommsg(ld, p); -} - -static struct command_result *json_sendcustommsg(struct command *cmd, - const char *buffer, - const jsmntok_t *obj UNNEEDED, - const jsmntok_t *params) -{ - struct json_stream *response; - struct node_id *dest; - struct peer *peer; - struct subd *owner; - u8 *msg; - int type; - - if (!param(cmd, buffer, params, - p_req("node_id", param_node_id, &dest), - p_req("msg", param_bin_from_hex, &msg), - NULL)) - return command_param_failed(); - - type = fromwire_peektype(msg); - if (peer_wire_is_defined(type)) { - return command_fail( - cmd, JSONRPC2_INVALID_REQUEST, - "Cannot send messages of type %d (%s). It is not possible " - "to send messages that have a type managed internally " - "since that might cause issues with the internal state " - "tracking.", - type, peer_wire_name(type)); - } - - if (type % 2 == 0) { - return command_fail( - cmd, JSONRPC2_INVALID_REQUEST, - "Cannot send even-typed %d custom message. Currently " - "custom messages are limited to odd-numbered message " - "types, as even-numbered types might result in " - "disconnections.", - type); - } - - peer = peer_by_id(cmd->ld, dest); - if (!peer) { - return command_fail(cmd, JSONRPC2_INVALID_REQUEST, - "No such peer: %s", - type_to_string(cmd, struct node_id, dest)); - } - - owner = peer_get_owning_subd(peer); - if (owner == NULL) { - return command_fail(cmd, JSONRPC2_INVALID_REQUEST, - "Peer is not connected: %s", - type_to_string(cmd, struct node_id, dest)); - } - - /* Only a couple of subdaemons have the ability to send custom - * messages. We whitelist those, and error if the current owner is not - * in the whitelist. The reason is that some subdaemons do not handle - * spontaneous messages from the master well (I'm looking at you - * `closingd`...). */ - if (!streq(owner->name, "channeld") && - !streq(owner->name, "openingd")) { - return command_fail(cmd, JSONRPC2_INVALID_REQUEST, - "Peer is currently owned by %s which does " - "not support injecting custom messages.", - owner->name); - } - - subd_send_msg(owner, take(towire_custommsg_out(cmd, msg))); - - response = json_stream_success(cmd); - json_add_string(response, "status", - tal_fmt(cmd, - "Message sent to subdaemon %s for delivery", - owner->name)); - - return command_success(cmd, response); -} - -static const struct json_command sendcustommsg_command = { - "sendcustommsg", - "utility", - json_sendcustommsg, - "Send a custom message to the peer with the given {node_id}", - .verbose = "sendcustommsg node_id hexcustommsg", -}; - -AUTODATA(json_command, &sendcustommsg_command); - -#ifdef COMPAT_V0100 -#ifdef DEVELOPER -static const struct json_command dev_sendcustommsg_command = { - "dev-sendcustommsg", - "utility", - json_sendcustommsg, - "Send a custom message to the peer with the given {node_id}", - .verbose = "dev-sendcustommsg node_id hexcustommsg", -}; - -AUTODATA(json_command, &dev_sendcustommsg_command); -#endif /* DEVELOPER */ -#endif /* COMPAT_V0100 */ diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index ecdc39b39a7e..601285935ed5 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -97,9 +97,6 @@ struct htlc_in_map *load_channels_from_wallet(struct lightningd *ld); void peer_dev_memleak(struct command *cmd); #endif /* DEVELOPER */ -void handle_custommsg_in(struct lightningd *ld, const struct node_id *peer_id, - const u8 *msg); - /* Triggered at each new block. */ void waitblockheight_notify_new_block(struct lightningd *ld, u32 block_height); diff --git a/lightningd/subd.c b/lightningd/subd.c index 56a6d49bd810..e64ffb3da3a6 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -17,7 +17,6 @@ #include #include #include -#include #include /* Carefully move fd *@from to @to: on success *from set to to */ @@ -816,8 +815,7 @@ void subd_send_msg(struct subd *sd, const u8 *msg_out) u16 type = fromwire_peektype(msg_out); /* FIXME: We should use unique upper bits for each daemon, then * have generate-wire.py add them, just assert here. */ - assert(!strstarts(common_wire_name(type), "INVALID") || - !strstarts(sd->msgname(type), "INVALID")); + assert(!strstarts(sd->msgname(type), "INVALID")); msg_enqueue(sd->outq, msg_out); } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 5af0727915fe..7d40e18d034c 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -480,11 +480,6 @@ struct command_result *param_array(struct command *cmd UNNEEDED, const char *nam const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, const jsmntok_t **arr UNNEEDED) { fprintf(stderr, "param_array called!\n"); abort(); } -/* Generated stub for param_bin_from_hex */ -struct command_result *param_bin_from_hex(struct command *cmd UNNEEDED, const char *name UNNEEDED, - const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - u8 **bin UNNEEDED) -{ fprintf(stderr, "param_bin_from_hex called!\n"); abort(); } /* Generated stub for param_bool */ struct command_result *param_bool(struct command *cmd UNNEEDED, const char *name UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, @@ -558,9 +553,6 @@ struct command_result *param_u64(struct command *cmd UNNEEDED, const char *name /* Generated stub for peer_active_channel */ struct channel *peer_active_channel(struct peer *peer UNNEEDED) { fprintf(stderr, "peer_active_channel called!\n"); abort(); } -/* Generated stub for peer_get_owning_subd */ -struct subd *peer_get_owning_subd(struct peer *peer UNNEEDED) -{ fprintf(stderr, "peer_get_owning_subd called!\n"); abort(); } /* Generated stub for peer_memleak_done */ void peer_memleak_done(struct command *cmd UNNEEDED, struct subd *leaker UNNEEDED) { fprintf(stderr, "peer_memleak_done called!\n"); abort(); } diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 51cbab0d8a71..1fad044a41b6 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -42,7 +42,6 @@ #include #include #include -#include #include /* stdin == lightningd, 3 == peer, 4 == gossipd, 5 = hsmd */ @@ -891,17 +890,6 @@ static void dualopend_dev_memleak(struct state *state) } #endif /* DEVELOPER */ -/* We were told to send a custommsg to the peer by `lightningd`. All the - * verification is done on the side of `lightningd` so we should be good to - * just forward it here. */ -static void dualopend_send_custommsg(struct state *state, const u8 *msg) -{ - u8 *inner; - if (!fromwire_custommsg_out(tmpctx, msg, &inner)) - master_badmsg(WIRE_CUSTOMMSG_OUT, msg); - peer_write(state->pps, take(inner)); -} - static u8 *psbt_to_tx_sigs_msg(const tal_t *ctx, struct state *state, const struct wally_psbt *psbt) @@ -3467,23 +3455,6 @@ static void handle_gossip_in(struct state *state) handle_gossip_msg(state->pps, take(msg)); } -/* Try to handle a custommsg Returns true if it was a custom message and has - * been handled, false if the message was not handled. - */ -static bool dualopend_handle_custommsg(const u8 *msg) -{ - enum peer_wire type = fromwire_peektype(msg); - if (type % 2 == 1 && !peer_wire_is_defined(type)) { - /* The message is not part of the messages we know how to - * handle. Assuming this is a custommsg, we just forward it to the - * master. */ - wire_sync_write(REQ_FD, take(towire_custommsg_in(NULL, msg))); - return true; - } else { - return false; - } -} - /* BOLT #2: * * A receiving node: @@ -3586,10 +3557,9 @@ static void do_reconnect_dance(struct state *state) do { clean_tmpctx(); msg = peer_read(tmpctx, state->pps); - } while (dualopend_handle_custommsg(msg) - || handle_peer_gossip_or_error(state->pps, - &state->channel_id, - soft_error, msg)); + } while (handle_peer_gossip_or_error(state->pps, + &state->channel_id, + soft_error, msg)); if (!fromwire_channel_reestablish (msg, &cid, @@ -3707,16 +3677,6 @@ static u8 *handle_master_in(struct state *state) case WIRE_DUALOPEND_LOCAL_PRIVATE_CHANNEL: break; } - - /* Now handle common messages. */ - switch ((enum common_wire)t) { - case WIRE_CUSTOMMSG_OUT: - dualopend_send_custommsg(state, msg); - /* We send these. */ - case WIRE_CUSTOMMSG_IN: - break; - } - status_failed(STATUS_FAIL_MASTER_IO, "Unknown msg %s", tal_hex(tmpctx, msg)); } @@ -3794,16 +3754,6 @@ static u8 *handle_peer_in(struct state *state) break; } - /* Handle custommsgs */ - enum peer_wire type = fromwire_peektype(msg); - if (type % 2 == 1 && !peer_wire_is_defined(type)) { - /* The message is not part of the messages we know how to - * handle. Assuming this is a custommsg, we just - * forward it to master. */ - wire_sync_write(REQ_FD, take(towire_custommsg_in(NULL, msg))); - return NULL; - } - /* Handles standard cases, and legal unknown ones. */ if (handle_peer_gossip_or_error(state->pps, &state->channel_id, false, msg)) diff --git a/openingd/openingd.c b/openingd/openingd.c index e94c31f74437..43cf0618f57e 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -1260,16 +1259,6 @@ static u8 *handle_peer_in(struct state *state) if (t == WIRE_OPEN_CHANNEL) return fundee_channel(state, msg); - /* Handle custommsgs */ - enum peer_wire type = fromwire_peektype(msg); - if (type % 2 == 1 && !peer_wire_is_defined(type)) { - /* The message is not part of the messages we know how to - * handle. Assuming this is a custommsg, we just forward it to the - * master. */ - wire_sync_write(REQ_FD, take(towire_custommsg_in(NULL, msg))); - return NULL; - } - /* Handles standard cases, and legal unknown ones. */ if (handle_peer_gossip_or_error(state->pps, &state->channel_id, false, msg)) @@ -1334,17 +1323,6 @@ static void handle_dev_memleak(struct state *state, const u8 *msg) } #endif /* DEVELOPER */ -/* We were told to send a custommsg to the peer by `lightningd`. All the - * verification is done on the side of `lightningd` so we should be good to - * just forward it here. */ -static void openingd_send_custommsg(struct state *state, const u8 *msg) -{ - u8 *inner; - if (!fromwire_custommsg_out(tmpctx, msg, &inner)) - master_badmsg(WIRE_CUSTOMMSG_OUT, msg); - peer_write(state->pps, take(inner)); -} - /* Standard lightningd-fd-is-ready-to-read demux code. Again, we could hang * here, but if we can't trust our parent, who can we trust? */ static u8 *handle_master_in(struct state *state) @@ -1406,16 +1384,6 @@ static u8 *handle_master_in(struct state *state) break; } - /* Now handle common messages. */ - switch ((enum common_wire)t) { - case WIRE_CUSTOMMSG_OUT: - openingd_send_custommsg(state, msg); - return NULL; - /* We send these. */ - case WIRE_CUSTOMMSG_IN: - break; - } - status_failed(STATUS_FAIL_MASTER_IO, "Unknown msg %s", tal_hex(tmpctx, msg)); } diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 4b18694214b3..e4c7b74b1e69 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -128,9 +128,6 @@ bool fromwire_channeld_sending_commitsig(const tal_t *ctx UNNEEDED, const void * /* Generated stub for fromwire_connectd_peer_connected */ bool fromwire_connectd_peer_connected(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct node_id *id UNNEEDED, struct wireaddr_internal *addr UNNEEDED, bool *incoming UNNEEDED, u8 **features UNNEEDED) { fprintf(stderr, "fromwire_connectd_peer_connected called!\n"); abort(); } -/* Generated stub for fromwire_custommsg_in */ -bool fromwire_custommsg_in(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **msg UNNEEDED) -{ fprintf(stderr, "fromwire_custommsg_in called!\n"); abort(); } /* Generated stub for fromwire_hsmd_get_output_scriptpubkey_reply */ bool fromwire_hsmd_get_output_scriptpubkey_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u8 **script UNNEEDED) { fprintf(stderr, "fromwire_hsmd_get_output_scriptpubkey_reply called!\n"); abort(); } @@ -521,11 +518,6 @@ void outpointfilter_remove(struct outpointfilter *of UNNEEDED, bool param(struct command *cmd UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t params[] UNNEEDED, ...) { fprintf(stderr, "param called!\n"); abort(); } -/* Generated stub for param_bin_from_hex */ -struct command_result *param_bin_from_hex(struct command *cmd UNNEEDED, const char *name UNNEEDED, - const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, - u8 **bin UNNEEDED) -{ fprintf(stderr, "param_bin_from_hex called!\n"); abort(); } /* Generated stub for param_bool */ struct command_result *param_bool(struct command *cmd UNNEEDED, const char *name UNNEEDED, const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, @@ -591,9 +583,6 @@ void payment_store(struct lightningd *ld UNNEEDED, struct wallet_payment *paymen void payment_succeeded(struct lightningd *ld UNNEEDED, struct htlc_out *hout UNNEEDED, const struct preimage *rval UNNEEDED) { fprintf(stderr, "payment_succeeded called!\n"); abort(); } -/* Generated stub for peer_get_owning_subd */ -struct subd *peer_get_owning_subd(struct peer *peer UNNEEDED) -{ fprintf(stderr, "peer_get_owning_subd called!\n"); abort(); } /* Generated stub for peer_memleak_done */ void peer_memleak_done(struct command *cmd UNNEEDED, struct subd *leaker UNNEEDED) { fprintf(stderr, "peer_memleak_done called!\n"); abort(); } @@ -616,12 +605,6 @@ void peer_start_dualopend(struct peer *peer UNNEEDED, int peer_fd UNNEEDED, int void peer_start_openingd(struct peer *peer UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED) { fprintf(stderr, "peer_start_openingd called!\n"); abort(); } -/* Generated stub for peer_wire_is_defined */ -bool peer_wire_is_defined(u16 type UNNEEDED) -{ fprintf(stderr, "peer_wire_is_defined called!\n"); abort(); } -/* Generated stub for peer_wire_name */ -const char *peer_wire_name(int e UNNEEDED) -{ fprintf(stderr, "peer_wire_name called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ bool plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, tal_t *cb_arg STEALS UNNEEDED) @@ -710,9 +693,6 @@ u8 *towire_connectd_peer_disconnected(const tal_t *ctx UNNEEDED, const struct no /* Generated stub for towire_connectd_peer_final_msg */ u8 *towire_connectd_peer_final_msg(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, const u8 *msg UNNEEDED) { fprintf(stderr, "towire_connectd_peer_final_msg called!\n"); abort(); } -/* Generated stub for towire_custommsg_out */ -u8 *towire_custommsg_out(const tal_t *ctx UNNEEDED, const u8 *msg UNNEEDED) -{ fprintf(stderr, "towire_custommsg_out called!\n"); abort(); } /* Generated stub for towire_errorfmt */ u8 *towire_errorfmt(const tal_t *ctx UNNEEDED, const struct channel_id *channel UNNEEDED, diff --git a/wire/Makefile b/wire/Makefile index 9651eaf1e895..44380df67b91 100644 --- a/wire/Makefile +++ b/wire/Makefile @@ -10,7 +10,6 @@ WIRE_HEADERS := wire/onion_defs.h \ wire/peer$(EXP)_wiregen.h \ wire/onion$(EXP)_wiregen.h \ wire/bolt12$(EXP)_wiregen.h \ - wire/common_wiregen.h \ wire/channel_type_wiregen.h \ wire/peer$(EXP)_printgen.h \ wire/onion$(EXP)_printgen.h @@ -22,7 +21,6 @@ WIRE_SRC := wire/wire_sync.c \ wire/peer_wire.c \ wire/tlvstream.c \ wire/towire.c \ - wire/common_wiregen.c \ wire/bolt12$(EXP)_wiregen.c \ wire/peer$(EXP)_wiregen.c \ wire/channel_type_wiregen.c \ diff --git a/wire/common_wire.csv b/wire/common_wire.csv deleted file mode 100644 index 7e607c806ccc..000000000000 --- a/wire/common_wire.csv +++ /dev/null @@ -1,10 +0,0 @@ -# A custom message that we got from a peer and don't know how to handle, so we -# forward it to the master for further handling. -msgtype,custommsg_in,1030 -msgdata,custommsg_in,msg_len,u16, -msgdata,custommsg_in,msg,u8,msg_len - -# A custom message that the master tells us to send to the peer. -msgtype,custommsg_out,1031 -msgdata,custommsg_out,msg_len,u16, -msgdata,custommsg_out,msg,u8,msg_len From 460d78e6cdf0857e0f223eeeefbde2e4b1325b10 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:07:00 +1030 Subject: [PATCH 46/51] channeld: simply exit if hsmd vanishes. We currently die when gossipd vanishes, but our direct connection will go away. We then complain if the node is shutting down while we're talking to hsmd. Signed-off-by: Rusty Russell --- channeld/Makefile | 1 + channeld/channeld.c | 15 +++++---------- channeld/channeld.h | 10 ++++++++++ channeld/watchtower.c | 15 ++++++--------- 4 files changed, 22 insertions(+), 19 deletions(-) create mode 100644 channeld/channeld.h diff --git a/channeld/Makefile b/channeld/Makefile index 2c9e89d758e2..bef41c69a92a 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -4,6 +4,7 @@ CHANNELD_HEADERS := \ channeld/full_channel_error_names_gen.h \ channeld/channeld_wiregen.h \ channeld/channeld_htlc.h \ + channeld/channeld.h \ channeld/commit_tx.h \ channeld/full_channel.h \ channeld/full_channel_error.h \ diff --git a/channeld/channeld.c b/channeld/channeld.c index bdb1609f8f52..df48e959ff60 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -193,23 +194,17 @@ static void billboard_update(const struct peer *peer) peer_billboard(false, update); } -static const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES) +const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES) { u8 *msg; - int type = fromwire_peektype(req); + /* hsmd goes away at shutdown. That's OK. */ if (!wire_sync_write(HSM_FD, req)) - status_failed(STATUS_FAIL_HSM_IO, - "Writing %s to HSM: %s", - hsmd_wire_name(type), - strerror(errno)); + exit(0); msg = wire_sync_read(ctx, HSM_FD); if (!msg) - status_failed(STATUS_FAIL_HSM_IO, - "Reading resp to %s: %s", - hsmd_wire_name(type), - strerror(errno)); + exit(0); return msg; } diff --git a/channeld/channeld.h b/channeld/channeld.h new file mode 100644 index 000000000000..a2b26b08246a --- /dev/null +++ b/channeld/channeld.h @@ -0,0 +1,10 @@ +#ifndef LIGHTNING_CHANNELD_CHANNELD_H +#define LIGHTNING_CHANNELD_CHANNELD_H +#include "config.h" +#include +#include +#include + +const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES); + +#endif /* LIGHTNING_CHANNELD_CHANNELD_H */ diff --git a/channeld/watchtower.c b/channeld/watchtower.c index a895dfc1d31b..744588d72da6 100644 --- a/channeld/watchtower.c +++ b/channeld/watchtower.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -26,7 +27,7 @@ penalty_tx_create(const tal_t *ctx, struct bitcoin_tx *tx; struct keyset keyset; size_t weight; - u8 *msg; + const u8 *msg; struct amount_sat fee, min_out, amt; struct bitcoin_signature sig; u32 locktime = 0; @@ -105,16 +106,12 @@ penalty_tx_create(const tal_t *ctx, bitcoin_tx_finalize(tx); u8 *hsm_sign_msg = - towire_hsmd_sign_penalty_to_us(ctx, &remote_per_commitment_secret, + towire_hsmd_sign_penalty_to_us(tmpctx, &remote_per_commitment_secret, tx, wscript); - if (!wire_sync_write(hsm_fd, take(hsm_sign_msg))) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Writing sign request to hsm"); - - msg = wire_sync_read(tmpctx, hsm_fd); - if (!msg || !fromwire_hsmd_sign_tx_reply(msg, &sig)) - status_failed(STATUS_FAIL_INTERNAL_ERROR, + msg = hsm_req(tmpctx, hsm_sign_msg); + if (!fromwire_hsmd_sign_tx_reply(msg, &sig)) + status_failed(STATUS_FAIL_HSM_IO, "Reading sign_tx_reply: %s", tal_hex(tmpctx, msg)); witness = bitcoin_witness_sig_and_element(tx, &sig, &ONE, sizeof(ONE), From bcf867d9c43fa2a113a5cb7c39e9c6f4077f0e54 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:07:00 +1030 Subject: [PATCH 47/51] subdaemons: remove gossipd fd from per-peer daemons. Signed-off-by: Rusty Russell --- channeld/channeld.c | 27 ++---- closingd/closingd.c | 17 ++-- common/peer_failed.c | 1 - common/per_peer_state.c | 18 +--- common/per_peer_state.h | 10 +-- common/read_peer_msg.c | 96 ++------------------- common/read_peer_msg.h | 42 ++------- connectd/connectd.c | 28 +++--- connectd/connectd.h | 3 + connectd/connectd_wire.csv | 4 +- lightningd/channel_control.c | 9 +- lightningd/channel_control.h | 2 +- lightningd/closing_control.c | 4 +- lightningd/closing_control.h | 2 +- lightningd/connect_control.c | 6 +- lightningd/dual_open_control.c | 25 +++--- lightningd/dual_open_control.h | 4 +- lightningd/onchain_control.c | 2 +- lightningd/opening_common.c | 8 +- lightningd/opening_common.h | 4 +- lightningd/opening_control.c | 26 +++--- lightningd/opening_control.h | 3 +- lightningd/peer_control.c | 20 ++--- lightningd/peer_control.h | 5 +- lightningd/subd.c | 16 ++-- lightningd/subd.h | 6 +- lightningd/test/run-invoice-select-inchan.c | 9 +- openingd/dualopend.c | 61 +++---------- openingd/openingd.c | 61 +++---------- wallet/test/run-wallet.c | 9 +- 30 files changed, 148 insertions(+), 380 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index df48e959ff60..117311f0c931 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -45,9 +45,9 @@ #include #include -/* stdin == requests, 3 == peer, 4 = gossip, 5 = HSM */ +/* stdin == requests, 3 == peer, 4 = HSM */ #define MASTER_FD STDIN_FILENO -#define HSM_FD 5 +#define HSM_FD 4 struct peer { struct per_peer_state *pps; @@ -2119,13 +2119,12 @@ static void peer_in(struct peer *peer, const u8 *msg) /* Since LND seems to send errors which aren't actually fatal events, * we treat errors here as soft. */ - if (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, soft_error, msg)) + if (handle_peer_error(peer->pps, &peer->channel_id, soft_error, msg)) return; /* Must get funding_locked before almost anything. */ if (!peer->funding_locked[REMOTE]) { if (type != WIRE_FUNDING_LOCKED - && type != WIRE_PONG && type != WIRE_SHUTDOWN /* We expect these for v2 !! */ && type != WIRE_TX_SIGNATURES @@ -2202,7 +2201,7 @@ static void peer_in(struct peer *peer, const u8 *msg) handle_unexpected_reestablish(peer, msg); return; - /* These are all swallowed by handle_peer_gossip_or_error */ + /* These are all swallowed by connectd */ case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_CHANNEL_UPDATE: case WIRE_NODE_ANNOUNCEMENT: @@ -2787,8 +2786,8 @@ static void peer_reconnect(struct peer *peer, do { clean_tmpctx(); msg = peer_read(tmpctx, peer->pps); - } while (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, soft_error, - msg) || + } while (handle_peer_error(peer->pps, &peer->channel_id, soft_error, + msg) || capture_premature_msg(&premature_msgs, msg)); got_reestablish: @@ -3744,9 +3743,9 @@ static void init_channel(struct peer *peer) tal_dup(peer, struct penalty_base, &pbases[i])); tal_free(pbases); - /* stdin == requests, 3 == peer, 4 = gossip */ + /* stdin == requests, 3 == peer */ peer->pps = new_per_peer_state(peer); - per_peer_state_set_fds(peer->pps, 3, 4); + per_peer_state_set_fd(peer->pps, 3); status_debug("init %s: remote_per_commit = %s, old_remote_per_commit = %s" " next_idx_local = %"PRIu64 @@ -3892,11 +3891,10 @@ int main(int argc, char *argv[]) FD_ZERO(&fds_in); FD_SET(MASTER_FD, &fds_in); FD_SET(peer->pps->peer_fd, &fds_in); - FD_SET(peer->pps->gossip_fd, &fds_in); FD_ZERO(&fds_out); FD_SET(peer->pps->peer_fd, &fds_out); - nfds = peer->pps->gossip_fd+1; + nfds = peer->pps->peer_fd+1; while (!shutdown_complete(peer)) { struct timemono first; @@ -3955,13 +3953,6 @@ int main(int argc, char *argv[]) /* This could take forever, but who cares? */ msg = peer_read(tmpctx, peer->pps); peer_in(peer, msg); - } else if (FD_ISSET(peer->pps->gossip_fd, &rfds)) { - msg = wire_sync_read(tmpctx, peer->pps->gossip_fd); - /* Gossipd hangs up on us to kill us when a new - * connection comes in. */ - if (!msg) - peer_failed_connection_lost(); - handle_gossip_msg(peer->pps, take(msg)); } } diff --git a/closingd/closingd.c b/closingd/closingd.c index e013b5781dce..7cf8fb296c3d 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -30,9 +30,9 @@ #include #include -/* stdin == requests, 3 == peer, 4 = gossip, 5 = hsmd */ +/* stdin == requests, 3 == peer, 4 = hsmd */ #define REQ_FD STDIN_FILENO -#define HSM_FD 5 +#define HSM_FD 4 static void notify(enum log_level level, const char *fmt, ...) { @@ -118,15 +118,10 @@ static u8 *closing_read_peer_msg(const tal_t *ctx, { for (;;) { u8 *msg; - bool from_gossipd; clean_tmpctx(); - msg = peer_or_gossip_sync_read(ctx, pps, &from_gossipd); - if (from_gossipd) { - handle_gossip_msg(pps, take(msg)); - continue; - } - if (!handle_peer_gossip_or_error(pps, channel_id, false, msg)) + msg = peer_read(ctx, pps); + if (!handle_peer_error(pps, channel_id, false, msg)) return msg; } } @@ -906,9 +901,9 @@ int main(int argc, char *argv[]) &wrong_funding)) master_badmsg(WIRE_CLOSINGD_INIT, msg); - /* stdin == requests, 3 == peer, 4 = gossip, 5 = hsmd */ + /* stdin == requests, 3 == peer, 4 = hsmd */ pps = notleak(new_per_peer_state(ctx)); - per_peer_state_set_fds(pps, 3, 4); + per_peer_state_set_fd(pps, 3); funding_wscript = bitcoin_redeem_2of2(ctx, &funding_pubkey[LOCAL], diff --git a/common/peer_failed.c b/common/peer_failed.c index e9f5487dafdc..c9c18d84dbe7 100644 --- a/common/peer_failed.c +++ b/common/peer_failed.c @@ -19,7 +19,6 @@ peer_fatal_continue(const u8 *msg TAKES, const struct per_peer_state *pps) status_send(msg); status_send_fd(pps->peer_fd); - status_send_fd(pps->gossip_fd); exit(0x80 | (reason & 0xFF)); } diff --git a/common/per_peer_state.c b/common/per_peer_state.c index b33305538d27..981e06c07126 100644 --- a/common/per_peer_state.c +++ b/common/per_peer_state.c @@ -12,39 +12,25 @@ static void destroy_per_peer_state(struct per_peer_state *pps) { if (pps->peer_fd != -1) close(pps->peer_fd); - if (pps->gossip_fd != -1) - close(pps->gossip_fd); } struct per_peer_state *new_per_peer_state(const tal_t *ctx) { struct per_peer_state *pps = tal(ctx, struct per_peer_state); - pps->peer_fd = pps->gossip_fd = -1; + pps->peer_fd = -1; tal_add_destructor(pps, destroy_per_peer_state); return pps; } -void per_peer_state_set_fds(struct per_peer_state *pps, - int peer_fd, int gossip_fd) +void per_peer_state_set_fd(struct per_peer_state *pps, int peer_fd) { assert(pps->peer_fd == -1); - assert(pps->gossip_fd == -1); pps->peer_fd = peer_fd; - pps->gossip_fd = gossip_fd; -} - -void per_peer_state_set_fds_arr(struct per_peer_state *pps, const int *fds) -{ - /* We expect 2 fds. */ - assert(tal_count(fds) == 2); - per_peer_state_set_fds(pps, fds[0], fds[1]); } void per_peer_state_fdpass_send(int fd, const struct per_peer_state *pps) { assert(pps->peer_fd != -1); - assert(pps->gossip_fd != -1); fdpass_send(fd, pps->peer_fd); - fdpass_send(fd, pps->gossip_fd); } diff --git a/common/per_peer_state.h b/common/per_peer_state.h index af41d95f0a8d..0561d8ce2870 100644 --- a/common/per_peer_state.h +++ b/common/per_peer_state.h @@ -9,19 +9,15 @@ /* Things we hand between daemons to talk to peers. */ struct per_peer_state { /* If not -1, closed on freeing */ - int peer_fd, gossip_fd; + int peer_fd; }; /* Allocate a new per-peer state and add destructor to close fds if set; - * sets fds to -1. */ + * sets peer_fd to -1. */ struct per_peer_state *new_per_peer_state(const tal_t *ctx); /* Initialize the fds (must be -1 previous) */ -void per_peer_state_set_fds(struct per_peer_state *pps, - int peer_fd, int gossip_fd); - -/* Array version of above: tal_count(fds) must be 2 */ -void per_peer_state_set_fds_arr(struct per_peer_state *pps, const int *fds); +void per_peer_state_set_fd(struct per_peer_state *pps, int peer_fd); void per_peer_state_fdpass_send(int fd, const struct per_peer_state *pps); diff --git a/common/read_peer_msg.c b/common/read_peer_msg.c index fe841108c6c4..bda5ae73f455 100644 --- a/common/read_peer_msg.c +++ b/common/read_peer_msg.c @@ -12,39 +12,6 @@ #include #include -u8 *peer_or_gossip_sync_read(const tal_t *ctx, - struct per_peer_state *pps, - bool *from_gossipd) -{ - fd_set readfds; - u8 *msg; - - 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, NULL) <= 0) { - status_failed(STATUS_FAIL_GOSSIP_IO, - "select failed?: %s", strerror(errno)); - } - - if (FD_ISSET(pps->peer_fd, &readfds)) { - msg = peer_read(ctx, pps); - *from_gossipd = false; - return msg; - } - - msg = wire_sync_read(ctx, pps->gossip_fd); - if (!msg) - status_failed(STATUS_FAIL_GOSSIP_IO, - "Error reading gossip msg: %s", - strerror(errno)); - *from_gossipd = true; - return msg; -} - bool is_peer_error(const tal_t *ctx, const u8 *msg, const struct channel_id *channel_id, char **desc, bool *warning) @@ -94,72 +61,27 @@ bool is_wrong_channel(const u8 *msg, const struct channel_id *expected, return !channel_id_eq(expected, actual); } -void handle_gossip_msg(struct per_peer_state *pps, const u8 *msg TAKES) -{ - u8 *gossip; - - /* It's a raw gossip msg: this copies or takes() */ - gossip = tal_dup_talarr(tmpctx, u8, msg); - - /* Gossipd can send us gossip messages, OR warnings */ - if (fromwire_peektype(gossip) == WIRE_WARNING) { - peer_write(pps, gossip); - peer_failed_connection_lost(); - } else { - peer_write(pps, gossip); - } -} - -bool handle_peer_gossip_or_error(struct per_peer_state *pps, - const struct channel_id *channel_id, - bool soft_error, - const u8 *msg TAKES) +bool handle_peer_error(struct per_peer_state *pps, + const struct channel_id *channel_id, + bool soft_error, + const u8 *msg TAKES) { char *err; bool warning; - u8 *pong; - -#if DEVELOPER - /* Any odd-typed unknown message is handled by the caller, so if we - * find one here it's an error. */ - assert(!is_unknown_msg_discardable(msg)); -#else - /* BOLT #1: - * - * A receiving node: - * - upon receiving a message of _odd_, unknown type: - * - MUST ignore the received message. - */ - if (is_unknown_msg_discardable(msg)) - goto handled; -#endif - - if (check_ping_make_pong(NULL, msg, &pong)) { - if (pong) - peer_write(pps, take(pong)); - return true; - } else if (is_msg_for_gossipd(msg)) { - wire_sync_write(pps->gossip_fd, msg); - /* wire_sync_write takes, so don't take again. */ - return true; - } if (is_peer_error(tmpctx, msg, channel_id, &err, &warning)) { /* Ignore unknown channel errors. */ - if (!err) - goto handled; + if (!err) { + if (taken(msg)) + tal_free(msg); + return true; + } /* We hang up when a warning is received. */ peer_failed_received_errmsg(pps, err, channel_id, soft_error || warning); - goto handled; } return false; - -handled: - if (taken(msg)) - tal_free(msg); - return true; } diff --git a/common/read_peer_msg.h b/common/read_peer_msg.h index fbdff761a759..7a4052a0e90e 100644 --- a/common/read_peer_msg.h +++ b/common/read_peer_msg.h @@ -8,25 +8,6 @@ struct crypto_state; struct channel_id; struct per_peer_state; -/** - * peer_or_gossip_sync_read - read a peer message, or maybe a gossip msg. - * @ctx: context to allocate return packet from. - * @pps: the per-peer peer state and fds - * @from_gossipd: true if the msg was from gossipd, otherwise false. - * - * Will call peer_failed_connection_lost() or - * status_failed(STATUS_FAIL_GOSSIP_IO) or return a message. - * - * Usually, you should call handle_gossip_msg if *@from_gossipd is - * true, otherwise if is_peer_error() handle the error, otherwise if - * is_msg_for_gossipd() then send to gossipd, otherwise if is - * is_wrong_channel() send that as a reply. Otherwise it should be - * a valid message. - */ -u8 *peer_or_gossip_sync_read(const tal_t *ctx, - struct per_peer_state *pps, - bool *from_gossipd); - /** * is_peer_error - if it's an error, describe if it applies to this channel. * @ctx: context to allocate return from. @@ -55,28 +36,17 @@ bool is_wrong_channel(const u8 *msg, const struct channel_id *expected, /** - * handle_peer_gossip_or_error - simple handler for all the above cases. + * handle_peer_error - simple handler for errors * @pps: per-peer state. * @channel_id: the channel id of the current channel. * @soft_error: tell lightningd that incoming error is non-fatal. * @msg: the peer message (only taken if returns true). * - * This returns true if it handled the packet: a gossip packet (forwarded - * to gossipd), or an error packet (causes peer_failed_received_errmsg or - * ignored), or a ping (may reply with pong). - */ -bool handle_peer_gossip_or_error(struct per_peer_state *pps, - const struct channel_id *channel_id, - bool soft_error, - const u8 *msg TAKES); - -/** - * handle_timestamp_filter - deal with timestamp filter requests. - * @pps: per-peer state. - * @msg: the peer message (only taken if returns true). + * This returns true if it handled the packet. */ -bool handle_timestamp_filter(struct per_peer_state *pps, const u8 *msg TAKES); +bool handle_peer_error(struct per_peer_state *pps, + const struct channel_id *channel_id, + bool soft_error, + const u8 *msg TAKES); -/* We got this message from gossipd: forward/quit as it asks. */ -void handle_gossip_msg(struct per_peer_state *pps, const u8 *msg TAKES); #endif /* LIGHTNING_COMMON_READ_PEER_MSG_H */ diff --git a/connectd/connectd.c b/connectd/connectd.c index 68e8fe71d991..8018c0c9b783 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -336,6 +336,8 @@ static struct io_plan *peer_reconnected(struct io_conn *conn, /*~ When we free a peer, we remove it from the daemon's hashtable */ static void destroy_peer(struct peer *peer, struct daemon *daemon) { + if (peer->gossip_fd >= 0) + close(peer->gossip_fd); peer_htable_del(&daemon->peers, peer); } @@ -386,7 +388,7 @@ struct io_plan *peer_connected(struct io_conn *conn, struct peer *peer; int unsup; size_t depender, missing; - int subd_fd, gossip_fd; + int subd_fd; peer = peer_htable_get(&daemon->peers, id); if (peer) @@ -445,8 +447,8 @@ struct io_plan *peer_connected(struct io_conn *conn, return io_close(conn); /* If gossipd can't give us a file descriptor, we give up connecting. */ - gossip_fd = get_gossipfd(daemon, id, their_features); - if (gossip_fd < 0) { + peer->gossip_fd = get_gossipfd(daemon, id, their_features); + if (peer->gossip_fd < 0) { close(subd_fd); return tal_free(peer); } @@ -460,10 +462,9 @@ struct io_plan *peer_connected(struct io_conn *conn, /*~ daemon_conn is a message queue for inter-daemon communication: we * queue up the `connect_peer_connected` message to tell lightningd - * we have connected, and give the peer and gossip fds. */ + * we have connected, and give the peer fd. */ daemon_conn_send(daemon->master, take(msg)); daemon_conn_send_fd(daemon->master, subd_fd); - daemon_conn_send_fd(daemon->master, gossip_fd); /*~ Now we set up this connection to read/write from subd */ return multiplex_peer_setup(conn, peer); @@ -1860,20 +1861,19 @@ static void peer_final_msg(struct io_conn *conn, struct peer *peer; struct node_id id; u8 *finalmsg; + int peer_fd; if (!fromwire_connectd_peer_final_msg(tmpctx, msg, &id, &finalmsg)) master_badmsg(WIRE_CONNECTD_PEER_FINAL_MSG, msg); - /* Get the peer_fd and gossip_fd for this peer: we don't need them. */ + /* Get the peer_fd for this peer: we don't need it though! */ io_fd_block(io_conn_fd(conn), true); - for (size_t i = 0; i < 2; i++) { - int fd = fdpass_recv(io_conn_fd(conn)); - if (fd == -1) - status_failed(STATUS_FAIL_MASTER_IO, - "Getting fd %zu after peer_final_msg: %s", - i, strerror(errno)); - close(fd); - } + peer_fd = fdpass_recv(io_conn_fd(conn)); + if (peer_fd == -1) + status_failed(STATUS_FAIL_MASTER_IO, + "Getting peer fd after peer_final_msg: %s", + strerror(errno)); + close(peer_fd); io_fd_block(io_conn_fd(conn), false); /* This can happen if peer hung up on us. */ diff --git a/connectd/connectd.h b/connectd/connectd.h index 93814efc5e3c..23ed9c0cecfe 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -77,6 +77,9 @@ struct peer { /* Random ping timer, to detect dead connections. */ struct oneshot *ping_timer; + + /* FIXME: remove! */ + int gossip_fd; }; /*~ The HTABLE_DEFINE_TYPE() macro needs a keyof() function to extract the key: diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index 01c03335cb32..c735f3c93173 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -60,7 +60,7 @@ msgdata,connectd_connect_failed,failreason,wirestring, msgdata,connectd_connect_failed,seconds_to_delay,u32, msgdata,connectd_connect_failed,addrhint,?wireaddr_internal, -# Connectd -> master: we got a peer. Three fds: peer, gossip and gossip_store +# Connectd -> master: we got a peer. Plus fd for peer daemon msgtype,connectd_peer_connected,2002 msgdata,connectd_peer_connected,id,node_id, msgdata,connectd_peer_connected,addr,wireaddr_internal, @@ -72,7 +72,7 @@ msgdata,connectd_peer_connected,features,u8,flen msgtype,connectd_peer_disconnected,2015 msgdata,connectd_peer_disconnected,id,node_id, -# master -> connectd: give message to peer and disconnect. Three fds: peer, gossip and gossip_store +# master -> connectd: give message to peer and disconnect. Plus fd for peer msgtype,connectd_peer_final_msg,2003 msgdata,connectd_peer_final_msg,id,node_id, msgdata,connectd_peer_final_msg,len,u16, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 49c8406d6f30..3680f8f71a03 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -354,7 +354,7 @@ static void peer_start_closingd_after_shutdown(struct channel *channel, } /* This sets channel->owner, closes down channeld. */ - peer_start_closingd(channel, fds[0], fds[1]); + peer_start_closingd(channel, fds[0]); /* We might have reconnected, so already be here. */ if (!channel_closed(channel) @@ -495,9 +495,9 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) peer_got_shutdown(sd->channel, msg); break; case WIRE_CHANNELD_SHUTDOWN_COMPLETE: - /* We expect 2 fds. */ + /* We expect 1 fd. */ if (!fds) - return 2; + return 1; peer_start_closingd_after_shutdown(sd->channel, msg, fds); break; case WIRE_CHANNELD_FAIL_FALLEN_BEHIND: @@ -556,7 +556,7 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) } void peer_start_channeld(struct channel *channel, - int peer_fd, int gossip_fd, + int peer_fd, const u8 *fwd_msg, bool reconnected, const u8 *reestablish_only) @@ -592,7 +592,6 @@ void peer_start_channeld(struct channel *channel, channel_errmsg, channel_set_billboard, take(&peer_fd), - take(&gossip_fd), take(&hsmfd), NULL)); if (!channel->owner) { diff --git a/lightningd/channel_control.h b/lightningd/channel_control.h index 0cb05b7296b9..cd90c248d9f9 100644 --- a/lightningd/channel_control.h +++ b/lightningd/channel_control.h @@ -10,7 +10,7 @@ struct lightningd; struct peer; void peer_start_channeld(struct channel *channel, - int peer_fd, int gossip_fd, + int peer_fd, const u8 *fwd_msg, bool reconnected, const u8 *reestablish_only); diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index 0d2a0c249c8c..ae49eef40a62 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -337,7 +337,7 @@ static unsigned closing_msg(struct subd *sd, const u8 *msg, const int *fds UNUSE return 0; } -void peer_start_closingd(struct channel *channel, int peer_fd, int gossip_fd) +void peer_start_closingd(struct channel *channel, int peer_fd) { u8 *initmsg; u32 min_feerate, feerate, *max_feerate; @@ -350,7 +350,6 @@ void peer_start_closingd(struct channel *channel, int peer_fd, int gossip_fd) if (!channel->shutdown_scriptpubkey[REMOTE]) { close(peer_fd); - close(gossip_fd); channel_internal_error(channel, "Can't start closing: no remote info"); return; @@ -369,7 +368,6 @@ void peer_start_closingd(struct channel *channel, int peer_fd, int gossip_fd) channel_errmsg, channel_set_billboard, take(&peer_fd), - take(&gossip_fd), take(&hsmfd), NULL)); diff --git a/lightningd/closing_control.h b/lightningd/closing_control.h index e36450d3aab4..4d1e0364242c 100644 --- a/lightningd/closing_control.h +++ b/lightningd/closing_control.h @@ -10,6 +10,6 @@ struct lightningd; void resolve_close_command(struct lightningd *ld, struct channel *channel, bool cooperative); -void peer_start_closingd(struct channel *channel, int peer_fd, int gossip_fd); +void peer_start_closingd(struct channel *channel, int peer_fd); #endif /* LIGHTNING_LIGHTNINGD_CLOSING_CONTROL_H */ diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 6e839a4aaf41..e609e43b6ca6 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -440,9 +440,9 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd break; case WIRE_CONNECTD_PEER_CONNECTED: - if (tal_count(fds) != 2) - return 2; - peer_connected(connectd->ld, msg, fds[0], fds[1]); + if (tal_count(fds) != 1) + return 1; + peer_connected(connectd->ld, msg, fds[0]); break; case WIRE_CONNECTD_CONNECT_FAILED: diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 290bc6b3cfe9..2daae9b2b88b 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1336,11 +1336,10 @@ static void handle_channel_closed(struct subd *dualopend, "Bad DUALOPEND_SHUTDOWN_COMPLETE: %s", tal_hex(msg, msg)); close(fds[0]); - close(fds[1]); return; } - peer_start_closingd(channel, fds[0], fds[1]); + peer_start_closingd(channel, fds[0]); channel_set_state(channel, CHANNELD_SHUTTING_DOWN, CLOSINGD_SIGEXCHANGE, @@ -1653,7 +1652,7 @@ static void handle_channel_locked(struct subd *dualopend, wallet_channel_clear_inflights(dualopend->ld->wallet, channel); /* FIXME: LND sigs/update_fee msgs? */ - peer_start_channeld(channel, fds[0], fds[1], NULL, false, NULL); + peer_start_channeld(channel, fds[0], NULL, false, NULL); return; } @@ -2969,16 +2968,16 @@ static unsigned int dual_opend_msg(struct subd *dualopend, handle_dry_run_finished(dualopend, msg); return 0; case WIRE_DUALOPEND_CHANNEL_LOCKED: - if (tal_count(fds) != 2) - return 2; + if (tal_count(fds) != 1) + return 1; handle_channel_locked(dualopend, fds, msg); return 0; case WIRE_DUALOPEND_GOT_SHUTDOWN: handle_peer_wants_to_close(dualopend, msg); return 0; case WIRE_DUALOPEND_SHUTDOWN_COMPLETE: - if (tal_count(fds) != 2) - return 2; + if (tal_count(fds) != 1) + return 1; handle_channel_closed(dualopend, fds, msg); return 0; case WIRE_DUALOPEND_FAIL_FALLEN_BEHIND: @@ -3182,7 +3181,7 @@ AUTODATA(json_command, &openchannel_bump_command); AUTODATA(json_command, &openchannel_abort_command); static void start_fresh_dualopend(struct peer *peer, - int peer_fd, int gossip_fd, + int peer_fd, struct channel *channel) { int hsmfd; @@ -3205,7 +3204,6 @@ static void start_fresh_dualopend(struct peer *peer, channel_errmsg, channel_set_billboard, take(&peer_fd), - take(&gossip_fd), take(&hsmfd), NULL); if (!channel->owner) { @@ -3242,7 +3240,7 @@ static void start_fresh_dualopend(struct peer *peer, } void peer_restart_dualopend(struct peer *peer, - int peer_fd, int gossip_fd, + int peer_fd, struct channel *channel) { u32 max_to_self_delay, blockheight; @@ -3254,7 +3252,7 @@ void peer_restart_dualopend(struct peer *peer, u8 *msg; if (channel_unsaved(channel)) { - start_fresh_dualopend(peer, peer_fd, gossip_fd, channel); + start_fresh_dualopend(peer, peer_fd, channel); return; } hsmfd = hsm_get_client_fd(peer->ld, &peer->id, channel->dbid, @@ -3272,7 +3270,6 @@ void peer_restart_dualopend(struct peer *peer, channel_errmsg, channel_set_billboard, take(&peer_fd), - take(&gossip_fd), take(&hsmfd), NULL)); if (!channel->owner) { log_broken(channel->log, "Could not subdaemon channel: %s", @@ -3346,7 +3343,7 @@ void peer_restart_dualopend(struct peer *peer, subd_send_msg(channel->owner, take(msg)); } -void peer_start_dualopend(struct peer *peer, int peer_fd, int gossip_fd) +void peer_start_dualopend(struct peer *peer, int peer_fd) { struct channel *channel; @@ -3356,5 +3353,5 @@ void peer_start_dualopend(struct peer *peer, int peer_fd, int gossip_fd) peer->ld->config.fee_base, peer->ld->config.fee_per_satoshi); - start_fresh_dualopend(peer, peer_fd, gossip_fd, channel); + start_fresh_dualopend(peer, peer_fd, channel); } diff --git a/lightningd/dual_open_control.h b/lightningd/dual_open_control.h index f7a11d786321..479aca10074e 100644 --- a/lightningd/dual_open_control.h +++ b/lightningd/dual_open_control.h @@ -4,10 +4,10 @@ #include "config.h" #include -void peer_start_dualopend(struct peer *peer, int peer_fd, int gossip_fd); +void peer_start_dualopend(struct peer *peer, int peer_fd); void peer_restart_dualopend(struct peer *peer, - int peer_fd, int gossip_fd, + int peer_fd, struct channel *channel); void dualopen_tell_depth(struct subd *dualopend, diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index c6b77e9b47a1..2531a01bedba 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -571,7 +571,7 @@ static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds U /* Only error onchaind can get is if it dies. */ static void onchain_error(struct channel *channel, - int peer_fd UNUSED, int gossip_fd UNUSED, + int peer_fd UNUSED, const struct channel_id *channel_id UNUSED, const char *desc, bool warning UNUSED, diff --git a/lightningd/opening_common.c b/lightningd/opening_common.c index eb2ff1aecce0..e817d6967d60 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -75,7 +75,7 @@ new_uncommitted_channel(struct peer *peer) } void opend_channel_errmsg(struct uncommitted_channel *uc, - int peer_fd, int gossip_fd, + int peer_fd, const struct channel_id *channel_id UNUSED, const char *desc, bool warning UNUSED, @@ -83,7 +83,6 @@ void opend_channel_errmsg(struct uncommitted_channel *uc, { /* Close fds, if any. */ close(peer_fd); - close(gossip_fd); uncommitted_channel_disconnect(uc, LOG_INFORM, desc); tal_free(uc); } @@ -169,7 +168,7 @@ void handle_reestablish(struct lightningd *ld, const struct node_id *peer_id, const struct channel_id *channel_id, const u8 *reestablish, - int peer_fd, int gossip_fd) + int peer_fd) { struct peer *peer; struct channel *c; @@ -185,7 +184,7 @@ void handle_reestablish(struct lightningd *ld, if (c && channel_closed(c)) { log_debug(c->log, "Reestablish on %s channel: using channeld to reply", channel_state_name(c)); - peer_start_channeld(c, peer_fd, gossip_fd, NULL, true, + peer_start_channeld(c, peer_fd, NULL, true, reestablish); } else { const u8 *err = towire_errorfmt(tmpctx, channel_id, @@ -196,7 +195,6 @@ void handle_reestablish(struct lightningd *ld, take(towire_connectd_peer_final_msg(NULL, peer_id, err))); subd_send_fd(ld->connectd, peer_fd); - subd_send_fd(ld->connectd, gossip_fd); } } diff --git a/lightningd/opening_common.h b/lightningd/opening_common.h index 644a876f59e6..9e60d30c46e6 100644 --- a/lightningd/opening_common.h +++ b/lightningd/opening_common.h @@ -95,7 +95,7 @@ struct uncommitted_channel * new_uncommitted_channel(struct peer *peer); void opend_channel_errmsg(struct uncommitted_channel *uc, - int peer_fd, int gossip_fd, + int peer_fd, const struct channel_id *channel_id UNUSED, const char *desc, bool warning UNUSED, @@ -121,7 +121,7 @@ void handle_reestablish(struct lightningd *ld, const struct node_id *peer_id, const struct channel_id *channel_id, const u8 *reestablish, - int peer_fd, int gossip_fd); + int peer_fd); #if DEVELOPER struct command; diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 0fcbb115b89b..ed717fc840e1 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -405,7 +405,7 @@ static void opening_funder_finished(struct subd *openingd, const u8 *resp, wallet_penalty_base_add(ld->wallet, channel->dbid, pbase); funding_success(channel); - peer_start_channeld(channel, fds[0], fds[1], NULL, false, NULL); + peer_start_channeld(channel, fds[0], NULL, false, NULL); cleanup: /* Frees fc too */ @@ -515,14 +515,13 @@ static void opening_fundee_finished(struct subd *openingd, wallet_penalty_base_add(ld->wallet, channel->dbid, pbase); /* On to normal operation! */ - peer_start_channeld(channel, fds[0], fds[1], fwd_msg, false, NULL); + peer_start_channeld(channel, fds[0], fwd_msg, false, NULL); tal_free(uc); return; failed: close(fds[0]); - close(fds[1]); tal_free(uc); } @@ -795,7 +794,7 @@ static void opening_got_offer(struct subd *openingd, } static void opening_got_reestablish(struct subd *openingd, const u8 *msg, - const int fds[2], + const int fds[1], struct uncommitted_channel *uc) { struct lightningd *ld = openingd->ld; @@ -809,15 +808,13 @@ static void opening_got_reestablish(struct subd *openingd, const u8 *msg, tal_hex(tmpctx, msg)); tal_free(openingd); close(fds[0]); - close(fds[1]); return; } /* This could free peer */ tal_free(uc); - handle_reestablish(ld, &peer_id, &channel_id, reestablish, - fds[0], fds[1]); + handle_reestablish(ld, &peer_id, &channel_id, reestablish, fds[0]); } static unsigned int openingd_msg(struct subd *openingd, @@ -834,8 +831,8 @@ static unsigned int openingd_msg(struct subd *openingd, tal_free(openingd); return 0; } - if (tal_count(fds) != 2) - return 2; + if (tal_count(fds) != 1) + return 1; opening_funder_finished(openingd, msg, fds, uc->fc); return 0; case WIRE_OPENINGD_FUNDER_START_REPLY: @@ -858,8 +855,8 @@ static unsigned int openingd_msg(struct subd *openingd, return 0; case WIRE_OPENINGD_FUNDEE: - if (tal_count(fds) != 2) - return 2; + if (tal_count(fds) != 1) + return 1; opening_fundee_finished(openingd, msg, fds, uc); return 0; @@ -868,8 +865,8 @@ static unsigned int openingd_msg(struct subd *openingd, return 0; case WIRE_OPENINGD_GOT_REESTABLISH: - if (tal_count(fds) != 2) - return 2; + if (tal_count(fds) != 1) + return 1; opening_got_reestablish(openingd, msg, fds, uc); return 0; @@ -891,7 +888,7 @@ static unsigned int openingd_msg(struct subd *openingd, return 0; } -void peer_start_openingd(struct peer *peer, int peer_fd, int gossip_fd) +void peer_start_openingd(struct peer *peer, int peer_fd) { int hsmfd; u32 max_to_self_delay; @@ -915,7 +912,6 @@ void peer_start_openingd(struct peer *peer, int peer_fd, int gossip_fd) opend_channel_errmsg, opend_channel_set_billboard, take(&peer_fd), - take(&gossip_fd), take(&hsmfd), NULL); if (!uc->open_daemon) { uncommitted_channel_disconnect(uc, LOG_BROKEN, diff --git a/lightningd/opening_control.h b/lightningd/opening_control.h index b17f480e5f01..76db459912c0 100644 --- a/lightningd/opening_control.h +++ b/lightningd/opening_control.h @@ -13,8 +13,7 @@ struct uncommitted_channel; void json_add_uncommitted_channel(struct json_stream *response, const struct uncommitted_channel *uc); -void peer_start_openingd(struct peer *peer, - int peer_fd, int gossip_fd); +void peer_start_openingd(struct peer *peer, int peer_fd); struct subd *peer_get_owning_subd(struct peer *peer); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index a5b28d5a42fc..9d0137657cd5 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -279,7 +279,7 @@ void drop_to_chain(struct lightningd *ld, struct channel *channel, } void channel_errmsg(struct channel *channel, - int peer_fd, int gossip_fd, + int peer_fd, const struct channel_id *channel_id UNUSED, const char *desc, bool warning, @@ -929,7 +929,7 @@ struct peer_connected_hook_payload { struct wireaddr_internal addr; bool incoming; struct peer *peer; - int peer_fd, gossip_fd; + int peer_fd; u8 *error; }; @@ -1011,7 +1011,6 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa channel->peer->connected_incoming = payload->incoming; peer_restart_dualopend(peer, payload->peer_fd, - payload->gossip_fd, channel); return; case CHANNELD_AWAITING_LOCKIN: @@ -1023,7 +1022,6 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa channel->peer->connected_incoming = payload->incoming; peer_start_channeld(channel, payload->peer_fd, - payload->gossip_fd, NULL, true, NULL); return; @@ -1045,16 +1043,11 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa channel->peer->connected_incoming = payload->incoming; peer_restart_dualopend(peer, payload->peer_fd, - payload->gossip_fd, channel); } else - peer_start_dualopend(peer, - payload->peer_fd, - payload->gossip_fd); + peer_start_dualopend(peer, payload->peer_fd); } else - peer_start_openingd(peer, - payload->peer_fd, - payload->gossip_fd); + peer_start_openingd(peer, payload->peer_fd); return; send_error: @@ -1065,7 +1058,6 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa take(towire_connectd_peer_final_msg(NULL, &peer->id, error))); subd_send_fd(ld->connectd, payload->peer_fd); - subd_send_fd(ld->connectd, payload->gossip_fd); } static bool @@ -1121,8 +1113,7 @@ REGISTER_PLUGIN_HOOK(peer_connected, /* Connectd tells us a peer has connected: it never hands us duplicates, since * it holds them until we say peer_died. */ -void peer_connected(struct lightningd *ld, const u8 *msg, - int peer_fd, int gossip_fd) +void peer_connected(struct lightningd *ld, const u8 *msg, int peer_fd) { struct node_id id; u8 *their_features; @@ -1140,7 +1131,6 @@ void peer_connected(struct lightningd *ld, const u8 *msg, tal_hex(msg, msg)); hook_payload->peer_fd = peer_fd; - hook_payload->gossip_fd = gossip_fd; /* If we're already dealing with this peer, hand off to correct * subdaemon. Otherwise, we'll hand to openingd to wait there. */ diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 601285935ed5..57dfd3824a68 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -63,14 +63,13 @@ struct peer *peer_from_json(struct lightningd *ld, const char *buffer, const jsmntok_t *peeridtok); -void peer_connected(struct lightningd *ld, const u8 *msg, - int peer_fd, int gossip_fd); +void peer_connected(struct lightningd *ld, const u8 *msg, int peer_fd); /* Could be configurable. */ #define OUR_CHANNEL_FLAGS CHANNEL_FLAGS_ANNOUNCE_CHANNEL void channel_errmsg(struct channel *channel, - int peer_fd, int gossip_fd, + int peer_fd, const struct channel_id *channel_id, const char *desc, bool warning, diff --git a/lightningd/subd.c b/lightningd/subd.c index e64ffb3da3a6..37ce776b2ba1 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -403,7 +403,7 @@ static bool log_status_fail(struct subd *sd, const u8 *msg) return true; } -static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[2]) +static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[1]) { void *channel = sd->channel; struct channel_id channel_id; @@ -415,14 +415,12 @@ static bool handle_peer_error(struct subd *sd, const u8 *msg, int fds[2]) &channel_id, &desc, &warning, &err_for_them)) { close(fds[0]); - close(fds[1]); return false; } /* Don't free sd; we may be about to free channel. */ sd->channel = NULL; - sd->errcb(channel, fds[0], fds[1], &channel_id, desc, warning, - err_for_them); + sd->errcb(channel, fds[0], &channel_id, desc, warning, err_for_them); return true; } @@ -523,11 +521,11 @@ static struct io_plan *sd_msg_read(struct io_conn *conn, struct subd *sd) if (sd->channel) { switch ((enum peer_status_wire)type) { case WIRE_STATUS_PEER_ERROR: - /* We expect 2 fds after this */ + /* We expect 1 fd after this */ if (!sd->fds_in) { /* Don't free msg_in: we go around again. */ tal_steal(sd, sd->msg_in); - plan = sd_collect_fds(conn, sd, 2); + plan = sd_collect_fds(conn, sd, 1); goto out; } if (!handle_peer_error(sd, sd->msg_in, sd->fds_in)) @@ -625,7 +623,7 @@ static void destroy_subd(struct subd *sd) if (!outer_transaction) db_begin_transaction(db); if (sd->errcb) - sd->errcb(channel, -1, -1, NULL, + sd->errcb(channel, -1, NULL, tal_fmt(sd, "Owning subdaemon %s died (%i)", sd->name, status), false, NULL); @@ -681,7 +679,7 @@ static struct subd *new_subd(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - int peer_fd, int gossip_fd, + int peer_fd, const struct channel_id *channel_id, const char *desc, bool warning, @@ -791,7 +789,7 @@ struct subd *new_channel_subd_(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - int peer_fd, int gossip_fd, + int peer_fd, const struct channel_id *channel_id, const char *desc, bool warning, diff --git a/lightningd/subd.h b/lightningd/subd.h index bfa7fef1c26f..5257a468e3f7 100644 --- a/lightningd/subd.h +++ b/lightningd/subd.h @@ -47,7 +47,7 @@ struct subd { * sufficient information to hand back to gossipd, including the * error message we sent them if any. */ void (*errcb)(void *channel, - int peer_fd, int gossip_fd, + int peer_fd, const struct channel_id *channel_id, const char *desc, bool warning, @@ -124,7 +124,7 @@ struct subd *new_channel_subd_(struct lightningd *ld, unsigned int (*msgcb)(struct subd *, const u8 *, const int *fds), void (*errcb)(void *channel, - int peer_fd, int gossip_fd, + int peer_fd, const struct channel_id *channel_id, const char *desc, bool warning, @@ -141,7 +141,7 @@ struct subd *new_channel_subd_(struct lightningd *ld, (msgname), (msgcb), \ typesafe_cb_postargs(void, void *, (errcb), \ (channel), \ - int, int, \ + int, \ const struct channel_id *, \ const char *, bool, const u8 *), \ typesafe_cb_postargs(void, void *, (billboardcb), \ diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 7d40e18d034c..be7cc6a62483 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -561,22 +561,21 @@ struct channel *peer_normal_channel(struct peer *peer UNNEEDED) { fprintf(stderr, "peer_normal_channel called!\n"); abort(); } /* Generated stub for peer_restart_dualopend */ void peer_restart_dualopend(struct peer *peer UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED, + int peer_fd UNNEEDED, struct channel *channel UNNEEDED) { fprintf(stderr, "peer_restart_dualopend called!\n"); abort(); } /* Generated stub for peer_start_channeld */ void peer_start_channeld(struct channel *channel UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED, + int peer_fd UNNEEDED, const u8 *fwd_msg UNNEEDED, bool reconnected UNNEEDED, const u8 *reestablish_only UNNEEDED) { fprintf(stderr, "peer_start_channeld called!\n"); abort(); } /* Generated stub for peer_start_dualopend */ -void peer_start_dualopend(struct peer *peer UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED) +void peer_start_dualopend(struct peer *peer UNNEEDED, int peer_fd UNNEEDED) { fprintf(stderr, "peer_start_dualopend called!\n"); abort(); } /* Generated stub for peer_start_openingd */ -void peer_start_openingd(struct peer *peer UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED) +void peer_start_openingd(struct peer *peer UNNEEDED, int peer_fd UNNEEDED) { fprintf(stderr, "peer_start_openingd called!\n"); abort(); } /* Generated stub for peer_unsaved_channel */ struct channel *peer_unsaved_channel(struct peer *peer UNNEEDED) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 1fad044a41b6..8134bd0e2de9 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -44,9 +44,9 @@ #include #include -/* stdin == lightningd, 3 == peer, 4 == gossipd, 5 = hsmd */ +/* stdin == lightningd, 3 == peer, 4 = hsmd */ #define REQ_FD STDIN_FILENO -#define HSM_FD 5 +#define HSM_FD 4 /* tx_add_input, tx_add_output, tx_rm_input, tx_rm_output */ #define NUM_TX_MSGS (TX_RM_OUTPUT + 1) @@ -1158,7 +1158,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) * form, but we use it in a very limited way. */ for (;;) { u8 *msg; - bool from_gossipd; char *err; bool warning; struct channel_id actual; @@ -1169,20 +1168,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) clean_tmpctx(); /* This helper routine polls both the peer and gossipd. */ - msg = peer_or_gossip_sync_read(ctx, state->pps, &from_gossipd); - - /* Use standard helper for gossip msgs (forwards, if it's an - * error, exits). */ - if (from_gossipd) { - handle_gossip_msg(state->pps, take(msg)); - continue; - } - - /* Some messages go straight to gossipd. */ - if (is_msg_for_gossipd(msg)) { - wire_sync_write(state->pps->gossip_fd, take(msg)); - continue; - } + msg = peer_read(ctx, state->pps); /* BOLT #1: * @@ -3442,19 +3428,6 @@ static u8 *handle_funding_depth(struct state *state, u8 *msg) return NULL; } -/*~ If we see the gossip_fd readable, we read a whole message. Sure, we might - * block, but we trust gossipd. */ -static void handle_gossip_in(struct state *state) -{ - u8 *msg = wire_sync_read(NULL, state->pps->gossip_fd); - - if (!msg) - status_failed(STATUS_FAIL_GOSSIP_IO, - "Reading gossip: %s", strerror(errno)); - - handle_gossip_msg(state->pps, take(msg)); -} - /* BOLT #2: * * A receiving node: @@ -3557,9 +3530,9 @@ static void do_reconnect_dance(struct state *state) do { clean_tmpctx(); msg = peer_read(tmpctx, state->pps); - } while (handle_peer_gossip_or_error(state->pps, - &state->channel_id, - soft_error, msg)); + } while (handle_peer_error(state->pps, + &state->channel_id, + soft_error, msg)); if (!fromwire_channel_reestablish (msg, &cid, @@ -3754,9 +3727,8 @@ static u8 *handle_peer_in(struct state *state) break; } - /* Handles standard cases, and legal unknown ones. */ - if (handle_peer_gossip_or_error(state->pps, - &state->channel_id, false, msg)) + /* Handles errors. */ + if (handle_peer_error(state->pps, &state->channel_id, false, msg)) return NULL; peer_write(state->pps, @@ -3779,7 +3751,7 @@ int main(int argc, char *argv[]) { common_setup(argv[0]); - struct pollfd pollfd[3]; + struct pollfd pollfd[2]; struct state *state = tal(NULL, struct state); struct secret *none; struct fee_states *fee_states; @@ -3905,9 +3877,9 @@ int main(int argc, char *argv[]) - /* 3 == peer, 4 == gossipd, 5 = hsmd */ + /* 3 == peer, 4 = hsmd */ state->pps = new_per_peer_state(state); - per_peer_state_set_fds(state->pps, 3, 4); + per_peer_state_set_fd(state->pps, 3); /*~ We need an initial per-commitment point whether we're funding or * they are, and lightningd has reserved a unique dbid for us already, @@ -3931,10 +3903,8 @@ int main(int argc, char *argv[]) /*~ We manually run a little poll() loop here. With only three fds */ pollfd[0].fd = REQ_FD; pollfd[0].events = POLLIN; - pollfd[1].fd = state->pps->gossip_fd; + pollfd[1].fd = state->pps->peer_fd; pollfd[1].events = POLLIN; - pollfd[2].fd = state->pps->peer_fd; - pollfd[2].events = POLLIN; /* Do reconnect, if need be */ if (state->channel) { @@ -3950,7 +3920,7 @@ int main(int argc, char *argv[]) /*~ If we get a signal which aborts the poll() call, valgrind * complains about revents being uninitialized. I'm not sure * that's correct, but it's easy to be sure. */ - pollfd[0].revents = pollfd[1].revents = pollfd[2].revents = 0; + pollfd[0].revents = pollfd[1].revents = 0; poll(pollfd, ARRAY_SIZE(pollfd), -1); /* Subtle: handle_master_in can do its own poll loop, so @@ -3959,11 +3929,8 @@ int main(int argc, char *argv[]) if (pollfd[0].revents & POLLIN) msg = handle_master_in(state); /* Second priority: messages from peer. */ - else if (pollfd[2].revents & POLLIN) - msg = handle_peer_in(state); - /* Last priority: chit-chat from gossipd. */ else if (pollfd[1].revents & POLLIN) - handle_gossip_in(state); + msg = handle_peer_in(state); /* If we've shutdown, we're done */ if (shutdown_complete(state)) diff --git a/openingd/openingd.c b/openingd/openingd.c index 43cf0618f57e..964bfc5f0d72 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -35,9 +35,9 @@ #include #include -/* stdin == lightningd, 3 == peer, 4 == gossipd, 5 = hsmd */ +/* stdin == lightningd, 3 == peer, 4 = hsmd */ #define REQ_FD STDIN_FILENO -#define HSM_FD 5 +#define HSM_FD 4 #if DEVELOPER /* If --dev-force-tmp-channel-id is set, it ends up here */ @@ -184,7 +184,6 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, * form, but we use it in a very limited way. */ for (;;) { u8 *msg; - bool from_gossipd; char *err; bool warning; struct channel_id actual; @@ -194,20 +193,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, clean_tmpctx(); /* This helper routine polls both the peer and gossipd. */ - msg = peer_or_gossip_sync_read(ctx, state->pps, &from_gossipd); - - /* Use standard helper for gossip msgs (forwards, if it's an - * error, exits). */ - if (from_gossipd) { - handle_gossip_msg(state->pps, take(msg)); - continue; - } - - /* Some messages go straight to gossipd. */ - if (is_msg_for_gossipd(msg)) { - wire_sync_write(state->pps->gossip_fd, take(msg)); - continue; - } + msg = wire_sync_read(ctx, state->pps->peer_fd); /* BOLT #1: * @@ -1260,8 +1246,7 @@ static u8 *handle_peer_in(struct state *state) return fundee_channel(state, msg); /* Handles standard cases, and legal unknown ones. */ - if (handle_peer_gossip_or_error(state->pps, - &state->channel_id, false, msg)) + if (handle_peer_error(state->pps, &state->channel_id, false, msg)) return NULL; extracted = extract_channel_id(msg, &channel_id); @@ -1285,19 +1270,6 @@ static u8 *handle_peer_in(struct state *state) peer_failed_connection_lost(); } -/*~ If we see the gossip_fd readable, we read a whole message. Sure, we might - * block, but we trust gossipd. */ -static void handle_gossip_in(struct state *state) -{ - u8 *msg = wire_sync_read(NULL, state->pps->gossip_fd); - - if (!msg) - status_failed(STATUS_FAIL_GOSSIP_IO, - "Reading gossip: %s", strerror(errno)); - - handle_gossip_msg(state->pps, take(msg)); -} - /* Memory leak detection is DEVELOPER-only because we go to great lengths to * record the backtrace when allocations occur: without that, the leak * detection tends to be useless for diagnosing where the leak came from, but @@ -1393,7 +1365,7 @@ int main(int argc, char *argv[]) setup_locale(); u8 *msg; - struct pollfd pollfd[3]; + struct pollfd pollfd[2]; struct state *state = tal(NULL, struct state); struct secret *none; struct channel_id *force_tmp_channel_id; @@ -1424,9 +1396,9 @@ int main(int argc, char *argv[]) dev_force_tmp_channel_id = force_tmp_channel_id; #endif - /* 3 == peer, 4 == gossipd, 5 = hsmd */ + /* 3 == peer, 4 = hsmd */ state->pps = new_per_peer_state(state); - per_peer_state_set_fds(state->pps, 3, 4); + per_peer_state_set_fd(state->pps, 3); /*~ Initially we're not associated with a channel, but * handle_peer_gossip_or_error compares this. */ @@ -1463,10 +1435,8 @@ int main(int argc, char *argv[]) /*~ We manually run a little poll() loop here. With only three fds */ pollfd[0].fd = REQ_FD; pollfd[0].events = POLLIN; - pollfd[1].fd = state->pps->gossip_fd; + pollfd[1].fd = state->pps->peer_fd; pollfd[1].events = POLLIN; - pollfd[2].fd = state->pps->peer_fd; - pollfd[2].events = POLLIN; /* We exit when we get a conclusion to write to lightningd: either * opening_funder_reply or opening_fundee. */ @@ -1475,7 +1445,7 @@ int main(int argc, char *argv[]) /*~ If we get a signal which aborts the poll() call, valgrind * complains about revents being uninitialized. I'm not sure * that's correct, but it's easy to be sure. */ - pollfd[0].revents = pollfd[1].revents = pollfd[2].revents = 0; + pollfd[0].revents = pollfd[1].revents = 0; poll(pollfd, ARRAY_SIZE(pollfd), -1); /* Subtle: handle_master_in can do its own poll loop, so @@ -1484,22 +1454,19 @@ int main(int argc, char *argv[]) if (pollfd[0].revents & POLLIN) msg = handle_master_in(state); /* Second priority: messages from peer. */ - else if (pollfd[2].revents & POLLIN) - msg = handle_peer_in(state); - /* Last priority: chit-chat from gossipd. */ else if (pollfd[1].revents & POLLIN) - handle_gossip_in(state); + msg = handle_peer_in(state); /* Since we're the top-level event loop, we clean up */ clean_tmpctx(); } - /*~ Write message and hand back the peer fd and gossipd fd. This also - * means that if the peer or gossipd wrote us any messages we didn't - * read yet, it will simply be read by the next daemon. */ + /*~ Write message and hand back the peer fd. This also means that if + * the peer wrote us any messages we didn't read yet, it will simply + * be read by the next daemon. */ wire_sync_write(REQ_FD, msg); per_peer_state_fdpass_send(REQ_FD, state->pps); - status_debug("Sent %s with fds", + status_debug("Sent %s with fd", openingd_wire_name(fromwire_peektype(msg))); /* This frees the entire tal tree. */ diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index e4c7b74b1e69..9a07d747f782 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -588,22 +588,21 @@ void peer_memleak_done(struct command *cmd UNNEEDED, struct subd *leaker UNNEEDE { fprintf(stderr, "peer_memleak_done called!\n"); abort(); } /* Generated stub for peer_restart_dualopend */ void peer_restart_dualopend(struct peer *peer UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED, + int peer_fd UNNEEDED, struct channel *channel UNNEEDED) { fprintf(stderr, "peer_restart_dualopend called!\n"); abort(); } /* Generated stub for peer_start_channeld */ void peer_start_channeld(struct channel *channel UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED, + int peer_fd UNNEEDED, const u8 *fwd_msg UNNEEDED, bool reconnected UNNEEDED, const u8 *reestablish_only UNNEEDED) { fprintf(stderr, "peer_start_channeld called!\n"); abort(); } /* Generated stub for peer_start_dualopend */ -void peer_start_dualopend(struct peer *peer UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED) +void peer_start_dualopend(struct peer *peer UNNEEDED, int peer_fd UNNEEDED) { fprintf(stderr, "peer_start_dualopend called!\n"); abort(); } /* Generated stub for peer_start_openingd */ -void peer_start_openingd(struct peer *peer UNNEEDED, - int peer_fd UNNEEDED, int gossip_fd UNNEEDED) +void peer_start_openingd(struct peer *peer UNNEEDED, int peer_fd UNNEEDED) { fprintf(stderr, "peer_start_openingd called!\n"); abort(); } /* Generated stub for plugin_hook_call_ */ bool plugin_hook_call_(struct lightningd *ld UNNEEDED, const struct plugin_hook *hook UNNEEDED, From eb178b8ca08c1abf6d74364daf94a5e3f5a8bfe8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:07:00 +1030 Subject: [PATCH 48/51] gossipd: don't hand out fds. Gossipd now simply gets told by channeld when peers arrive or leave. (it only needs to know for the seeker). Signed-off-by: Rusty Russell --- connectd/connectd.c | 70 ++----------- connectd/connectd.h | 3 - connectd/connectd_gossipd_wire.csv | 6 +- gossipd/gossipd.c | 159 ++++++++--------------------- gossipd/gossipd.h | 3 - 5 files changed, 54 insertions(+), 187 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 8018c0c9b783..6203a17e9638 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -210,57 +210,6 @@ static void peer_connected_in(struct daemon *daemon, tal_free(connect); } -/*~ Every per-peer daemon needs a connection to the gossip daemon; this allows - * it to forward gossip to/from the peer. The gossip daemon needs to know a - * 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 - * out by gossipd too, and also a "gossip_state" indicating where we're up to. - * - * 'features' is a field in the `init` message, indicating properties of the - * node. - */ -static int get_gossipfd(struct daemon *daemon, - const struct node_id *id, - const u8 *their_features) -{ - bool gossip_queries_feature, success; - u8 *msg; - - /*~ The way features generally work is that both sides need to offer it; - * we always offer `gossip_queries`, but this check is explicit. */ - gossip_queries_feature - = feature_negotiated(daemon->our_features, their_features, - OPT_GOSSIP_QUERIES); - - /*~ We do this communication sync, since gossipd is our friend and - * it's easier. If gossipd fails, we fail. */ - msg = towire_gossipd_new_peer(NULL, id, gossip_queries_feature); - if (!wire_sync_write(GOSSIPCTL_FD, take(msg))) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed writing to gossipctl: %s", - strerror(errno)); - - msg = wire_sync_read(tmpctx, GOSSIPCTL_FD); - if (!fromwire_gossipd_new_peer_reply(msg, &success)) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed parsing msg gossipctl: %s", - tal_hex(tmpctx, msg)); - - /* Gossipd might run out of file descriptors, so it tells us, and we - * give up on connecting this peer. */ - if (!success) { - status_broken("Gossipd did not give us an fd: losing peer %s", - type_to_string(tmpctx, struct node_id, id)); - return -1; - } - - /* Otherwise, the next thing in the socket will be the file descriptor - * for the per-peer daemon. */ - return fdpass_recv(GOSSIPCTL_FD); - -} - /*~ This is an ad-hoc marshalling structure where we store arguments so we * can call peer_connected again. */ struct peer_reconnected { @@ -336,8 +285,6 @@ static struct io_plan *peer_reconnected(struct io_conn *conn, /*~ When we free a peer, we remove it from the daemon's hashtable */ static void destroy_peer(struct peer *peer, struct daemon *daemon) { - if (peer->gossip_fd >= 0) - close(peer->gossip_fd); peer_htable_del(&daemon->peers, peer); } @@ -389,6 +336,7 @@ struct io_plan *peer_connected(struct io_conn *conn, int unsup; size_t depender, missing; int subd_fd; + bool option_gossip_queries; peer = peer_htable_get(&daemon->peers, id); if (peer) @@ -446,12 +394,12 @@ struct io_plan *peer_connected(struct io_conn *conn, if (!peer) return io_close(conn); - /* If gossipd can't give us a file descriptor, we give up connecting. */ - peer->gossip_fd = get_gossipfd(daemon, id, their_features); - if (peer->gossip_fd < 0) { - close(subd_fd); - return tal_free(peer); - } + /* Tell gossipd it can ask query this new peer for gossip */ + option_gossip_queries = feature_negotiated(daemon->our_features, + their_features, + OPT_GOSSIP_QUERIES); + msg = towire_gossipd_new_peer(NULL, id, option_gossip_queries); + daemon_conn_send(daemon->gossipd, take(msg)); /* Get ready for streaming gossip from the store */ setup_peer_gossip_store(peer, daemon->our_features, their_features); @@ -1833,6 +1781,10 @@ static void cleanup_dead_peer(struct daemon *daemon, const struct node_id *id) type_to_string(tmpctx, struct node_id, id)); status_peer_debug(id, "disconnect"); + /* Tell gossipd to stop asking this peer gossip queries */ + daemon_conn_send(daemon->gossipd, + take(towire_gossipd_peer_gone(NULL, id))); + /* Wake up in case there's a reconnecting peer waiting in io_wait. */ io_wake(peer); diff --git a/connectd/connectd.h b/connectd/connectd.h index 23ed9c0cecfe..93814efc5e3c 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -77,9 +77,6 @@ struct peer { /* Random ping timer, to detect dead connections. */ struct oneshot *ping_timer; - - /* FIXME: remove! */ - int gossip_fd; }; /*~ The HTABLE_DEFINE_TYPE() macro needs a keyof() function to extract the key: diff --git a/connectd/connectd_gossipd_wire.csv b/connectd/connectd_gossipd_wire.csv index bdb9a75f5292..195a73421bb8 100644 --- a/connectd/connectd_gossipd_wire.csv +++ b/connectd/connectd_gossipd_wire.csv @@ -8,9 +8,9 @@ msgdata,gossipd_new_peer,id,node_id, # Did we negotiate OPT_GOSSIP_QUERIES? msgdata,gossipd_new_peer,gossip_queries_feature,bool, -# if success: + gossip fd -msgtype,gossipd_new_peer_reply,4100 -msgdata,gossipd_new_peer_reply,success,bool, +# peer is done +msgtype,gossipd_peer_gone,4101 +msgdata,gossipd_peer_gone,id,node_id, # connectd tells gossipd a gossip msg it received for peer. msgtype,gossipd_recv_gossip,4002 diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 8828c3673480..9c69350f3a24 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -89,12 +89,6 @@ static void destroy_peer(struct peer *peer) node = get_node(peer->daemon->rstate, &peer->id); if (node) peer_disable_channels(peer->daemon, node); - - /* This is tricky: our lifetime is tied to the daemon_conn; it's our - * parent, so we are freed if it is, but we need to free it if we're - * freed manually. tal_free() treats this as a noop if it's already - * being freed */ - tal_free(peer->dc); } /* Search for a peer. */ @@ -346,103 +340,26 @@ static void handle_local_private_channel(struct daemon *daemon, const u8 *msg) } } -/*~ This is where the per-peer daemons send us messages. It's either forwarded - * gossip, or a request for information. We deliberately use non-overlapping - * message types so we can distinguish them. */ -static struct io_plan *peer_msg_in(struct io_conn *conn, - const u8 *msg, - struct peer *peer) -{ - /* These are messages relayed from peer */ - switch ((enum peer_wire)fromwire_peektype(msg)) { - /* These are not sent by peer (connectd sends us gossip msgs) */ - case WIRE_CHANNEL_ANNOUNCEMENT: - case WIRE_CHANNEL_UPDATE: - case WIRE_NODE_ANNOUNCEMENT: - case WIRE_QUERY_CHANNEL_RANGE: - case WIRE_REPLY_CHANNEL_RANGE: - case WIRE_QUERY_SHORT_CHANNEL_IDS: - case WIRE_REPLY_SHORT_CHANNEL_IDS_END: - case WIRE_WARNING: - case WIRE_INIT: - case WIRE_ERROR: - case WIRE_PING: - case WIRE_PONG: - case WIRE_OPEN_CHANNEL: - case WIRE_ACCEPT_CHANNEL: - case WIRE_FUNDING_CREATED: - case WIRE_FUNDING_SIGNED: - case WIRE_FUNDING_LOCKED: - case WIRE_SHUTDOWN: - case WIRE_CLOSING_SIGNED: - case WIRE_UPDATE_ADD_HTLC: - case WIRE_UPDATE_FULFILL_HTLC: - case WIRE_UPDATE_FAIL_HTLC: - case WIRE_UPDATE_FAIL_MALFORMED_HTLC: - case WIRE_COMMITMENT_SIGNED: - case WIRE_REVOKE_AND_ACK: - case WIRE_UPDATE_FEE: - case WIRE_UPDATE_BLOCKHEIGHT: - case WIRE_CHANNEL_REESTABLISH: - case WIRE_ANNOUNCEMENT_SIGNATURES: - case WIRE_GOSSIP_TIMESTAMP_FILTER: - case WIRE_TX_ADD_INPUT: - case WIRE_TX_REMOVE_INPUT: - case WIRE_TX_ADD_OUTPUT: - case WIRE_TX_REMOVE_OUTPUT: - case WIRE_TX_COMPLETE: - case WIRE_TX_SIGNATURES: - case WIRE_OPEN_CHANNEL2: - case WIRE_ACCEPT_CHANNEL2: - case WIRE_INIT_RBF: - case WIRE_ACK_RBF: - case WIRE_OBS2_ONION_MESSAGE: - case WIRE_ONION_MESSAGE: -#if EXPERIMENTAL_FEATURES - case WIRE_STFU: -#endif - status_broken("peer %s: relayed unexpected msg of type %s", - type_to_string(tmpctx, struct node_id, &peer->id), - peer_wire_name(fromwire_peektype(msg))); - return io_close(conn); - } - - /* Anything else should not have been sent to us: close on it */ - status_peer_broken(&peer->id, "unexpected cmd of type %i", - fromwire_peektype(msg)); - return io_close(conn); -} - -/*~ This is where connectd tells us about a new peer, and we hand back an fd for - * it to send us messages via peer_msg_in above */ -static struct io_plan *connectd_new_peer(struct io_conn *conn, - struct daemon *daemon, - const u8 *msg) +/*~ This is where connectd tells us about a new peer we might want to + * gossip with. */ +static void connectd_new_peer(struct daemon *daemon, const u8 *msg) { - struct peer *peer = tal(conn, struct peer); + struct peer *peer = tal(daemon, struct peer); struct node *node; - int fds[2]; if (!fromwire_gossipd_new_peer(msg, &peer->id, &peer->gossip_queries_feature)) { - status_broken("Bad new_peer msg from connectd: %s", + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Bad new_peer msg from connectd: %s", tal_hex(tmpctx, msg)); - return io_close(conn); } - /* This can happen: we handle it gracefully, returning a `failed` msg. */ - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) { - status_broken("Failed to create socketpair: %s", - strerror(errno)); - daemon_conn_send(daemon->connectd, - take(towire_gossipd_new_peer_reply(NULL, - false))); - goto done; + if (find_peer(daemon, &peer->id)) { + status_broken("Peer %s already here?", + type_to_string(tmpctx, struct node_id, &peer->id)); + tal_free(find_peer(daemon, &peer->id)); } - /* We might not have noticed old peer is dead; kill it now. */ - tal_free(find_peer(daemon, &peer->id)); - /* Populate the rest of the peer info. */ peer->daemon = daemon; peer->gossip_counter = 0; @@ -458,27 +375,30 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn, list_add_tail(&peer->daemon->peers, &peer->list); tal_add_destructor(peer, destroy_peer); - /* This is the new connection. */ - peer->dc = daemon_conn_new(daemon, fds[0], - peer_msg_in, - NULL, peer); - /* Free peer if conn closed (destroy_peer closes conn if peer freed) */ - tal_steal(peer->dc, peer); - node = get_node(daemon->rstate, &peer->id); if (node) peer_enable_channels(daemon, node); /* This sends the initial timestamp filter. */ seeker_setup_peer_gossip(daemon->seeker, peer); +} + +static void connectd_peer_gone(struct daemon *daemon, const u8 *msg) +{ + struct node_id id; + struct peer *peer; - /* Reply with success, and the new fd and gossip_state. */ - daemon_conn_send(daemon->connectd, - take(towire_gossipd_new_peer_reply(NULL, true))); - daemon_conn_send_fd(daemon->connectd, fds[1]); + if (!fromwire_gossipd_peer_gone(msg, &id)) { + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Bad peer_gone msg from connectd: %s", + tal_hex(tmpctx, msg)); + } -done: - return daemon_conn_read_next(conn, daemon->connectd); + peer = find_peer(daemon, &id); + if (!peer) + status_broken("Peer %s already gone?", + type_to_string(tmpctx, struct node_id, &id)); + tal_free(peer); } /*~ lightningd asks us if we know any addresses for a given id. */ @@ -519,12 +439,11 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg) tal_hex(tmpctx, outermsg)); } - /* FIXME: happens when peer closes! */ peer = find_peer(daemon, &id); if (!peer) { - status_debug("connectd sent gossip msg %s for unknown peer %s", - peer_wire_name(fromwire_peektype(msg)), - type_to_string(tmpctx, struct node_id, &id)); + status_broken("connectd sent gossip msg %s for unknown peer %s", + peer_wire_name(fromwire_peektype(msg)), + type_to_string(tmpctx, struct node_id, &id)); return; } @@ -612,20 +531,17 @@ static struct io_plan *connectd_req(struct io_conn *conn, enum connectd_gossipd_wire t = fromwire_peektype(msg); switch (t) { - case WIRE_GOSSIPD_NEW_PEER: - return connectd_new_peer(conn, daemon, msg); - /* This is not for this fd! */ case WIRE_GOSSIPD_RECV_GOSSIP: + case WIRE_GOSSIPD_NEW_PEER: + case WIRE_GOSSIPD_PEER_GONE: /* We send these, don't receive them. */ - case WIRE_GOSSIPD_NEW_PEER_REPLY: case WIRE_GOSSIPD_SEND_GOSSIP: break; } - status_broken("Bad msg from connectd: %s", - tal_hex(tmpctx, msg)); - return io_close(conn); + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Bad msg from connectd: %s", tal_hex(tmpctx, msg)); } /*~ connectd's input handler is very simple. */ @@ -640,10 +556,15 @@ static struct io_plan *connectd_gossip_req(struct io_conn *conn, handle_recv_gossip(daemon, msg); goto handled; - /* This is not for this fd! */ case WIRE_GOSSIPD_NEW_PEER: + connectd_new_peer(daemon, msg); + goto handled; + + case WIRE_GOSSIPD_PEER_GONE: + connectd_peer_gone(daemon, msg); + goto handled; + /* We send these, don't receive them. */ - case WIRE_GOSSIPD_NEW_PEER_REPLY: case WIRE_GOSSIPD_SEND_GOSSIP: break; } diff --git a/gossipd/gossipd.h b/gossipd/gossipd.h index 75b39b8c67a1..9a73c8974305 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -109,9 +109,6 @@ struct peer { void (*query_channel_range_cb)(struct peer *peer, u32 first_blocknum, u32 number_of_blocks, const struct range_query_reply *replies); - - /* The daemon_conn used to queue messages to/from the peer. */ - struct daemon_conn *dc; }; /* Search for a peer. */ From 39c241b192d1cd62832e462fcb9c28ca7dc206b9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:07:00 +1030 Subject: [PATCH 49/51] connectd: remove second gossip fd. Now we only send and receive gossip messages on this fd. Signed-off-by: Rusty Russell --- connectd/connectd.c | 5 ++--- gossipd/gossipd.c | 30 +++------------------------ gossipd/gossipd.h | 1 - lightningd/connect_control.c | 12 +++-------- lightningd/connect_control.h | 2 +- lightningd/gossip_control.c | 7 ++----- lightningd/gossip_control.h | 2 +- lightningd/lightningd.c | 6 +++--- lightningd/test/run-find_my_abspath.c | 4 ++-- 9 files changed, 17 insertions(+), 52 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 6203a17e9638..dc4ea050e6fd 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -53,7 +53,6 @@ * thus may know how to reach certain peers. */ #define HSM_FD 3 #define GOSSIPCTL_FD 4 -#define GOSSIPCTL2_FD 5 /*~ In C convention, constants are UPPERCASE macros. Not everything needs to * be a constant, but it soothes the programmer's conscience to encapsulate @@ -1519,7 +1518,7 @@ static void connect_init(struct daemon *daemon, const u8 *msg) announcable))); #if DEVELOPER if (dev_disconnect) - dev_disconnect_init(6); + dev_disconnect_init(5); #endif } @@ -1993,7 +1992,7 @@ int main(int argc, char *argv[]) status_setup_async(daemon->master); /* This streams gossip to and from gossipd */ - daemon->gossipd = daemon_conn_new(daemon, GOSSIPCTL2_FD, + daemon->gossipd = daemon_conn_new(daemon, GOSSIPCTL_FD, recv_gossip, NULL, daemon); diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 9c69350f3a24..720df9b471bf 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -114,7 +114,7 @@ void peer_supplied_good_gossip(struct peer *peer, size_t amount) void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) { u8 *outermsg = towire_gossipd_send_gossip(NULL, &peer->id, msg); - daemon_conn_send(peer->daemon->connectd2, take(outermsg)); + daemon_conn_send(peer->daemon->connectd, take(outermsg)); if (taken(msg)) tal_free(msg); @@ -530,27 +530,6 @@ static struct io_plan *connectd_req(struct io_conn *conn, { enum connectd_gossipd_wire t = fromwire_peektype(msg); - switch (t) { - /* This is not for this fd! */ - case WIRE_GOSSIPD_RECV_GOSSIP: - case WIRE_GOSSIPD_NEW_PEER: - case WIRE_GOSSIPD_PEER_GONE: - /* We send these, don't receive them. */ - case WIRE_GOSSIPD_SEND_GOSSIP: - break; - } - - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Bad msg from connectd: %s", tal_hex(tmpctx, msg)); -} - -/*~ connectd's input handler is very simple. */ -static struct io_plan *connectd_gossip_req(struct io_conn *conn, - const u8 *msg, - struct daemon *daemon) -{ - enum connectd_gossipd_wire t = fromwire_peektype(msg); - switch (t) { case WIRE_GOSSIPD_RECV_GOSSIP: handle_recv_gossip(daemon, msg); @@ -573,7 +552,7 @@ static struct io_plan *connectd_gossip_req(struct io_conn *conn, "Bad msg from connectd2: %s", tal_hex(tmpctx, msg)); handled: - return daemon_conn_read_next(conn, daemon->connectd2); + return daemon_conn_read_next(conn, daemon->connectd); } /* BOLT #7: @@ -731,14 +710,11 @@ static void gossip_init(struct daemon *daemon, const u8 *msg) /* Fire up the seeker! */ daemon->seeker = new_seeker(daemon); - /* connectd is already started, and uses this fd to ask us things. */ + /* connectd is already started, and uses this fd to feed/recv gossip. */ daemon->connectd = daemon_conn_new(daemon, CONNECTD_FD, connectd_req, maybe_send_query_responses, daemon); - daemon->connectd2 = daemon_conn_new(daemon, CONNECTD2_FD, - connectd_gossip_req, NULL, daemon); - /* OK, we are ready. */ daemon_conn_send(daemon->master, take(towire_gossipd_init_reply(NULL))); diff --git a/gossipd/gossipd.h b/gossipd/gossipd.h index 9a73c8974305..a84d5765eb71 100644 --- a/gossipd/gossipd.h +++ b/gossipd/gossipd.h @@ -33,7 +33,6 @@ struct daemon { /* Connection to connect daemon. */ struct daemon_conn *connectd; - struct daemon_conn *connectd2; /* Routing information */ struct routing_state *rstate; diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index e609e43b6ca6..2ecfd5c82993 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -477,9 +477,9 @@ static void connect_init_done(struct subd *connectd, io_break(connectd); } -int connectd_init(struct lightningd *ld, int *gossipd_fd2) +int connectd_init(struct lightningd *ld) { - int fds[2], fds2[2]; + int fds[2]; u8 *msg; int hsmfd; struct wireaddr_internal *wireaddrs = ld->proposed_wireaddr; @@ -492,16 +492,11 @@ int connectd_init(struct lightningd *ld, int *gossipd_fd2) if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) != 0) fatal("Could not socketpair for connectd<->gossipd"); - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds2) != 0) - fatal("Could not socketpair for connectd<->gossipd 2"); - hsmfd = hsm_get_global_fd(ld, HSM_CAP_ECDH); ld->connectd = new_global_subd(ld, "lightning_connectd", connectd_wire_name, connectd_msg, - take(&hsmfd), - take(&fds[1]), - take(&fds2[1]), + take(&hsmfd), take(&fds[1]), #if DEVELOPER /* Not take(): we share it */ ld->dev_disconnect_fd >= 0 ? @@ -542,7 +537,6 @@ int connectd_init(struct lightningd *ld, int *gossipd_fd2) /* Wait for init_reply */ io_loop(NULL, NULL); - *gossipd_fd2 = fds2[0]; return fds[0]; } diff --git a/lightningd/connect_control.h b/lightningd/connect_control.h index 681c5c7a1ed5..67beb003782b 100644 --- a/lightningd/connect_control.h +++ b/lightningd/connect_control.h @@ -7,7 +7,7 @@ struct pubkey; struct wireaddr_internal; /* Returns fd for gossipd to talk to connectd */ -int connectd_init(struct lightningd *ld, int *gossipd_fd2); +int connectd_init(struct lightningd *ld); void connectd_activate(struct lightningd *ld); void try_reconnect(struct channel *channel, u32 seconds_delay, diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index 66108ddb2e2d..2e445880fc30 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -214,7 +214,7 @@ static void gossipd_init_done(struct subd *gossipd, /* Create the `gossipd` subdaemon and send the initialization * message */ -void gossip_init(struct lightningd *ld, int connectd_fd, int connectd_fd2) +void gossip_init(struct lightningd *ld, int connectd_fd) { u8 *msg; int hsmfd; @@ -223,10 +223,7 @@ void gossip_init(struct lightningd *ld, int connectd_fd, int connectd_fd2) ld->gossip = new_global_subd(ld, "lightning_gossipd", gossipd_wire_name, gossip_msg, - take(&hsmfd), - take(&connectd_fd), - take(&connectd_fd2), - NULL); + take(&hsmfd), take(&connectd_fd), NULL); if (!ld->gossip) err(1, "Could not subdaemon gossip"); diff --git a/lightningd/gossip_control.h b/lightningd/gossip_control.h index 869f53930aaf..c1d587902158 100644 --- a/lightningd/gossip_control.h +++ b/lightningd/gossip_control.h @@ -8,7 +8,7 @@ struct channel; struct lightningd; -void gossip_init(struct lightningd *ld, int connectd_fd, int connectd_fd2); +void gossip_init(struct lightningd *ld, int connectd_fd); void gossipd_notify_spend(struct lightningd *ld, const struct short_channel_id *scid); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 329316cd1854..3700816625ea 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -846,7 +846,7 @@ int main(int argc, char *argv[]) { struct lightningd *ld; u32 min_blockheight, max_blockheight; - int connectd_gossipd_fd, connectd_gossipd_fd2; + int connectd_gossipd_fd; int stop_fd; struct timers *timers; const char *stop_response; @@ -1022,7 +1022,7 @@ int main(int argc, char *argv[]) * which knows (via node_announcement messages) the public * addresses of nodes, so connectd_init hands it one end of a * socket pair, and gives us the other */ - connectd_gossipd_fd = connectd_init(ld, &connectd_gossipd_fd2); + connectd_gossipd_fd = connectd_init(ld); /*~ We do every database operation within a transaction; usually this * is covered by the infrastructure (eg. opening a transaction before @@ -1074,7 +1074,7 @@ int main(int argc, char *argv[]) * channel_announcement, channel_update, node_announcement and gossip * queries. It also hands us the latest channel_updates for our * channels. */ - gossip_init(ld, connectd_gossipd_fd, connectd_gossipd_fd2); + gossip_init(ld, connectd_gossipd_fd); /*~ Create RPC socket: now lightning-cli can send us JSON RPC commands * over a UNIX domain socket specified by `ld->rpc_filename`. */ diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index 102ca04fde44..b0a2469d946a 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -26,7 +26,7 @@ void coin_mvts_init_count(struct lightningd *ld UNNEEDED) void connectd_activate(struct lightningd *ld UNNEEDED) { fprintf(stderr, "connectd_activate called!\n"); abort(); } /* Generated stub for connectd_init */ -int connectd_init(struct lightningd *ld UNNEEDED, int *gossipd_fd2 UNNEEDED) +int connectd_init(struct lightningd *ld UNNEEDED) { fprintf(stderr, "connectd_init called!\n"); abort(); } /* Generated stub for daemon_poll */ int daemon_poll(struct pollfd *fds UNNEEDED, nfds_t nfds UNNEEDED, int timeout UNNEEDED) @@ -95,7 +95,7 @@ bool fromwire_status_peer_error(const tal_t *ctx UNNEEDED, const void *p UNNEEDE bool fromwire_status_version(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, wirestring **version UNNEEDED) { fprintf(stderr, "fromwire_status_version called!\n"); abort(); } /* Generated stub for gossip_init */ -void gossip_init(struct lightningd *ld UNNEEDED, int connectd_fd UNNEEDED, int connectd_fd2 UNNEEDED) +void gossip_init(struct lightningd *ld UNNEEDED, int connectd_fd UNNEEDED) { fprintf(stderr, "gossip_init called!\n"); abort(); } /* Generated stub for gossip_notify_new_block */ void gossip_notify_new_block(struct lightningd *ld UNNEEDED, u32 blockheight UNNEEDED) From 895038419a40ae8363b16baf82f9ee0c6a90e7e3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 20 Dec 2021 16:07:00 +1030 Subject: [PATCH 50/51] connectd: don't received useless peer fd if we're told to send final msg. We don't need the connection to ourselves! Signed-off-by: Rusty Russell --- connectd/connectd.c | 11 ----------- connectd/connectd_wire.csv | 2 +- lightningd/opening_common.c | 2 +- lightningd/peer_control.c | 2 +- 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index dc4ea050e6fd..fc52d4733b72 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1812,21 +1812,10 @@ static void peer_final_msg(struct io_conn *conn, struct peer *peer; struct node_id id; u8 *finalmsg; - int peer_fd; if (!fromwire_connectd_peer_final_msg(tmpctx, msg, &id, &finalmsg)) master_badmsg(WIRE_CONNECTD_PEER_FINAL_MSG, msg); - /* Get the peer_fd for this peer: we don't need it though! */ - io_fd_block(io_conn_fd(conn), true); - peer_fd = fdpass_recv(io_conn_fd(conn)); - if (peer_fd == -1) - status_failed(STATUS_FAIL_MASTER_IO, - "Getting peer fd after peer_final_msg: %s", - strerror(errno)); - close(peer_fd); - io_fd_block(io_conn_fd(conn), false); - /* This can happen if peer hung up on us. */ peer = peer_htable_get(&daemon->peers, &id); if (peer) { diff --git a/connectd/connectd_wire.csv b/connectd/connectd_wire.csv index c735f3c93173..7632a2840e43 100644 --- a/connectd/connectd_wire.csv +++ b/connectd/connectd_wire.csv @@ -72,7 +72,7 @@ msgdata,connectd_peer_connected,features,u8,flen msgtype,connectd_peer_disconnected,2015 msgdata,connectd_peer_disconnected,id,node_id, -# master -> connectd: give message to peer and disconnect. Plus fd for peer +# master -> connectd: give message to peer and disconnect. msgtype,connectd_peer_final_msg,2003 msgdata,connectd_peer_final_msg,id,node_id, msgdata,connectd_peer_final_msg,len,u16, diff --git a/lightningd/opening_common.c b/lightningd/opening_common.c index e817d6967d60..90a134f685ec 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -194,7 +194,7 @@ void handle_reestablish(struct lightningd *ld, subd_send_msg(ld->connectd, take(towire_connectd_peer_final_msg(NULL, peer_id, err))); - subd_send_fd(ld->connectd, peer_fd); + close(peer_fd); } } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 9d0137657cd5..40a2b4c38b6a 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1057,7 +1057,7 @@ static void peer_connected_hook_final(struct peer_connected_hook_payload *payloa subd_send_msg(ld->connectd, take(towire_connectd_peer_final_msg(NULL, &peer->id, error))); - subd_send_fd(ld->connectd, payload->peer_fd); + close(payload->peer_fd); } static bool From aa88b6af679d4cab1a9e8279229f53dbe174f2e4 Mon Sep 17 00:00:00 2001 From: Dustin Dettmer Date: Thu, 30 Dec 2021 17:46:03 -0800 Subject: [PATCH 51/51] Compiler error I'm guessing doing a 16 bit swap on WIRE_GOSSIP_STORE_ENDED is the solution Error on Mac OSX 11.6: common/gossip_store.c:132:16: error: result of comparison of constant 152043520 with expression of type 'be16' (aka 'unsigned short') is always false [-Werror,-Wtautological-constant-out-of-range-compare] if (buf.type == CPU_TO_BE32(WIRE_GOSSIP_STORE_ENDED)) $ gcc -v Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1 Apple clang version 13.0.0 (clang-1300.0.29.30) Target: x86_64-apple-darwin20.6.0 --- common/gossip_store.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/gossip_store.c b/common/gossip_store.c index 57a12d3c683e..9056dee01158 100644 --- a/common/gossip_store.c +++ b/common/gossip_store.c @@ -129,7 +129,7 @@ size_t find_gossip_store_end(int gossip_store_fd, size_t off) u32 msglen = be32_to_cpu(buf.hdr.len) & GOSSIP_STORE_LEN_MASK; /* Don't swallow end marker! */ - if (buf.type == CPU_TO_BE32(WIRE_GOSSIP_STORE_ENDED)) + if (buf.type == CPU_TO_BE16(WIRE_GOSSIP_STORE_ENDED)) break; off += sizeof(buf.hdr) + msglen;