From a9e66922228410a3f5f18dda6bed2da29eedb78b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:27:52 +1030 Subject: [PATCH 01/34] 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 a73017835c2f..06da2389714d 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 627404a5d695b0f08489e7be950475ed6963e276 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:28:52 +1030 Subject: [PATCH 02/34] 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 ac5580856c7c..fcde98ba1871 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1452,6 +1452,7 @@ static struct io_plan *recv_req(struct io_conn *conn, case WIRE_GOSSIPD_ADDGOSSIP_REPLY: case WIRE_GOSSIPD_NEW_BLOCKHEIGHT_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 f0a6a9c898d1..6df53358a6c1 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -116,3 +116,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 79eee3248933..10f388672ea6 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -253,6 +253,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; @@ -461,6 +462,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 4f3fb1d28d50..729ac8599dd1 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -237,6 +237,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 9b82d9b793db..11b2463e537e 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -5,10 +5,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -107,6 +109,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); @@ -144,6 +172,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 5a9e8f30b3fd5de421251aaf041cb08fcff73d67 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:29:52 +1030 Subject: [PATCH 03/34] 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 af6f9858d223..c0210f7f28ea 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -1799,10 +1799,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: @@ -1958,7 +1961,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 3cde1fad72e7..15e7f0e3c7c3 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -1081,7 +1081,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 34e10387ebfcd76e87bdeb3cd86c5e339bb056ad Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:30:52 +1030 Subject: [PATCH 04/34] 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 fcde98ba1871..06ff2deb489f 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1413,6 +1413,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 6df53358a6c1..96d42fd1bba5 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -122,3 +122,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 66bad4d6941b..13b610fe104c 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 729ac8599dd1..091346f2cc2e 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -474,4 +474,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 11b2463e537e..090f4ad41858 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -135,6 +135,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); @@ -156,6 +167,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 24fc4d4e296835f42d062a29c68f14987e4a2726 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:31:52 +1030 Subject: [PATCH 05/34] 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 | 11 +- 11 files changed, 55 insertions(+), 229 deletions(-) diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 06ff2deb489f..6e12096124ae 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -1177,56 +1177,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) @@ -1382,10 +1332,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; @@ -1448,7 +1394,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 96d42fd1bba5..7dba19620276 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 13b610fe104c..5ccc425f6f28 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 090f4ad41858..5859fd675f85 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -153,7 +153,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: @@ -172,7 +171,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_NEW_BLOCKHEIGHT_REPLY: case WIRE_GOSSIPD_GET_ADDRS_REPLY: diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 06da2389714d..cedc20e77d8d 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 346cc8ecca3f..6889945c50bb 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -533,7 +533,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; @@ -566,10 +566,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); @@ -780,14 +777,13 @@ 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, final_amount, 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 8c60ed4e3219..20932c567433 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; @@ -645,13 +561,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)", @@ -662,8 +576,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)) { @@ -708,7 +622,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) { @@ -734,9 +647,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, @@ -745,9 +657,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; } @@ -765,8 +676,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; } @@ -782,7 +693,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; } @@ -791,15 +701,12 @@ static void forward_htlc(struct htlc_in *hin, outgoing_cltv_value, AMOUNT_MSAT(0), &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, @@ -1497,7 +1404,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, @@ -1575,7 +1482,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 d6c49983e613..3cdf6476ecdf 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, @@ -50,8 +50,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 7dc898b452b9..a5a68b4ae954 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 695998e30b1c..1ca2fd25de15 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -131,9 +131,6 @@ 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(); } /* 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(); } @@ -149,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, @@ -585,7 +585,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) @@ -736,9 +736,6 @@ 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(); } From 042a6ed48ee36a3eb1f7269af9ca1152198a23f4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:32:52 +1030 Subject: [PATCH 06/34] 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 a8d0aaaa0b76..0c272791529a 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 * @@ -3312,6 +3293,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; @@ -3373,7 +3363,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: @@ -3387,18 +3377,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: @@ -3408,7 +3398,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; } @@ -3591,6 +3581,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; @@ -3757,6 +3755,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); @@ -3793,6 +3794,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; } @@ -3898,7 +3900,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 6e12096124ae..77c484e8052e 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -277,65 +277,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; @@ -781,19 +722,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 5ccc425f6f28..5babc51c9fb7 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 be3748e07e06..d8333673fb0a 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -504,6 +504,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); @@ -525,6 +529,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. */ @@ -717,7 +722,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)); @@ -1008,6 +1014,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 2f80661b388f..db8fa838b5c9 100644 --- a/lightningd/channel_control.h +++ b/lightningd/channel_control.h @@ -39,4 +39,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 5859fd675f85..33038d3e3d7e 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -131,8 +132,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 cff1d7e6f4ddf8a1ea3bb9b9aeb188f84cc77287 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:33:52 +1030 Subject: [PATCH 07/34] 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 0c272791529a..a3d9fa113cdf 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); } @@ -3795,6 +3790,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 77c484e8052e..a27e6ccb81ef 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -289,31 +290,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. */ @@ -645,7 +675,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)) { @@ -720,40 +749,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); } @@ -1297,6 +1303,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 7dba19620276..eaec7643caa9 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -115,6 +115,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 c52d68bc3e9f..c95834d02785 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -1820,23 +1820,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, @@ -1851,21 +1846,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 5babc51c9fb7..2ad7a2f3e7c8 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 d8333673fb0a..030b15b5eb2a 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -412,6 +413,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); @@ -508,6 +526,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 33038d3e3d7e..3b13a102119d 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -1,6 +1,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -167,6 +168,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: @@ -278,6 +282,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 4ca14eb3f6e044dcfb4c654f091c853c9035fa9e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:34:52 +1030 Subject: [PATCH 08/34] channeld: pause before sending initial channel_update. The last change exposed 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. We can have the channel_update hit gossipd before we've told it about the channel. It ignores the channel_update for the currently-unknown channel: we get a 'bad gossip' message, but the immediate symptom is a timeout in tests/test_closing.py::test_onchain_multihtlc_their_unilateral: ``` node_factory = bitcoind = @pytest.mark.developer("needs DEVELOPER=1 for dev_ignore_htlcs") @pytest.mark.slow_test def test_onchain_multihtlc_their_unilateral(node_factory, bitcoind): """Node pushes a channel onchain with multiple HTLCs with same payment_hash """ > h, nodes = setup_multihtlc_test(node_factory, bitcoind) tests/test_closing.py:2938: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tests/test_closing.py:2780: in setup_multihtlc_test nodes = node_factory.line_graph(7, wait_for_announce=True, /usr/local/lib/python3.8/dist-packages/pyln/testing/utils.py:1416: in line_graph self.join_nodes(nodes, fundchannel, fundamount, wait_for_announce, announce_channels) /usr/local/lib/python3.8/dist-packages/pyln/testing/utils.py:1394: in join_nodes nodes[i + 1].wait_channel_active(scids[i]) /usr/local/lib/python3.8/dist-packages/pyln/testing/utils.py:958: in wait_channel_active wait_for(lambda: self.is_channel_active(chanid)) ``` Note that we are usually much faster to send between subds than we are between peers, but during CI this is common, as we're all running on the same machine. Signed-off-by: Rusty Russell --- channeld/channeld.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index a3d9fa113cdf..c0a2d46857bb 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -419,6 +419,13 @@ static void send_channel_update(struct peer *peer, int disable_flag) wire_sync_write(MASTER_FD, take(msg)); } +/* Tell gossipd and the other side what parameters we expect should + * they route through us */ +static void send_channel_initial_update(struct peer *peer) +{ + send_channel_update(peer, 0); +} + /** * Add a channel locally and send a channel update to the peer * @@ -442,9 +449,12 @@ static void make_channel_local_active(struct peer *peer) 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); + /* Under CI, because blocks come so fast, we often find that the + * peer sends its first channel_update before the above message has + * reached it. */ + notleak(new_reltimer(&peer->timers, peer, + time_from_sec(5), + send_channel_initial_update, peer)); } static void send_announcement_signatures(struct peer *peer) From 6a17c89d125a341d9c221155dd8be0bc53bfa017 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:35:52 +1030 Subject: [PATCH 09/34] 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 1728b3a45d1c..ba9219f76923 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1368,6 +1369,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; @@ -2991,7 +3010,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 28c9a407dfa8..87a38d3520db 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -3396,6 +3396,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; @@ -3410,6 +3442,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); @@ -3665,6 +3700,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 c87fbef2a30d..6c6543487d4e 100644 --- a/openingd/dualopend_wire.csv +++ b/openingd/dualopend_wire.csv @@ -238,3 +238,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 95b0decf8a244db24e3f63b14852c330561a7024 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:36:52 +1030 Subject: [PATCH 10/34] 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 01be81414106..64dac103535d 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 @@ -1577,7 +1578,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 } @@ -2001,6 +2002,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 @@ -2037,6 +2047,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 aa151ea891c3..86800f1e93ec 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -126,6 +126,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 a8861aad1d4a..e46305595653 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -403,9 +403,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; @@ -418,11 +418,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 ? @@ -463,6 +468,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 3b13a102119d..f6895fd69d00 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -239,7 +239,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; @@ -248,7 +248,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 cedc20e77d8d..b8ec5851fc69 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -850,7 +850,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 9cac29111ef9..ac79fffe3f7a 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -23,7 +23,7 @@ void channel_notify_new_block(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) @@ -92,7 +92,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 5b7cccf60530c32693f7b6252486e389c878d6fc Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:37:52 +1030 Subject: [PATCH 11/34] 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 64dac103535d..babdd5c00ed8 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -2007,7 +2007,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 a27e6ccb81ef..3e90a2dae9b0 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); } @@ -857,6 +861,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, @@ -868,8 +974,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; } @@ -878,6 +987,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: @@ -1037,6 +1173,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 2ad7a2f3e7c8..f1bedb5c7071 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(); } @@ -335,6 +338,9 @@ u8 *towire_gossipd_new_blockheight_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 4b48a405082bd713d049a125cd580163d918777b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:38:52 +1030 Subject: [PATCH 12/34] connectd: divert gossip messages directly to gossipd. Signed-off-by: Rusty Russell --- connectd/multiplex.c | 17 ++++++++++++++++- gossipd/gossipd.c | 30 ++++++++---------------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/connectd/multiplex.c b/connectd/multiplex.c index cdcb17a0c7bc..2d0ee88b2cbf 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +31,7 @@ #include #include #include +#include void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) { @@ -334,7 +337,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; @@ -347,6 +350,18 @@ 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); + + /* gossipd doesn't log IO, so we log it here. */ + status_peer_io(LOG_IO_IN, &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 3e90a2dae9b0..88ab7bab3698 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -682,27 +682,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; @@ -710,7 +689,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 4c9e67cb49a1dc0ebf3b7da6bb6d710dd992a806 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 25 Jan 2022 06:39:52 +1030 Subject: [PATCH 13/34] 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 88ab7bab3698..0e8153ffab6c 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. */ @@ -798,11 +798,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); @@ -1157,7 +1156,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 f1bedb5c7071..13e47d554e91 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 bc18acf6e85dd78a682da7665c0ed09ef63e6ad9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:01:19 +1030 Subject: [PATCH 14/34] pytest: ignore pings when doing query_gossip. Next patch starts a timeout ping, which can interfere with results. In theory, we should reply, but in practice (so far!) we seem to get enough time that it doesn't hang up on us. Signed-off-by: Rusty Russell --- tests/test_gossip.py | 54 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index c0210f7f28ea..9224375954b6 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -271,7 +271,7 @@ def test_gossip_timestamp_filter(node_factory, bitcoind, chainparams): msgs = l4.query_gossip('gossip_timestamp_filter', genesis_blockhash, '0', '0xFFFFFFFF', - filters=['0109']) + filters=['0109', '0012']) # 0x0100 = channel_announcement # 0x0102 = channel_update @@ -284,7 +284,7 @@ def test_gossip_timestamp_filter(node_factory, bitcoind, chainparams): msgs = l4.query_gossip('gossip_timestamp_filter', genesis_blockhash, '0', before_anything - backdate, - filters=['0109']) + filters=['0109', '0012']) assert msgs == [] # Now choose range which will only give first update. @@ -292,7 +292,7 @@ def test_gossip_timestamp_filter(node_factory, bitcoind, chainparams): genesis_blockhash, before_anything - backdate, after_12 - before_anything + 1, - filters=['0109']) + filters=['0109', '0012']) # 0x0100 = channel_announcement # 0x0102 = channel_update @@ -306,7 +306,7 @@ def test_gossip_timestamp_filter(node_factory, bitcoind, chainparams): genesis_blockhash, after_12 - backdate, after_23 - after_12 + 1, - filters=['0109']) + filters=['0109', '0012']) # 0x0100 = channel_announcement # 0x0102 = channel_update @@ -703,7 +703,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', chainparams['chain_hash'], 0, 1000000, - filters=['0109']) + filters=['0109', '0012']) encoded = subprocess.run(['devtools/mkencoded', '--scids', '00', scid12, scid23], check=True, timeout=TIMEOUT, @@ -722,7 +722,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, 0, block12, - filters=['0109']) + filters=['0109', '0012']) # reply_channel_range == 264 assert msgs == ['0108' # blockhash @@ -736,7 +736,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, 0, block12 + 1, - filters=['0109']) + filters=['0109', '0012']) encoded = subprocess.run(['devtools/mkencoded', '--scids', '00', scid12], check=True, timeout=TIMEOUT, @@ -755,7 +755,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, 0, block23, - filters=['0109']) + filters=['0109', '0012']) encoded = subprocess.run(['devtools/mkencoded', '--scids', '00', scid12], check=True, timeout=TIMEOUT, @@ -774,7 +774,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, block12, block23 - block12 + 1, - filters=['0109']) + filters=['0109', '0012']) encoded = subprocess.run(['devtools/mkencoded', '--scids', '00', scid12, scid23], check=True, timeout=TIMEOUT, @@ -793,7 +793,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, block23, 1, - filters=['0109']) + filters=['0109', '0012']) encoded = subprocess.run(['devtools/mkencoded', '--scids', '00', scid23], check=True, timeout=TIMEOUT, @@ -812,7 +812,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, block23 + 1, 1000000, - filters=['0109']) + filters=['0109', '0012']) # reply_channel_range == 264 assert msgs == ['0108' # blockhash @@ -829,7 +829,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, 0, 1000000, - filters=['0109']) + filters=['0109', '0012']) # It should definitely have split l2.daemon.wait_for_log('reply_channel_range: splitting 0-1 of 2') @@ -854,7 +854,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, 1, 429496000, - filters=['0109']) + filters=['0109', '0012']) assert len(msgs) == 2 # This should actually be large enough for zlib to kick in! @@ -870,7 +870,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): msgs = l2.query_gossip('query_channel_range', genesis_blockhash, 0, 65535, - filters=['0109']) + filters=['0109', '0012']) encoded = subprocess.run(['devtools/mkencoded', '--scids', '01', scid12, scid23, scid34], check=True, timeout=TIMEOUT, @@ -957,7 +957,7 @@ def test_query_short_channel_id(node_factory, bitcoind, chainparams): msgs = l1.query_gossip('query_short_channel_ids', chain_hash, encoded, - filters=['0109']) + filters=['0109', '0012']) # Should just get the WIRE_REPLY_SHORT_CHANNEL_IDS_END = 262 # (with chainhash and completeflag = 1) @@ -980,7 +980,7 @@ def test_query_short_channel_id(node_factory, bitcoind, chainparams): msgs = l1.query_gossip('query_short_channel_ids', chain_hash, encoded, - filters=['0109']) + filters=['0109', '0012']) assert len(msgs) == 6 # 0x0100 = channel_announcement @@ -1000,7 +1000,7 @@ def test_query_short_channel_id(node_factory, bitcoind, chainparams): msgs = l1.query_gossip('query_short_channel_ids', chain_hash, encoded, - filters=['0109']) + filters=['0109', '0012']) # Technically, this order could be different, but this matches code. assert len(msgs) == 10 @@ -1273,7 +1273,8 @@ def test_node_reannounce(node_factory, bitcoind, chainparams): '0', '0xFFFFFFFF', # Filter out gossip_timestamp_filter, # channel_announcement and channel_updates. - filters=['0109', '0102', '0100']) + # And pings. + filters=['0109', '0102', '0100', '0012']) assert len(msgs) == 2 assert (bytes("SENIORBEAM", encoding="utf8").hex() in msgs[0] @@ -1287,7 +1288,8 @@ def test_node_reannounce(node_factory, bitcoind, chainparams): '0', '0xFFFFFFFF', # Filter out gossip_timestamp_filter, # channel_announcement and channel_updates. - filters=['0109', '0102', '0100']) + # And pings. + filters=['0109', '0102', '0100', '0012']) assert msgs == msgs2 # Won't have queued up another one, either. assert not l1.daemon.is_in_log('node_announcement: delaying') @@ -1311,7 +1313,8 @@ def test_node_reannounce(node_factory, bitcoind, chainparams): '0', '0xFFFFFFFF', # Filter out gossip_timestamp_filter, # channel_announcement and channel_updates. - filters=['0109', '0102', '0100']) + # And pings. + filters=['0109', '0102', '0100', '0012']) assert msgs != msgs2 @@ -1328,11 +1331,14 @@ def test_gossipwith(node_factory): num_msgs = 0 while len(out): l, t = struct.unpack('>HH', out[0:4]) - # channel_announcement node_announcement, channel_update or timestamp_filter - assert t == 256 or t == 257 or t == 258 or t == 265 out = out[2 + l:] - if t != 265: - num_msgs += 1 + + # Ignore pings, timestamp_filter + if t == 265 or t == 18: + continue + # channel_announcement node_announcement or channel_update + assert t == 256 or t == 257 or t == 258 + num_msgs += 1 # one channel announcement, two channel_updates, two node announcements. assert num_msgs == 5 From b4c45af28bcab1d8aecdefe324444141b02422fd Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:01:32 +1030 Subject: [PATCH 15/34] 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 | 215 +++++++++++++++++++++++++++++++---- 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, 249 insertions(+), 247 deletions(-) delete mode 100644 lightningd/ping.h diff --git a/channeld/channeld.c b/channeld/channeld.c index c0a2d46857bb..01736f526331 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; @@ -1095,29 +1079,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) @@ -2190,29 +2151,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); @@ -2298,19 +2236,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); @@ -2326,6 +2251,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: @@ -3608,57 +3534,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) { @@ -3757,9 +3632,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; @@ -3798,7 +3670,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: @@ -4039,10 +3910,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 babdd5c00ed8..1d9bdfe29882 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1966,6 +1966,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); @@ -1978,6 +1982,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 86800f1e93ec..7b2eaa98da3d 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 { @@ -65,6 +75,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; + #if DEVELOPER bool dev_read_enabled; /* If non-NULL, this counts down; 0 means disable */ 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 2d0ee88b2cbf..18010471a158 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -14,12 +14,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -337,32 +339,110 @@ 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; + + /* gossipd doesn't log IO, so we log it here. */ + status_peer_io(LOG_IO_IN, &peer->id, msg); + + 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) +{ + /* gossipd doesn't log IO, so we log it here. */ + status_peer_io(LOG_IO_IN, &peer->id, 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); + + /* gossipd doesn't log IO, so we log it here. */ + status_peer_io(LOG_IO_IN, &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); - - /* gossipd doesn't log IO, so we log it here. */ - status_peer_io(LOG_IO_IN, &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; } /* gossipd doesn't log IO, so we log it here. */ @@ -371,7 +451,7 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg) 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; @@ -388,8 +468,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 void close_timeout(struct peer *peer) @@ -665,6 +772,10 @@ struct io_plan *multiplex_peer_setup(struct io_conn *peer_conn, * lightningd to tell us to close with the peer */ tal_add_destructor2(peer_conn, destroy_peer_conn, peer); + /* Start keepalives */ + peer->expecting_pong = PONG_UNEXPECTED; + set_ping_timer(peer); + return io_duplex(peer_conn, read_hdr_from_peer(peer_conn, peer), write_to_peer(peer_conn, peer)); @@ -677,3 +788,65 @@ 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 0b3ba146a1ff..bbb67e75501e 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -30,4 +30,7 @@ void setup_peer_gossip_store(struct peer *peer, /* Start the process of flushing and closing the peer_conn */ void close_peer_conn(struct peer *peer); + +/* 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 c1cbf9d4db57..90cb704a9ae5 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -31,7 +31,6 @@ LIGHTNINGD_SRC := \ lightningd/peer_control.c \ lightningd/peer_fd.c \ lightningd/peer_htlcs.c \ - lightningd/ping.c \ lightningd/plugin.c \ lightningd/plugin_control.c \ lightningd/plugin_hook.c \ @@ -42,6 +41,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 030b15b5eb2a..2e7792dc88a6 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -22,7 +22,6 @@ #include #include #include -#include #include static void update_feerates(struct lightningd *ld, struct channel *channel) @@ -519,9 +518,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); @@ -565,7 +561,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 e46305595653..ed037461a03b 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -363,10 +363,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 fb2d2086ec83a6b256a205878b25da5f871ecefa Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:02:32 +1030 Subject: [PATCH 16/34] 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 | 408 +++++++++++++++++++++ gossipd/Makefile | 6 - gossipd/gossipd.c | 356 +----------------- gossipd/gossipd_wire.csv | 19 - gossipd/test/run-onion_message.c | 588 ------------------------------ lightningd/connect_control.c | 6 + lightningd/gossip_control.c | 5 - lightningd/onion_message.c | 12 +- wire/peer_wire.c | 4 +- 15 files changed, 827 insertions(+), 978 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 1d9bdfe29882..b8343f6c69c9 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1970,6 +1971,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); @@ -1983,6 +1988,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 18010471a158..8637d01ff322 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -488,6 +489,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..8533d718f703 --- /dev/null +++ b/connectd/test/run-onion_message.c @@ -0,0 +1,408 @@ +#include "config.h" +#include "../onion_message.c" +#include "common/blindedpath.c" +#include "common/blinding.c" +#include "common/bigsize.c" +#include "common/hmac.c" +#include "common/onion.c" +#include "common/sphinx.c" +#include "wire/fromwire.c" +#if EXPERIMENTAL_FEATURES +#include "wire/peer_exp_wiregen.c" +#include "wire/onion_exp_wiregen.c" +#else +#include "wire/peer_wiregen.c" +#include "wire/onion_wiregen.c" +#endif +#include "wire/tlvstream.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_msat */ +struct amount_msat amount_msat(u64 millisatoshis UNNEEDED) +{ fprintf(stderr, "amount_msat called!\n"); abort(); } +/* Generated stub for amount_msat_eq */ +bool amount_msat_eq(struct amount_msat a UNNEEDED, struct amount_msat b UNNEEDED) +{ fprintf(stderr, "amount_msat_eq 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 ecdh */ +void ecdh(const struct pubkey *point UNNEEDED, struct secret *ss UNNEEDED) +{ fprintf(stderr, "ecdh called!\n"); abort(); } +/* Generated stub for fromwire_amount_msat */ +struct amount_msat fromwire_amount_msat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_amount_msat called!\n"); abort(); } +/* Generated stub for fromwire_amount_sat */ +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 */ +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_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_node_id */ +void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) +{ fprintf(stderr, "fromwire_node_id 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(); } +/* 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 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 status_fmt */ +void status_fmt(enum log_level level UNNEEDED, + const struct node_id *peer UNNEEDED, + const char *fmt UNNEEDED, ...) + +{ fprintf(stderr, "status_fmt called!\n"); abort(); } +/* Generated stub for towire */ +void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "towire called!\n"); abort(); } +/* Generated stub for towire_amount_msat */ +void towire_amount_msat(u8 **pptr UNNEEDED, const struct amount_msat msat UNNEEDED) +{ fprintf(stderr, "towire_amount_msat called!\n"); abort(); } +/* Generated stub for towire_amount_sat */ +void towire_amount_sat(u8 **pptr UNNEEDED, const struct amount_sat sat UNNEEDED) +{ fprintf(stderr, "towire_amount_sat 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_channel_id */ +void towire_channel_id(u8 **pptr UNNEEDED, const struct channel_id *channel_id UNNEEDED) +{ fprintf(stderr, "towire_channel_id 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_node_id */ +void towire_node_id(u8 **pptr UNNEEDED, const struct node_id *id UNNEEDED) +{ fprintf(stderr, "towire_node_id called!\n"); abort(); } +/* Generated stub for towire_pad */ +void towire_pad(u8 **pptr UNNEEDED, size_t num UNNEEDED) +{ fprintf(stderr, "towire_pad 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_tu32 */ +void towire_tu32(u8 **pptr UNNEEDED, u32 v UNNEEDED) +{ fprintf(stderr, "towire_tu32 called!\n"); abort(); } +/* Generated stub for towire_tu64 */ +void towire_tu64(u8 **pptr UNNEEDED, u64 v UNNEEDED) +{ fprintf(stderr, "towire_tu64 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(); } +/* 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 0e8153ffab6c..d7797c068e0b 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 @@ -350,327 +347,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. */ @@ -678,17 +354,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: @@ -730,6 +397,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 @@ -743,14 +412,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 @@ -891,12 +552,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: @@ -932,6 +587,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 @@ -1464,16 +1121,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_NEW_BLOCKHEIGHT_REPLY: case WIRE_GOSSIPD_GET_ADDRS_REPLY: diff --git a/gossipd/gossipd_wire.csv b/gossipd/gossipd_wire.csv index eaec7643caa9..e5369751ed89 100644 --- a/gossipd/gossipd_wire.csv +++ b/gossipd/gossipd_wire.csv @@ -69,25 +69,6 @@ msgdata,gossipd_new_blockheight,blockheight,u32, # gossipd: got it! msgtype,gossipd_new_blockheight_reply,3126 -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 13e47d554e91..000000000000 --- a/gossipd/test/run-onion_message.c +++ /dev/null @@ -1,588 +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_blockheight_reply */ -u8 *towire_gossipd_new_blockheight_reply(const tal_t *ctx UNNEEDED) -{ fprintf(stderr, "towire_gossipd_new_blockheight_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 ed037461a03b..bd56b82c166e 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -364,6 +365,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: @@ -384,6 +386,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 f6895fd69d00..7429d4db3a89 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -164,7 +163,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: @@ -180,9 +178,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 de82e39e243f7024fa232b0fd823cc9f8e2e7de3 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 17/34] connectd: do io logging properly for msgs we make. We don't need to log msgs from subds, but we do our own, and we weren't. 1. Rename queue_peer_msg to inject_peer_msg for clarity, make it do logging 2. In the one place where we're relaying, call msg_queue() directly. Signed-off-by: Rusty Russell --- connectd/connectd.c | 2 +- connectd/multiplex.c | 11 ++++++----- connectd/multiplex.h | 5 +++-- connectd/onion_message.c | 30 +++++++++++++++--------------- connectd/test/run-onion_message.c | 6 +++--- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index b8343f6c69c9..aa24cd0999f3 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -2028,7 +2028,7 @@ static struct io_plan *recv_gossip(struct io_conn *conn, peer = peer_htable_get(&daemon->peers, &dst); if (peer) - queue_peer_msg(peer, take(gossip_msg)); + inject_peer_msg(peer, take(gossip_msg)); return daemon_conn_read_next(conn, daemon->gossipd); } diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 8637d01ff322..384f12f62225 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -36,8 +36,9 @@ #include #include -void queue_peer_msg(struct peer *peer, const u8 *msg TAKES) +void inject_peer_msg(struct peer *peer, const u8 *msg TAKES) { + status_peer_io(LOG_IO_OUT, &peer->id, msg); msg_enqueue(peer->peer_outq, msg); } @@ -360,7 +361,7 @@ static void send_ping(struct peer *peer) return; } - queue_peer_msg(peer, take(make_ping(NULL, 1, 0))); + inject_peer_msg(peer, take(make_ping(NULL, 1, 0))); peer->expecting_pong = PONG_EXPECTED_PROBING; set_ping_timer(peer); } @@ -378,7 +379,7 @@ static void handle_ping_in(struct peer *peer, const u8 *msg) } if (pong) - queue_peer_msg(peer, take(pong)); + inject_peer_msg(peer, take(pong)); } static void handle_ping_reply(struct peer *peer, const u8 *msg) @@ -582,7 +583,7 @@ static struct io_plan *read_from_subd_done(struct io_conn *subd_conn, struct peer *peer) { /* Tell them to encrypt & write. */ - queue_peer_msg(peer, take(peer->subd_in)); + msg_enqueue(peer->peer_outq, take(peer->subd_in)); peer->subd_in = NULL; /* Wait for them to wake us */ @@ -828,7 +829,7 @@ void send_manual_ping(struct daemon *daemon, const u8 *msg) if (tal_count(ping) > 65535) status_failed(STATUS_FAIL_MASTER_IO, "Oversize ping"); - queue_peer_msg(peer, take(ping)); + inject_peer_msg(peer, take(ping)); status_debug("sending ping expecting %sresponse", num_pong_bytes >= 65532 ? "no " : ""); diff --git a/connectd/multiplex.h b/connectd/multiplex.h index bbb67e75501e..fa0a032fb100 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -21,8 +21,9 @@ struct io_plan *multiplex_peer_setup(struct io_conn *peer_conn, 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); +/* Inject a message into the output stream. Unlike a raw msg_enqueue, + * this does io logging if required. */ +void inject_peer_msg(struct peer *peer, const u8 *msg TAKES); void setup_peer_gossip_store(struct peer *peer, const struct feature_set *our_features, diff --git a/connectd/onion_message.c b/connectd/onion_message.c index f19594899172..5459fd57b181 100644 --- a/connectd/onion_message.c +++ b/connectd/onion_message.c @@ -37,9 +37,9 @@ void handle_obs2_onion_message(struct daemon *daemon, /* FIXME: ratelimit! */ if (!fromwire_obs2_onion_message(msg, msg, &blinding, &onion)) { - queue_peer_msg(peer, - towire_warningfmt(NULL, NULL, - "Bad onion_message")); + inject_peer_msg(peer, + towire_warningfmt(NULL, NULL, + "Bad onion_message")); return; } @@ -161,10 +161,10 @@ void handle_obs2_onion_message(struct daemon *daemon, &next_node)); return; } - queue_peer_msg(next_peer, - take(towire_obs2_onion_message(NULL, - &next_blinding, - serialize_onionpacket(tmpctx, rs->next)))); + inject_peer_msg(next_peer, + take(towire_obs2_onion_message(NULL, + &next_blinding, + serialize_onionpacket(tmpctx, rs->next)))); } } @@ -188,7 +188,7 @@ void onionmsg_req(struct daemon *daemon, const u8 *msg) omsg = towire_obs2_onion_message(NULL, &blinding, onionmsg); else omsg = towire_onion_message(NULL, &blinding, onionmsg); - queue_peer_msg(peer, take(omsg)); + inject_peer_msg(peer, take(omsg)); } } @@ -213,9 +213,9 @@ void handle_onion_message(struct daemon *daemon, /* FIXME: ratelimit! */ if (!fromwire_onion_message(msg, msg, &blinding, &onion)) { - queue_peer_msg(peer, - towire_warningfmt(NULL, NULL, - "Bad onion_message")); + inject_peer_msg(peer, + towire_warningfmt(NULL, NULL, + "Bad onion_message")); return; } @@ -336,10 +336,10 @@ void handle_onion_message(struct daemon *daemon, &next_node)); return; } - queue_peer_msg(next_peer, - take(towire_onion_message(NULL, - &next_blinding, - serialize_onionpacket(tmpctx, rs->next)))); + inject_peer_msg(next_peer, + take(towire_onion_message(NULL, + &next_blinding, + serialize_onionpacket(tmpctx, rs->next)))); } } diff --git a/connectd/test/run-onion_message.c b/connectd/test/run-onion_message.c index 8533d718f703..56ea1e268a05 100644 --- a/connectd/test/run-onion_message.c +++ b/connectd/test/run-onion_message.c @@ -88,6 +88,9 @@ bool fromwire_connectd_send_onionmsg(const tal_t *ctx UNNEEDED, const void *p UN /* Generated stub for fromwire_node_id */ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct node_id *id UNNEEDED) { fprintf(stderr, "fromwire_node_id called!\n"); abort(); } +/* Generated stub for inject_peer_msg */ +void inject_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED) +{ fprintf(stderr, "inject_peer_msg 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(); } @@ -100,9 +103,6 @@ void node_id_from_pubkey(struct node_id *id UNNEEDED, const struct pubkey *key U /* 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 status_fmt */ void status_fmt(enum log_level level UNNEEDED, const struct node_id *peer UNNEEDED, From c7ec0a35475cd1bccce96a22ed80c209b5d07198 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 18/34] common: make sure we hand through peer for io logging. This is mainly useful for connectd. Signed-off-by: Rusty Russell --- common/status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/status.c b/common/status.c index 499484c39f61..d2d770523c3e 100644 --- a/common/status.c +++ b/common/status.c @@ -125,7 +125,7 @@ void status_peer_io(enum log_level iodir, { report_logging_io("SIGUSR1"); if (logging_io) - status_io_full(iodir, NULL, "", p); + status_io_full(iodir, peer, "", p); /* We get a huge amount of gossip; don't log it */ else if (!is_msg_for_gossipd(p)) status_peer_io_short(iodir, peer, p); From 8ffb126c169d33e5ecdf5361f8dafa2a49a68c70 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 19/34] 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 | 37 +++++ connectd/multiplex.h | 3 + lightningd/channel_control.c | 10 -- lightningd/closing_control.c | 10 -- lightningd/connect_control.c | 149 ++++++++++++++++++ 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 ---- tests/test_misc.py | 8 +- wallet/test/run-wallet.c | 20 --- wire/Makefile | 2 - wire/common_wire.csv | 10 -- 21 files changed, 215 insertions(+), 394 deletions(-) delete mode 100644 wire/common_wire.csv diff --git a/channeld/channeld.c b/channeld/channeld.c index 01736f526331..dfc3923181d2 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include @@ -2049,23 +2048,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; @@ -2155,9 +2137,6 @@ static void peer_in(struct peer *peer, const u8 *msg) { enum peer_wire type = fromwire_peektype(msg); - if (channeld_handle_custommsg(msg)) - return; - if (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, msg)) return; @@ -2824,8 +2803,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, msg) || + } while (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, msg) || capture_premature_msg(&premature_msgs, msg)); got_reestablish: @@ -3577,17 +3555,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); @@ -3676,17 +3643,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 2d228a462434..4d8beddac3b9 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -126,15 +125,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, msg)) return msg; } diff --git a/connectd/connectd.c b/connectd/connectd.c index aa24cd0999f3..3016ceb37419 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1975,6 +1975,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); @@ -1989,6 +1993,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 384f12f62225..f94175b32ec0 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -366,6 +366,21 @@ static void send_ping(struct peer *peer) 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) + inject_peer_msg(peer, take(custommsg)); +} + static void handle_ping_in(struct peer *peer, const u8 *msg) { u8 *pong; @@ -472,6 +487,26 @@ static void handle_gossip_timetamp_filter_in(struct peer *peer, const u8 *msg) wake_gossip(peer); } +static bool handle_custommsg(struct daemon *daemon, + struct peer *peer, + 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. */ + status_peer_io(LOG_IO_IN, &peer->id, msg); + daemon_conn_send(daemon->master, + take(towire_connectd_custommsg_in(NULL, + &peer->id, + msg))); + return true; + } else { + return false; + } +} + /* We handle pings and gossip messages. */ static bool handle_message_locally(struct peer *peer, const u8 *msg) { @@ -496,6 +531,8 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg) } else if (type == WIRE_ONION_MESSAGE) { handle_onion_message(peer->daemon, peer, msg); return true; + } else if (handle_custommsg(peer->daemon, peer, msg)) { + return true; } /* Do we want to divert to gossipd? */ diff --git a/connectd/multiplex.h b/connectd/multiplex.h index fa0a032fb100..13c37e298221 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -34,4 +34,7 @@ void close_peer_conn(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 2e7792dc88a6..dcfb4536686b 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -22,7 +22,6 @@ #include #include #include -#include static void update_feerates(struct lightningd *ld, struct channel *channel) { @@ -564,15 +563,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 65f4bb909fad..1feed3897ecb 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -38,7 +38,6 @@ #include #include #include -#include struct close_command { /* Inside struct lightningd close_commands. */ @@ -336,15 +335,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 bd56b82c166e..292114810244 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include struct connect { struct list_node list; @@ -352,6 +354,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); @@ -366,6 +425,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: @@ -390,6 +450,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; } @@ -500,3 +564,88 @@ 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)); + } + + /* FIXME: This won't work once connectd keeps peers */ + if (!peer_get_owning_subd(peer)) { + return command_fail(cmd, JSONRPC2_INVALID_REQUEST, + "Peer is not connected: %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 ba9219f76923..b65f6a6c5966 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -31,7 +31,6 @@ #include #include #include -#include struct commit_rcvd { struct channel *channel; @@ -3030,15 +3029,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 acb53d292951..ad88b934aa2a 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -28,7 +28,6 @@ #include #include #include -#include void json_add_uncommitted_channel(struct json_stream *response, const struct uncommitted_channel *uc) @@ -890,15 +889,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 e87d0ae8bcc2..1dcd8302fc6e 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -65,7 +65,6 @@ #include #include #include -#include #include #include @@ -2403,167 +2402,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 dff52d9d1840..e16e80ba054b 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -98,9 +98,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 81614f8d1b78..60bb5318beac 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -18,7 +18,6 @@ #include #include #include -#include #include void maybe_subd_child(struct lightningd *ld, int childpid, int wstatus) @@ -831,8 +830,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 cdfcd9ee44cb..2868e952c84c 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -482,11 +482,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, @@ -560,9 +555,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 87a38d3520db..bd870c95a119 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 */ @@ -897,17 +896,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) @@ -3465,23 +3453,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: @@ -3582,10 +3553,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, - msg)); + } while (handle_peer_gossip_or_error(state->pps, + &state->channel_id, + msg)); if (!fromwire_channel_reestablish (msg, &cid, @@ -3703,16 +3673,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)); } @@ -3790,16 +3750,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, msg)) diff --git a/openingd/openingd.c b/openingd/openingd.c index 42257adfbed1..854c5cd088fc 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, 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/tests/test_misc.py b/tests/test_misc.py index 15e7f0e3c7c3..57bc7149a346 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -2168,8 +2168,8 @@ def test_sendcustommsg(node_factory): # This should work since the peer is currently owned by `channeld` l2.rpc.sendcustommsg(l1.info['id'], msg) l2.daemon.wait_for_log( - r'{peer_id}-{owner}-chan#[0-9]: \[OUT\] {msg}'.format( - owner='channeld', msg=msg, peer_id=l1.info['id'] + r'{peer_id}-{owner}: \[OUT\] {msg}'.format( + owner='connectd', msg=msg, peer_id=l1.info['id'] ) ) l1.daemon.wait_for_log(r'\[IN\] {}'.format(msg)) @@ -2183,8 +2183,8 @@ def test_sendcustommsg(node_factory): # This should work since the peer is currently owned by `openingd` l2.rpc.sendcustommsg(l4.info['id'], msg) l2.daemon.wait_for_log( - r'{peer_id}-{owner}-chan#[0-9]: \[OUT\] {msg}'.format( - owner='openingd', msg=msg, peer_id=l4.info['id'] + r'{peer_id}-{owner}: \[OUT\] {msg}'.format( + owner='connectd', msg=msg, peer_id=l4.info['id'] ) ) l4.daemon.wait_for_log(r'\[IN\] {}'.format(msg)) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 1ca2fd25de15..7778c252ce66 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(); } @@ -524,11 +521,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, @@ -594,9 +586,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(); } @@ -619,12 +608,6 @@ void peer_start_dualopend(struct peer *peer UNNEEDED, struct peer_fd *peer_fd UN void peer_start_openingd(struct peer *peer UNNEEDED, struct peer_fd *peer_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) @@ -713,9 +696,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 cee59bc8defc7c8f7625264059a239021ec9ddcb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 20/34] 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 dfc3923181d2..fb90922d2c21 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 8d6d86dbb739f31a765fd2972c5385e0faef8272 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 21/34] subdaemons: remove gossipd fd from per-peer daemons. Signed-off-by: Rusty Russell --- channeld/channeld.c | 25 ++---- 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 | 40 ++------- connectd/connectd.c | 28 +++--- connectd/connectd.h | 3 + connectd/connectd_wire.csv | 4 +- lightningd/channel_control.c | 5 +- lightningd/closing_control.c | 4 +- lightningd/connect_control.c | 6 +- lightningd/dual_open_control.c | 10 +-- lightningd/opening_common.c | 5 +- lightningd/opening_control.c | 13 ++- lightningd/peer_control.c | 10 +-- lightningd/peer_control.h | 3 +- lightningd/peer_fd.c | 13 ++- lightningd/peer_fd.h | 13 ++- lightningd/subd.c | 6 +- lightningd/test/run-find_my_abspath.c | 2 +- lightningd/test/run-invoice-select-inchan.c | 2 +- lightningd/test/run-shuffle_fds.c | 2 +- openingd/dualopend.c | 61 +++---------- openingd/openingd.c | 63 ++++---------- wallet/test/run-wallet.c | 2 +- 27 files changed, 120 insertions(+), 342 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index fb90922d2c21..e491a52e1ba5 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; @@ -2132,13 +2132,12 @@ static void peer_in(struct peer *peer, const u8 *msg) { enum peer_wire type = fromwire_peektype(msg); - if (handle_peer_gossip_or_error(peer->pps, &peer->channel_id, msg)) + if (handle_peer_error(peer->pps, &peer->channel_id, 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 @@ -2215,7 +2214,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: @@ -2798,7 +2797,7 @@ 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, msg) || + } while (handle_peer_error(peer->pps, &peer->channel_id, msg) || capture_premature_msg(&premature_msgs, msg)); got_reestablish: @@ -3752,9 +3751,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 @@ -3895,11 +3894,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; @@ -3958,13 +3956,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 4d8beddac3b9..0cd50bd1683e 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -29,9 +29,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, ...) { @@ -117,15 +117,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, msg)) + msg = peer_read(ctx, pps); + if (!handle_peer_error(pps, channel_id, msg)) return msg; } } @@ -905,9 +900,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 c2f87344cf6f..fcf403f91799 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,70 +61,23 @@ 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, - const u8 *msg TAKES) +bool handle_peer_error(struct per_peer_state *pps, + const struct channel_id *channel_id, + 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, 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 a3fecb83f1ac..2719eb2a3c64 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,26 +36,15 @@ 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. * @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, - 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, + 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 3016ceb37419..b70f9bafc3dc 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); } @@ -395,7 +397,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) @@ -454,8 +456,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); } @@ -469,10 +471,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); @@ -1894,20 +1895,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 7b2eaa98da3d..a630ff64968e 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -81,6 +81,9 @@ struct peer { /* Random ping timer, to detect dead connections. */ struct oneshot *ping_timer; + /* FIXME: remove! */ + int gossip_fd; + #if DEVELOPER bool dev_read_enabled; /* If non-NULL, this counts down; 0 means disable */ 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 dcfb4536686b..d36baacd8749 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -506,9 +506,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: @@ -603,7 +603,6 @@ void peer_start_channeld(struct channel *channel, channel_errmsg, channel_set_billboard, take(&peer_fd->fd), - take(&peer_fd->gossip_fd), take(&hsmfd), NULL)); if (!channel->owner) { diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index 1feed3897ecb..64261238d76e 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -338,8 +338,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 peer_fd *peer_fd) +void peer_start_closingd(struct channel *channel, struct peer_fd *peer_fd) { u8 *initmsg; u32 min_feerate, feerate, *max_feerate; @@ -369,7 +368,6 @@ void peer_start_closingd(struct channel *channel, channel_errmsg, channel_set_billboard, take(&peer_fd->fd), - take(&peer_fd->gossip_fd), take(&hsmfd), NULL)); diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 292114810244..f3da8ff8042f 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -438,9 +438,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 b65f6a6c5966..9b3a05ad8cf9 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -2994,16 +2994,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: @@ -3230,7 +3230,6 @@ static void start_fresh_dualopend(struct peer *peer, channel_errmsg, channel_set_billboard, take(&peer_fd->fd), - take(&peer_fd->gossip_fd), take(&hsmfd), NULL); if (!channel->owner) { @@ -3297,7 +3296,6 @@ void peer_restart_dualopend(struct peer *peer, channel_errmsg, channel_set_billboard, take(&peer_fd->fd), - take(&peer_fd->gossip_fd), take(&hsmfd), NULL)); if (!channel->owner) { log_broken(channel->log, "Could not subdaemon channel: %s", diff --git a/lightningd/opening_common.c b/lightningd/opening_common.c index 7843267051bd..7afc8b4b4996 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -195,9 +195,8 @@ void handle_reestablish(struct lightningd *ld, take(towire_connectd_peer_final_msg(NULL, peer_id, err))); subd_send_fd(ld->connectd, peer_fd->fd); - subd_send_fd(ld->connectd, peer_fd->gossip_fd); - /* Don't close those fds! */ - peer_fd->fd = peer_fd->gossip_fd = -1; + /* Don't close this fd! */ + peer_fd->fd = -1; } } diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index ad88b934aa2a..4c91a43f2751 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -838,8 +838,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: @@ -862,8 +862,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; @@ -872,8 +872,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; @@ -919,7 +919,6 @@ void peer_start_openingd(struct peer *peer, struct peer_fd *peer_fd) opend_channel_errmsg, opend_channel_set_billboard, take(&peer_fd->fd), - take(&peer_fd->gossip_fd), take(&hsmfd), NULL); if (!uc->open_daemon) { uncommitted_channel_disconnect(uc, LOG_BROKEN, diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 1dcd8302fc6e..ec594fad6d36 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1053,9 +1053,8 @@ 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->fd); - subd_send_fd(ld->connectd, payload->peer_fd->gossip_fd); - /* Don't close those fds! */ - payload->peer_fd->fd = payload->peer_fd->gossip_fd = -1; + /* Don't close the fd! */ + payload->peer_fd->fd = -1; } static bool @@ -1111,8 +1110,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; @@ -1129,7 +1127,7 @@ void peer_connected(struct lightningd *ld, const u8 *msg, fatal("Connectd gave bad CONNECT_PEER_CONNECTED message %s", tal_hex(msg, msg)); - hook_payload->peer_fd = new_peer_fd(hook_payload, peer_fd, gossip_fd); + hook_payload->peer_fd = new_peer_fd(hook_payload, peer_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 e16e80ba054b..fc06b3d0c222 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -64,8 +64,7 @@ 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 diff --git a/lightningd/peer_fd.c b/lightningd/peer_fd.c index 5508dc720f92..9a63f55be2df 100644 --- a/lightningd/peer_fd.c +++ b/lightningd/peer_fd.c @@ -7,23 +7,20 @@ static void destroy_peer_fd(struct peer_fd *peer_fd) { if (peer_fd->fd != -1) close(peer_fd->fd); - if (peer_fd->gossip_fd != -1) - close(peer_fd->gossip_fd); } -struct peer_fd *new_peer_fd(const tal_t *ctx, int peer_fdnum, int gossip_fd) +struct peer_fd *new_peer_fd(const tal_t *ctx, int peer_fdnum) { struct peer_fd *peer_fd = tal(ctx, struct peer_fd); peer_fd->fd = peer_fdnum; - peer_fd->gossip_fd = gossip_fd; tal_add_destructor(peer_fd, destroy_peer_fd); return peer_fd; } -struct peer_fd *new_peer_fd_arr(const tal_t *ctx, const int *fds) +struct peer_fd *new_peer_fd_arr(const tal_t *ctx, const int *fd) { - /* We expect 2 fds. */ - assert(tal_count(fds) == 2); - return new_peer_fd(ctx, fds[0], fds[1]); + /* We expect 1 fd. */ + assert(tal_count(fd) == 1); + return new_peer_fd(ctx, fd[0]); } diff --git a/lightningd/peer_fd.h b/lightningd/peer_fd.h index 705deb47684a..fc9ea027bda3 100644 --- a/lightningd/peer_fd.h +++ b/lightningd/peer_fd.h @@ -3,19 +3,16 @@ #include "config.h" #include -/* This name is a little preemptive: it still contains the gossip_fd - * for now! */ +/* Tal wrapper for fd connecting subd to connectd */ struct peer_fd { /* If not -1, closed on freeing */ int fd; - int gossip_fd; }; -/* Allocate a new per-peer state and add destructor to close fds if set; - * sets fds to -1. */ -struct peer_fd *new_peer_fd(const tal_t *ctx, int peer_fd, int gossip_fd); +/* Allocate a new per-peer state and add destructor to close fd if set. */ +struct peer_fd *new_peer_fd(const tal_t *ctx, int peer_fd); -/* Array version of above: tal_count(fds) must be 2 */ -struct peer_fd *new_peer_fd_arr(const tal_t *ctx, const int *fds); +/* Array version of above: tal_count(fds) must be 1 */ +struct peer_fd *new_peer_fd_arr(const tal_t *ctx, const int *fd); #endif /* LIGHTNING_LIGHTNINGD_PEER_FD_H */ diff --git a/lightningd/subd.c b/lightningd/subd.c index 60bb5318beac..f563a32f1f79 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -414,7 +414,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; @@ -533,11 +533,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)) diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index ac79fffe3f7a..8c1e42e022d0 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -168,7 +168,7 @@ struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, 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_peer_fd_arr */ -struct peer_fd *new_peer_fd_arr(const tal_t *ctx UNNEEDED, const int *fds UNNEEDED) +struct peer_fd *new_peer_fd_arr(const tal_t *ctx UNNEEDED, const int *fd UNNEEDED) { fprintf(stderr, "new_peer_fd_arr called!\n"); abort(); } /* Generated stub for new_topology */ struct chain_topology *new_topology(struct lightningd *ld UNNEEDED, struct log *log UNNEEDED) diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 2868e952c84c..8d787bbdca2c 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -437,7 +437,7 @@ struct height_states *new_height_states(const tal_t *ctx UNNEEDED, const u32 *blockheight UNNEEDED) { fprintf(stderr, "new_height_states called!\n"); abort(); } /* Generated stub for new_peer_fd */ -struct peer_fd *new_peer_fd(const tal_t *ctx UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED) +struct peer_fd *new_peer_fd(const tal_t *ctx UNNEEDED, int peer_fd UNNEEDED) { fprintf(stderr, "new_peer_fd called!\n"); abort(); } /* Generated stub for new_reltimer_ */ struct oneshot *new_reltimer_(struct timers *timers UNNEEDED, diff --git a/lightningd/test/run-shuffle_fds.c b/lightningd/test/run-shuffle_fds.c index 3e1d5cd0b2ab..f26907cb66f8 100644 --- a/lightningd/test/run-shuffle_fds.c +++ b/lightningd/test/run-shuffle_fds.c @@ -109,7 +109,7 @@ struct log *new_log(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, const char *fmt UNNEEDED, ...) { fprintf(stderr, "new_log called!\n"); abort(); } /* Generated stub for new_peer_fd_arr */ -struct peer_fd *new_peer_fd_arr(const tal_t *ctx UNNEEDED, const int *fds UNNEEDED) +struct peer_fd *new_peer_fd_arr(const tal_t *ctx UNNEEDED, const int *fd UNNEEDED) { fprintf(stderr, "new_peer_fd_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) diff --git a/openingd/dualopend.c b/openingd/dualopend.c index bd870c95a119..cc49e20ac86f 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) @@ -1164,7 +1164,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; @@ -1175,20 +1174,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: * @@ -3440,19 +3426,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: @@ -3553,9 +3526,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, - msg)); + } while (handle_peer_error(state->pps, + &state->channel_id, + msg)); if (!fromwire_channel_reestablish (msg, &cid, @@ -3750,9 +3723,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, msg)) + /* Handles errors. */ + if (handle_peer_error(state->pps, &state->channel_id, msg)) return NULL; peer_write(state->pps, @@ -3775,7 +3747,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; @@ -3901,9 +3873,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, @@ -3927,10 +3899,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) { @@ -3946,7 +3916,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 @@ -3955,11 +3925,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 854c5cd088fc..282213c88322 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 = peer_read(ctx, state->pps); /* BOLT #1: * @@ -1259,9 +1245,8 @@ static u8 *handle_peer_in(struct state *state) if (t == WIRE_OPEN_CHANNEL) return fundee_channel(state, msg); - /* Handles standard cases, and legal unknown ones. */ - if (handle_peer_gossip_or_error(state->pps, - &state->channel_id, msg)) + /* Handles error cases. */ + if (handle_peer_error(state->pps, &state->channel_id, 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 7778c252ce66..eac5f34d5a49 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -442,7 +442,7 @@ struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx UNNEEDED, { fprintf(stderr, "new_coin_wallet_deposit called!\n"); abort(); } /* Generated stub for new_peer_fd */ -struct peer_fd *new_peer_fd(const tal_t *ctx UNNEEDED, int peer_fd UNNEEDED, int gossip_fd UNNEEDED) +struct peer_fd *new_peer_fd(const tal_t *ctx UNNEEDED, int peer_fd UNNEEDED) { fprintf(stderr, "new_peer_fd called!\n"); abort(); } /* Generated stub for notify_chain_mvt */ void notify_chain_mvt(struct lightningd *ld UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED) From 5dea21132e341dad9b7cce68aadd1cd688cfde7e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 22/34] 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 b70f9bafc3dc..f3cb14afbeec 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); } @@ -398,6 +345,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) @@ -455,12 +403,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); @@ -1846,6 +1794,10 @@ void peer_conn_closed(struct peer *peer) assert(!peer->to_peer); assert(peer->told_to_close); + /* Tell gossipd to stop asking this peer gossip queries */ + daemon_conn_send(peer->daemon->gossipd, + take(towire_gossipd_peer_gone(NULL, &peer->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 a630ff64968e..7b2eaa98da3d 100644 --- a/connectd/connectd.h +++ b/connectd/connectd.h @@ -81,9 +81,6 @@ struct peer { /* Random ping timer, to detect dead connections. */ struct oneshot *ping_timer; - /* FIXME: remove! */ - int gossip_fd; - #if DEVELOPER bool dev_read_enabled; /* If non-NULL, this counts down; 0 means disable */ 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 d7797c068e0b..5fef825a36f7 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. */ @@ -347,103 +341,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; @@ -459,27 +376,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. */ @@ -520,12 +440,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; } @@ -613,20 +532,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. */ @@ -641,10 +557,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 cd61786f60a0904c42d6945129d59edc29caabbf Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 23/34] 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 f3cb14afbeec..70950924ed34 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 @@ -1528,7 +1527,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 } @@ -2027,7 +2026,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 5fef825a36f7..6113dc8cae87 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); @@ -531,27 +531,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); @@ -574,7 +553,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: @@ -732,14 +711,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 f3da8ff8042f..57b0db804189 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -475,9 +475,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; @@ -490,16 +490,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 ? @@ -540,7 +535,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 7429d4db3a89..e16607345b24 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -234,7 +234,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; @@ -243,10 +243,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 b8ec5851fc69..cedc20e77d8d 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -850,7 +850,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 8c1e42e022d0..dbe411903ba9 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/lightningd/test/run-find_my_abspath.c @@ -23,7 +23,7 @@ void channel_notify_new_block(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) @@ -92,7 +92,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 9b51d5bfc4b8d32e249f33b0599ecc1f68fac9f6 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 24/34] connectd: don't received useless peer fd if we're told to send final msg. We don't need the connection to ourselves, just to free it. Signed-off-by: Rusty Russell --- connectd/connectd.c | 11 ----------- connectd/connectd_wire.csv | 2 +- lightningd/opening_common.c | 4 +--- lightningd/peer_control.c | 4 +--- lightningd/test/run-invoice-select-inchan.c | 3 --- wallet/test/run-wallet.c | 3 --- 6 files changed, 3 insertions(+), 24 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 70950924ed34..d161e695feb4 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1846,21 +1846,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 7afc8b4b4996..46087c13819e 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -194,9 +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->fd); - /* Don't close this fd! */ - peer_fd->fd = -1; + tal_free(peer_fd); } } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index ec594fad6d36..5d7627011ba4 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1052,9 +1052,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->fd); - /* Don't close the fd! */ - payload->peer_fd->fd = -1; + tal_free(payload->peer_fd); } static bool diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 8d787bbdca2c..d55ec8384eb7 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -603,9 +603,6 @@ void subd_req_(const tal_t *ctx UNNEEDED, void (*replycb)(struct subd * UNNEEDED, const u8 * UNNEEDED, const int * UNNEEDED, void *) UNNEEDED, void *replycb_data UNNEEDED) { fprintf(stderr, "subd_req_ called!\n"); abort(); } -/* Generated stub for subd_send_fd */ -void subd_send_fd(struct subd *sd UNNEEDED, int fd UNNEEDED) -{ fprintf(stderr, "subd_send_fd called!\n"); abort(); } /* Generated stub for subd_send_msg */ void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED) { fprintf(stderr, "subd_send_msg called!\n"); abort(); } diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index eac5f34d5a49..a6605b25af3f 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -642,9 +642,6 @@ void subd_req_(const tal_t *ctx UNNEEDED, void (*replycb)(struct subd * UNNEEDED, const u8 * UNNEEDED, const int * UNNEEDED, void *) UNNEEDED, void *replycb_data UNNEEDED) { fprintf(stderr, "subd_req_ called!\n"); abort(); } -/* Generated stub for subd_send_fd */ -void subd_send_fd(struct subd *sd UNNEEDED, int fd UNNEEDED) -{ fprintf(stderr, "subd_send_fd called!\n"); abort(); } /* Generated stub for subd_send_msg */ void subd_send_msg(struct subd *sd UNNEEDED, const u8 *msg_out UNNEEDED) { fprintf(stderr, "subd_send_msg called!\n"); abort(); } From 18e1deae5ba779a6e36169fec088d4a923b627e8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:05 +1030 Subject: [PATCH 25/34] gossip_store: handle compacted gossip_store correctly. Don't send EOF marker to peer, e.g. in tests/test_gossip.py::test_gossip_store_compact: ``` lightningd-2: 2022-01-24T03:34:22.925Z DEBUG connectd: gossip_store at end, new fd moved to 1875 lightningd-2: 2022-01-24T03:34:22.933Z DEBUG 035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d-connectd: Sending gossip INVALID 4105 lightningd-2: 2022-01-24T03:34:22.933Z DEBUG 035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d-channeld-chan#2: peer_in WIRE_WARNING lightningd-2: 2022-01-24T03:34:22.941Z DEBUG 035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d-connectd: peer_out INVALID 4105 lightningd-2: 2022-01-24T03:34:22.949Z DEBUG 035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d-channeld-chan#2: billboard perm: Received warning channel 2c7cf1dc9dada7ed14f10c78ade8f0de907c1b70e736c12ff6f7472dc69c3db3: Peer sent unknown message 4105 (INVALID 4105) ``` Signed-off-by: Rusty Russell --- common/gossip_store.c | 1 + 1 file changed, 1 insertion(+) diff --git a/common/gossip_store.c b/common/gossip_store.c index e730d4220c59..686b1f1773a7 100644 --- a/common/gossip_store.c +++ b/common/gossip_store.c @@ -99,6 +99,7 @@ u8 *gossip_store_next(const tal_t *ctx, /* end can go backwards in this case! */ if (type == WIRE_GOSSIP_STORE_ENDED) { *off = *end = reopen_gossip_store(gossip_store_fd, msg); + msg = tal_free(msg); /* Ignore gossipd internal messages. */ } else if (type != WIRE_CHANNEL_ANNOUNCEMENT && type != WIRE_CHANNEL_UPDATE From c77f6ed051bbdb5b76558cb4cffb6edbcf0db6ed Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:06 +1030 Subject: [PATCH 26/34] pytest: remove flake in test_upgrade_statickey_onchaind We were relying on the fee update to create an additional tx. That's ugly; do an actual payment and make sure we definitely complete a new tx by waiting for that *then* both revoke_and_ack. (Without this, we could get a unilateral close instead of a penalty). Signed-off-by: Rusty Russell --- tests/test_connection.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_connection.py b/tests/test_connection.py index 3280ab27c693..a248f73da5aa 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -3521,8 +3521,21 @@ def test_upgrade_statickey_onchaind(node_factory, executor, bitcoind): l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.daemon.wait_for_log('option_static_remotekey enabled at 1/1') + # Make sure another commitment happens, sending failed payment. + routestep = { + 'msatoshi': 1, + 'id': l2.info['id'], + 'delay': 5, + 'channel': '1x1x1' # note: can be bogus for 1-hop direct payments + } + l1.rpc.sendpay([routestep], '00' * 32, payment_secret='00' * 32) + with pytest.raises(RpcError, match=r'WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS'): + l1.rpc.waitsendpay('00' * 32) + # Make sure l2 gets REVOKE_AND_ACK from previous. + l2.daemon.wait_for_log('peer_in WIRE_UPDATE_ADD_HTLC') l2.daemon.wait_for_log('peer_out WIRE_REVOKE_AND_ACK') + l2.daemon.wait_for_log('peer_in WIRE_REVOKE_AND_ACK') # Pre-statickey penalty works. bitcoind.rpc.sendrawtransaction(tx) From e2e6fb4e29b9b8797a33ab8f2a570f7939aca08b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Jan 2022 14:03:06 +1030 Subject: [PATCH 27/34] pytest: make test_gossip_no_empty_announcements more robust. Don't assume gossip send order: explicitly disconnect and reconnect. Signed-off-by: Rusty Russell --- tests/test_gossip.py | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 9224375954b6..6a17319c0997 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -596,32 +596,47 @@ def test_routing_gossip_reconnect(node_factory): wait_for(lambda: len(n.rpc.listchannels()['channels']) == 4) -@pytest.mark.developer("needs DEVELOPER=1") -def test_gossip_no_empty_announcements(node_factory, bitcoind): +@pytest.mark.developer("needs fast gossip, dev-no-reconnect") +def test_gossip_no_empty_announcements(node_factory, bitcoind, chainparams): # Need full IO logging so we can see gossip - # 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'}, - # Writes to l4 first, then l2 - {'disconnect': ['+WIRE_CHANNEL_ANNOUNCEMENT*2'], + # l2 sends CHANNEL_ANNOUNCEMENT to l1, but not CHANNEL_UDPATE. + l1, l2, l3, l4 = node_factory.line_graph(4, opts=[{'log-level': 'io', + 'dev-no-reconnect': None}, + {'log-level': 'io', + 'disconnect': ['+WIRE_CHANNEL_ANNOUNCEMENT'], 'may_reconnect': True}, + {'may_reconnect': True}, {'may_reconnect': True}], fundchannel=False) - # Make an announced-but-not-updated channel. l3.fundchannel(l4, 10**5) bitcoind.generate_block(5) - # 0x0100 = channel_announcement, which goes to l2 before l3 dies. - l2.daemon.wait_for_log(r'\[IN\] 0100') + # l2 sends CHANNEL_ANNOUNCEMENT to l1, then disconnects/ + l2.daemon.wait_for_log('dev_disconnect') + l1.daemon.wait_for_log(r'\[IN\] 0100') - # But it never goes to l1, as there's no channel_update. + # l1 won't relay it (make sure it has time to digest though) time.sleep(2) - assert not l1.daemon.is_in_log(r'\[IN\] 0100') - assert len(l1.rpc.listchannels()['channels']) == 0 + assert l1.rpc.listchannels()['channels'] == [] + encoded = subprocess.run(['devtools/mkencoded', '--scids', '00'], + check=True, + timeout=TIMEOUT, + stdout=subprocess.PIPE).stdout.strip().decode() + assert l1.query_gossip('query_channel_range', + chainparams['chain_hash'], + 0, 1000000, + filters=['0109', '0012']) == ['0108' + # blockhash + + chainparams['chain_hash'] + # first_blocknum, number_of_blocks, complete + + format(0, '08x') + format(1000000, '08x') + '01' + # encoded_short_ids + + format(len(encoded) // 2, '04x') + + encoded] # If we reconnect, gossip will now flow. - l3.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2) From 1c95e02e42bcd1f69977ecd44b6d8585d7d5f8be Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 30 Jan 2022 14:07:23 +1030 Subject: [PATCH 28/34] pytest: protect against bad gossip messages from mining confirms too fast. If we fund a channel between two nodes, then mine all the blocks to announce it, any other nodes may see the announcement before the blocks, causing CI to complain about "bad gossip": ``` lightningd-4: 2022-01-25T22:33:25.468Z DEBUG 032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e-gossipd: Ignoring future channel_announcment for 113x1x1 (current block 112) lightningd-4: 2022-01-25T22:33:25.468Z DEBUG 032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e-gossipd: Bad gossip order: WIRE_CHANNEL_UPDATE before announcement 113x1x1/0 lightningd-4: 2022-01-25T22:33:25.468Z DEBUG 032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e-gossipd: Bad gossip order: WIRE_CHANNEL_UPDATE before announcement 113x1x1/1 lightningd-4: 2022-01-25T22:33:25.468Z DEBUG 032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e-gossipd: Bad gossip order: WIRE_NODE_ANNOUNCEMENT before announcement 032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e ``` Add a new helper for this case, and use it where there are more than 2 nodes. Cleans up test_routing_gossip and a few other places which did this manually. Signed-off-by: Rusty Russell --- contrib/pyln-testing/pyln/testing/utils.py | 11 ++++ tests/test_closing.py | 11 ++-- tests/test_connection.py | 12 ++-- tests/test_gossip.py | 65 +++++++++------------- tests/test_invoices.py | 6 +- tests/test_misc.py | 4 +- tests/test_pay.py | 39 ++++++------- tests/test_plugin.py | 9 ++- tests/utils.py | 2 +- 9 files changed, 77 insertions(+), 82 deletions(-) diff --git a/contrib/pyln-testing/pyln/testing/utils.py b/contrib/pyln-testing/pyln/testing/utils.py index a726e58439e0..f5117e81c6a2 100644 --- a/contrib/pyln-testing/pyln/testing/utils.py +++ b/contrib/pyln-testing/pyln/testing/utils.py @@ -118,6 +118,17 @@ def sync_blockheight(bitcoind, nodes): wait_for(lambda: n.rpc.getinfo()['blockheight'] == height) +def mine_funding_to_announce(bitcoind, nodes, num_blocks=5, wait_for_mempool=0): + """Mine blocks so a channel can be announced (5, if it's already +mined), but make sure we don't leave nodes behind who will reject the +announcement. Not needed if there are only two nodes. + + """ + bitcoind.generate_block(num_blocks - 1, wait_for_mempool) + sync_blockheight(bitcoind, nodes) + bitcoind.generate_block(1) + + def wait_channel_quiescent(n1, n2): wait_for(lambda: only_one(only_one(n1.rpc.listpeers(n2.info['id'])['peers'])['channels'])['htlcs'] == []) wait_for(lambda: only_one(only_one(n2.rpc.listpeers(n1.info['id'])['peers'])['channels'])['htlcs'] == []) diff --git a/tests/test_closing.py b/tests/test_closing.py index f5993a7b28b0..8ade7d63d5d8 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -8,7 +8,7 @@ account_balance, first_channel_id, closing_fee, TEST_NETWORK, scriptpubkey_addr, calc_lease_fee, EXPERIMENTAL_FEATURES, check_utxos_channel, anchor_expected, check_coin_moves, - check_balance_snaps + check_balance_snaps, mine_funding_to_announce ) import os @@ -281,7 +281,7 @@ def test_closing_different_fees(node_factory, bitcoind, executor): # Technically, this is async to fundchannel returning. l1.daemon.wait_for_log('sendrawtx exit 0') - bitcoind.generate_block(6) + mine_funding_to_announce(bitcoind, peers, num_blocks=6) # Now wait for them all to hit normal state, do payments l1.daemon.wait_for_logs(['update for channel .* now ACTIVE'] * num_peers @@ -349,7 +349,8 @@ def test_closing_specified_destination(node_factory, bitcoind, chainparams): l1.pay(l3, 100000000) l1.pay(l4, 100000000) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) + addr = chainparams['example_addr'] l1.rpc.close(chan12, None, addr) l1.rpc.call('close', {'id': chan13, 'destination': addr}) @@ -2156,7 +2157,7 @@ def test_onchain_middleman_simple(node_factory, bitcoind): channel_id = first_channel_id(l1, l2) # Make sure routes finalized. - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) l1.wait_channel_active(c23) # Give l1 some money to play with. @@ -2276,7 +2277,7 @@ def test_onchain_middleman_their_unilateral_in(node_factory, bitcoind): channel_id = first_channel_id(l1, l2) # Make sure routes finalized. - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) l1.wait_channel_active(c23) # Make sure l3 sees gossip for channel now; it can get upset diff --git a/tests/test_connection.py b/tests/test_connection.py index a248f73da5aa..669b840c6181 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -11,7 +11,7 @@ expected_channel_features, check_coin_moves, first_channel_id, account_balance, basic_fee, scriptpubkey_addr, - EXPERIMENTAL_FEATURES + EXPERIMENTAL_FEATURES, mine_funding_to_announce ) from pyln.testing.utils import SLOW_MACHINE, VALGRIND, EXPERIMENTAL_DUAL_FUND, FUNDAMOUNT @@ -2556,7 +2556,7 @@ def test_disconnectpeer(node_factory, bitcoind): # Fund channel l1 -> l3 l1.fundchannel(l3, 10**6) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # disconnecting a non gossiping peer results in error with pytest.raises(RpcError, match=r'Peer is in state CHANNELD_NORMAL'): @@ -2945,11 +2945,9 @@ def test_restart_many_payments(node_factory, bitcoind): # OK to use change from previous fundings l1.rpc.fundchannel(n.info['id'], 10**6, minconf=0) - # Now mine them, get scids; make sure they all see the first block - # otherwise they may complain about channel_announcement from the future. - bitcoind.generate_block(1, wait_for_mempool=num * 2) - sync_blockheight(bitcoind, [l1] + nodes) - bitcoind.generate_block(5) + # Now mine them, get scids + mine_funding_to_announce(bitcoind, [l1] + nodes, + num_blocks=6, wait_for_mempool=num * 2) wait_for(lambda: [only_one(n.rpc.listpeers()['peers'])['channels'][0]['state'] for n in nodes] == ['CHANNELD_NORMAL'] * len(nodes)) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index 6a17319c0997..142bb9dd1809 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -5,7 +5,8 @@ from pyln.client import RpcError, Millisatoshi from utils import ( DEVELOPER, wait_for, TIMEOUT, only_one, sync_blockheight, - expected_node_features, COMPAT, EXPERIMENTAL_FEATURES + expected_node_features, COMPAT, EXPERIMENTAL_FEATURES, + mine_funding_to_announce ) import json @@ -37,7 +38,7 @@ def test_gossip_pruning(node_factory, bitcoind): scid1, _ = l1.fundchannel(l2, 10**6) scid2, _ = l2.fundchannel(l3, 10**6) - bitcoind.generate_block(6) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Channels should be activated locally wait_for(lambda: [c['active'] for c in l1.rpc.listchannels()['channels']] == [True] * 4) @@ -201,7 +202,7 @@ def test_announce_and_connect_via_dns(node_factory, bitcoind): l3.rpc.connect(l2.info['id'], 'localhost', l2.port) l4.rpc.connect(l2.info['id'], 'localhost', l2.port) scid, _ = l1.fundchannel(l2, 10**6) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # wait until l3 and l4 see l1 via gossip with announced addresses wait_for(lambda: len(l3.rpc.listnodes(l1.info['id'])['nodes']) == 1) @@ -252,7 +253,7 @@ def test_gossip_timestamp_filter(node_factory, bitcoind, chainparams): # Make a public channel. chan12, _ = l1.fundchannel(l2, 10**5) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) l3.wait_for_channel_updates([chan12]) after_12 = int(time.time()) @@ -334,7 +335,7 @@ def test_connect_by_gossip(node_factory, bitcoind): # Nodes are gossiped only if they have channels chanid, _ = l2.fundchannel(l3, 10**6) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Let channel reach announcement depth l2.wait_channel_active(chanid) @@ -442,7 +443,7 @@ def test_gossip_jsonrpc(node_factory): @pytest.mark.developer("Too slow without --dev-fast-gossip") -def test_gossip_badsig(node_factory): +def test_gossip_badsig(node_factory, bitcoind): """Make sure node announcement signatures are ok. This is a smoke test to see if signatures fail. This used to be the case @@ -460,7 +461,7 @@ def test_gossip_badsig(node_factory): l2.fundchannel(l3, 10**6) # Wait for route propagation. - l1.bitcoin.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) l1.daemon.wait_for_log('Received node_announcement for node {}' .format(l3.info['id'])) assert not l1.daemon.is_in_log('signature verification failed') @@ -517,7 +518,7 @@ def test_gossip_persistence(node_factory, bitcoind): scid23, _ = l2.fundchannel(l3, 10**6) # Make channels public, except for l3 -> l4, which is kept local-only for now - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) scid34, _ = l3.fundchannel(l4, 10**6) bitcoind.generate_block(1) @@ -610,7 +611,7 @@ def test_gossip_no_empty_announcements(node_factory, bitcoind, chainparams): fundchannel=False) l3.fundchannel(l4, 10**5) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) # l2 sends CHANNEL_ANNOUNCEMENT to l1, then disconnects/ l2.daemon.wait_for_log('dev_disconnect') @@ -644,20 +645,16 @@ def test_gossip_no_empty_announcements(node_factory, bitcoind, chainparams): def test_routing_gossip(node_factory, bitcoind): nodes = node_factory.get_nodes(5) - sync_blockheight(bitcoind, nodes) for i in range(len(nodes) - 1): src, dst = nodes[i], nodes[i + 1] src.rpc.connect(dst.info['id'], 'localhost', dst.port) src.openchannel(dst, 25000, confirm=False, wait_for_announce=False) - sync_blockheight(bitcoind, nodes) - # Avoid "bad gossip" caused by future announcements (a node below - # confirmation height receiving and ignoring the announcement, - # thus marking followup messages as bad). - sync_blockheight(bitcoind, nodes) + # openchannel calls fundwallet which mines a block; so first channel + # is 4 deep, last is unconfirmed. # Allow announce messages. - bitcoind.generate_block(6) + mine_funding_to_announce(bitcoind, nodes, num_blocks=6, wait_for_mempool=1) # Deep check that all channels are in there comb = [] @@ -691,17 +688,15 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): l2.fundwallet(10**6) num_tx = len(bitcoind.rpc.getrawmempool()) + # We want these one block apart. l1.rpc.fundchannel(l2.info['id'], 10**5)['tx'] - wait_for(lambda: len(bitcoind.rpc.getrawmempool()) == num_tx + 1) - bitcoind.generate_block(1) - - num_tx = len(bitcoind.rpc.getrawmempool()) + bitcoind.generate_block(wait_for_mempool=num_tx + 1) + sync_blockheight(bitcoind, [l1, l2, l3, l4]) l2.rpc.fundchannel(l3.info['id'], 10**5)['tx'] - wait_for(lambda: len(bitcoind.rpc.getrawmempool()) == num_tx + 1) - bitcoind.generate_block(1) - # Get them both to gossip depth. - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4], + num_blocks=6, + wait_for_mempool=1) # Make sure l2 has received all the gossip. l2.daemon.wait_for_logs(['Received node_announcement for node ' + l1.info['id'], @@ -874,7 +869,7 @@ def test_gossip_query_channel_range(node_factory, bitcoind, chainparams): # This should actually be large enough for zlib to kick in! scid34, _ = l3.fundchannel(l4, 10**5) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) l2.daemon.wait_for_log('Received node_announcement for node ' + l4.info['id']) # Restore infinite encode size. @@ -924,12 +919,6 @@ def test_report_routing_failure(node_factory, bitcoind): # Finally the only possible path is # l1-l2-l3-l4. - def fund_from_to_payer(lsrc, ldst, lpayer): - lsrc.rpc.connect(ldst.info['id'], 'localhost', ldst.port) - c, _ = lsrc.fundchannel(ldst, 10000000) - bitcoind.generate_block(5) - lpayer.wait_for_channel_updates([c]) - # Setup # Construct lightningd l1, l2, l3, l4 = node_factory.get_nodes(4) @@ -946,7 +935,7 @@ def fund_from_to_payer(lsrc, ldst, lpayer): dst.daemon.lightning_dir)) c, _ = src.fundchannel(dst, 10**6) channels.append(c) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) for c in channels: l1.wait_channel_active(c) @@ -982,7 +971,7 @@ def test_query_short_channel_id(node_factory, bitcoind, chainparams): # Make channels public. scid12, _ = l1.fundchannel(l2, 10**5) scid23, _ = l2.fundchannel(l3, 10**5) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # It will know about everything. l1.daemon.wait_for_log('Received node_announcement for node {}'.format(l3.info['id'])) @@ -1369,7 +1358,7 @@ def test_gossip_notices_close(node_factory, bitcoind): node_factory.join_nodes([l2, l3]) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Make sure l1 learns about channel and nodes. wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2) @@ -1468,7 +1457,7 @@ def test_getroute_exclude(node_factory, bitcoind): # Now, create an alternate (better) route. l2.rpc.connect(l4.info['id'], 'localhost', l4.port) scid, _ = l2.fundchannel(l4, 1000000, wait_for_active=False) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5]) # We don't wait above, because we care about it hitting l1. l1.daemon.wait_for_logs([r'update for channel {}/0 now ACTIVE' @@ -1505,7 +1494,7 @@ def test_getroute_exclude(node_factory, bitcoind): scid15, _ = l1.fundchannel(l5, 1000000, wait_for_active=False) l5.rpc.connect(l4.info['id'], 'localhost', l4.port) scid54, _ = l5.fundchannel(l4, 1000000, wait_for_active=False) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5]) # We don't wait above, because we care about it hitting l1. l1.daemon.wait_for_logs([r'update for channel {}/0 now ACTIVE' @@ -1589,7 +1578,7 @@ def setup_gossip_store_test(node_factory, bitcoind): scid23, _ = l2.fundchannel(l3, 10**6) # Have that channel announced. - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Make sure we've got node_announcements wait_for(lambda: ['alias' in n for n in l2.rpc.listnodes()['nodes']] == [True, True]) @@ -2115,7 +2104,7 @@ def test_topology_leak(node_factory, bitcoind): l1, l2, l3 = node_factory.line_graph(3) l1.rpc.listchannels() - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Wait until l1 sees all the channels. wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 4) diff --git a/tests/test_invoices.py b/tests/test_invoices.py index 386f5a99e533..d31fade615b0 100644 --- a/tests/test_invoices.py +++ b/tests/test_invoices.py @@ -1,7 +1,7 @@ from fixtures import * # noqa: F401,F403 from fixtures import TEST_NETWORK from pyln.client import RpcError, Millisatoshi -from utils import only_one, wait_for, wait_channel_quiescent +from utils import only_one, wait_for, wait_channel_quiescent, mine_funding_to_announce import pytest @@ -221,7 +221,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind): l0 = node_factory.get_node() l0.rpc.connect(l1.info['id'], 'localhost', l1.port) scid_dummy, _ = l0.fundchannel(l1, 2 * (10**5)) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l0, l1, l2, l3]) # Make sure channel is totally public. wait_for(lambda: [c['public'] for c in l2.rpc.listchannels(scid_dummy)['channels']] == [True, True]) @@ -285,7 +285,7 @@ def test_invoice_routeboost_private(node_factory, bitcoind): # the exposure of private channels. l3.rpc.connect(l2.info['id'], 'localhost', l2.port) scid2, _ = l3.fundchannel(l2, (10**5)) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l0, l1, l2, l3]) # Make sure channel is totally public. wait_for(lambda: [c['public'] for c in l2.rpc.listchannels(scid2)['channels']] == [True, True]) diff --git a/tests/test_misc.py b/tests/test_misc.py index 57bc7149a346..6af6ac7cbf07 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -7,7 +7,7 @@ from threading import Event from pyln.testing.utils import ( DEVELOPER, TIMEOUT, VALGRIND, DEPRECATED_APIS, sync_blockheight, only_one, - wait_for, TailableProc, env + wait_for, TailableProc, env, mine_funding_to_announce ) from utils import ( account_balance, scriptpubkey_addr @@ -2281,7 +2281,7 @@ def test_listforwards(node_factory, bitcoind): c24, _ = l2.fundchannel(l4, 10**5) # Wait until channels are active - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) l1.wait_channel_active(c23) # successful payments diff --git a/tests/test_pay.py b/tests/test_pay.py index a5a68b4ae954..50eb721f857a 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -8,7 +8,7 @@ from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND, FUNDAMOUNT from utils import ( DEVELOPER, wait_for, only_one, sync_blockheight, TIMEOUT, - EXPERIMENTAL_FEATURES, env, VALGRIND + EXPERIMENTAL_FEATURES, env, VALGRIND, mine_funding_to_announce ) import copy import os @@ -182,7 +182,7 @@ def test_pay_exclude_node(node_factory, bitcoind): scid14, _ = l1.fundchannel(l4, 10**6, wait_for_active=False) scid45, _ = l4.fundchannel(l5, 10**6, wait_for_active=False) scid53, _ = l5.fundchannel(l3, 10**6, wait_for_active=False) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5]) l1.daemon.wait_for_logs([r'update for channel {}/0 now ACTIVE' .format(scid14), @@ -1137,7 +1137,7 @@ def test_forward_different_fees_and_cltv(node_factory, bitcoind): c1, _ = l1.fundchannel(l2, 10**6) c2, _ = l2.fundchannel(l3, 10**6) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Make sure l1 has seen announce for all channels. l1.wait_channel_active(c1) @@ -1244,7 +1244,7 @@ def test_forward_pad_fees_and_cltv(node_factory, bitcoind): c1, _ = l1.fundchannel(l2, 10**6) c2, _ = l2.fundchannel(l3, 10**6) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Make sure l1 has seen announce for all channels. l1.wait_channel_active(c1) @@ -1290,9 +1290,7 @@ def test_forward_stats(node_factory, bitcoind): l2.openchannel(l4, 10**6, wait_for_announce=False) l2.openchannel(l5, 10**6, wait_for_announce=False) - bitcoind.generate_block(1) - sync_blockheight(bitcoind, [l1, l2, l3, l4, l5]) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5]) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 8) @@ -1419,7 +1417,7 @@ def test_forward_local_failed_stats(node_factory, bitcoind, executor): l6.fundchannel(l1, 10**6) # Make sure routes finalized. - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5, l6]) l1.wait_channel_active(c23) l1.wait_channel_active(c24) l1.wait_channel_active(c25) @@ -1702,7 +1700,7 @@ def exhaust_channel(opener, peer, scid, already_spent=0): scid35, _ = l3.fundchannel(l5, 10**6, wait_for_active=False) # Make sure l1 sees all 7 channels - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5]) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 14) # Exhaust shortcut channels one at a time, to force retries. @@ -1763,7 +1761,7 @@ def test_pay_routeboost(node_factory, bitcoind, compat): scidl2l3, _ = l2.fundchannel(l3, 10**6) # Make sure l1 knows about the 2->3 channel. - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5]) l1.daemon.wait_for_logs([r'update for channel {}/0 now ACTIVE' .format(scidl2l3), r'update for channel {}/1 now ACTIVE' @@ -2030,8 +2028,7 @@ def test_setchannelfee_state(node_factory, bitcoind): # cid = result['channels'][0]['channel_id'] # test routing correct new fees once routing is established - bitcoind.generate_block(6) - sync_blockheight(bitcoind, [l0, l1, l2]) + mine_funding_to_announce(bitcoind, [l0, l1, l2]) l0.wait_for_route(l2) inv = l2.rpc.invoice(100000, 'test_setchannelfee_state', 'desc')['bolt11'] @@ -2595,7 +2592,7 @@ def test_tlv_or_legacy(node_factory, bitcoind): l3.daemon.wait_for_log("Got onion.*'type': 'tlv'") # We need 5 more blocks to announce l1->l2 channel. - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Make sure l1 knows about l2 wait_for(lambda: 'alias' in l1.rpc.listnodes(l2.info['id'])['nodes'][0]) @@ -2828,7 +2825,7 @@ def test_partial_payment(node_factory, bitcoind, executor): scid24, _ = l2.fundchannel(l4, 100000) l3.rpc.connect(l4.info['id'], 'localhost', l4.port) scid34, _ = l3.fundchannel(l4, 100000) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) # Wait until l1 knows about all channels. wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 8) @@ -3633,7 +3630,7 @@ def test_mpp_adaptive(node_factory, bitcoind): assert(c12['spendable_msat'].millisatoshis < amt) assert(c34['spendable_msat'].millisatoshis < amt) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 8) inv = l4.rpc.invoice( @@ -3728,8 +3725,7 @@ def test_mpp_presplit_routehint_conflict(node_factory, bitcoind): l2.rpc.connect(l3.info['id'], 'localhost', l3.port) l2.fundchannel(l3, 10**7, announce_channel=False) - bitcoind.generate_block(6) - sync_blockheight(bitcoind, [l1, l2, l3]) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Wait for l3 to learn about l1->l2, otherwise it will think # l2 is a deadend and not add it to the routehint. @@ -3894,8 +3890,7 @@ def test_mpp_waitblockheight_routehint_conflict(node_factory, bitcoind, executor l2.rpc.connect(l3.info['id'], 'localhost', l3.port) l2.fundchannel(l3, 10**7, announce_channel=False) - bitcoind.generate_block(6) - sync_blockheight(bitcoind, [l1, l2, l3]) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) # Wait for l3 to learn about l1->l2, otherwise it will think # l2 is a deadend and not add it to the routehint. @@ -4017,8 +4012,7 @@ def test_mpp_interference_2(node_factory, bitcoind, executor): l3.fundchannel(l6, int((unit * 6).to_satoshi()), announce_channel=False) # Now wait for the buyers to learn the entire public network. - bitcoind.generate_block(5) - sync_blockheight(bitcoind, [l1, l2, l3, l4, l5, l6, l7]) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5, l6, l7]) for channel in public_network: wait_for(lambda: len(l2.rpc.listchannels(channel)['channels']) == 2) wait_for(lambda: len(l3.rpc.listchannels(channel)['channels']) == 2) @@ -4120,8 +4114,7 @@ def test_mpp_overload_payee(node_factory, bitcoind): l5.fundbalancedchannel(l6, amt)] # Ensure l1 knows the entire public network. - bitcoind.generate_block(5) - sync_blockheight(bitcoind, [l1, l2, l3, l4, l5, l6]) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4, l5, l6]) for c in public_network: wait_for(lambda: len(l1.rpc.listchannels(c)['channels']) >= 2) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 2889b820030f..cec3b8ec369a 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -9,7 +9,8 @@ DEVELOPER, only_one, sync_blockheight, TIMEOUT, wait_for, TEST_NETWORK, DEPRECATED_APIS, expected_peer_features, expected_node_features, expected_channel_features, account_balance, - check_coin_moves, first_channel_id, EXPERIMENTAL_DUAL_FUND + check_coin_moves, first_channel_id, EXPERIMENTAL_DUAL_FUND, + mine_funding_to_announce ) import ast @@ -1723,7 +1724,9 @@ def test_hook_crash(node_factory, executor, bitcoind): n.rpc.plugin_start(p) l1.openchannel(n, 10**6, confirm=False, wait_for_announce=False) - bitcoind.generate_block(6) + # Mine final openchannel tx first. + sync_blockheight(bitcoind, [l1] + nodes) + mine_funding_to_announce(bitcoind, [l1] + nodes, wait_for_mempool=1) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2 * len(perm)) @@ -1918,7 +1921,7 @@ def test_coin_movement_notices(node_factory, bitcoind, chainparams): {'may_reconnect': True, 'plugin': coin_plugin}, ], wait_for_announce=True) - bitcoind.generate_block(5) + mine_funding_to_announce(bitcoind, [l1, l2, l3]) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 4) amount = 10**8 diff --git a/tests/utils.py b/tests/utils.py index d10fdada3b4c..c239d7152bd0 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,5 +1,5 @@ from pyln.testing.utils import TEST_NETWORK, TIMEOUT, VALGRIND, DEVELOPER, DEPRECATED_APIS # noqa: F401 -from pyln.testing.utils import env, only_one, wait_for, write_config, TailableProc, sync_blockheight, wait_channel_quiescent, get_tx_p2wsh_outnum # noqa: F401 +from pyln.testing.utils import env, only_one, wait_for, write_config, TailableProc, sync_blockheight, wait_channel_quiescent, get_tx_p2wsh_outnum, mine_funding_to_announce # noqa: F401 import bitstring from pyln.client import Millisatoshi from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND From 63f934464855d42e8d6ba3d18a0068cae730e0d0 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 30 Jan 2022 14:07:30 +1030 Subject: [PATCH 29/34] gossipd: fix longstanding logic error in gossip_generation. `hc` is never NULL, since it's `hc = &chan->half[direction];`; we really meant "is it initialized", and valgrind under CI finally caught it: ``` ==69243== Conditional jump or move depends on uninitialised value(s) ==69243== at 0x11C595: handle_local_channel_update (gossip_generation.c:758) ==69243== by 0x115254: recv_req (gossipd.c:986) ==69243== by 0x128F8D: handle_read (daemon_conn.c:31) ==69243== by 0x16BEE1: next_plan (io.c:59) ==69243== by 0x16CAE9: do_plan (io.c:407) ==69243== by 0x16CB2B: io_ready (io.c:417) ==69243== by 0x16EE1E: io_loop (poll.c:453) ==69243== by 0x1154DA: main (gossipd.c:1089) ==69243== ``` Signed-off-by: Rusty Russell --- gossipd/gossip_generation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index faf01bb7254f..70b8f854b15f 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -751,7 +751,7 @@ void handle_local_channel_update(struct daemon *daemon, const u8 *msg) return; /* Too early? Defer (don't worry if it's unannounced). */ - if (hc && is_chan_public(chan)) { + if (is_halfchan_defined(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); From dfb78ebb3224c9a36ff57dedc9e600b8d500b130 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 30 Jan 2022 14:07:30 +1030 Subject: [PATCH 30/34] lightningd: clean up subds before freeing HTLCs. Otherwise we get weird effects, as htlcs are being freed: ``` 2022-01-26T05:07:37.8774610Z lightningd-1: 2022-01-26T04:47:48.770Z DEBUG 030eeb52087b9dbb27b7aec79ca5249369f6ce7b20a5684ce38d9f4595a21c2fda-chan#8: Failing HTLC 18446744073709551615 due to peer death 2022-01-26T05:07:37.8775287Z lightningd-1: 2022-01-26T04:47:48.770Z **BROKEN** 030eeb52087b9dbb27b7aec79ca5249369f6ce7b20a5684ce38d9f4595a21c2fda-chan#8: Neither origin nor in? ``` Signed-off-by: Rusty Russell --- lightningd/lightningd.c | 5 +++++ lightningd/onchain_control.c | 7 ++++++- lightningd/opening_common.c | 12 ++++++++---- lightningd/subd.c | 14 ++++++++++++++ lightningd/subd.h | 9 +++++++++ 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index cedc20e77d8d..113abcdb6ecb 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -529,6 +529,11 @@ static void shutdown_subdaemons(struct lightningd *ld) ld->gossip = subd_shutdown(ld->gossip, 10); ld->hsm = subd_shutdown(ld->hsm, 10); + /*~ Closing the hsmd means all other subdaemons should be exiting; + * deal with that cleanly before we start freeing internal + * structures. */ + subd_shutdown_remaining(ld); + /* Now we free all the HTLCs */ free_htlcs(ld, NULL); diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index d4f81de27165..85137528a7ef 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -567,10 +567,15 @@ static void onchain_error(struct channel *channel, bool warning UNUSED, const u8 *err_for_them UNUSED) { + channel_set_owner(channel, NULL); + + /* This happens on shutdown: fine */ + if (channel->peer->ld->state == LD_STATE_SHUTDOWN) + return; + /* FIXME: re-launch? */ log_broken(channel->log, "%s", desc); channel_set_billboard(channel, true, desc); - channel_set_owner(channel, NULL); } /* With a reorg, this can get called multiple times; each time we'll kill diff --git a/lightningd/opening_common.c b/lightningd/opening_common.c index 46087c13819e..d8d39c20816d 100644 --- a/lightningd/opening_common.c +++ b/lightningd/opening_common.c @@ -105,7 +105,9 @@ void uncommitted_channel_disconnect(struct uncommitted_channel *uc, { u8 *msg = towire_connectd_peer_disconnected(tmpctx, &uc->peer->id); log_(uc->log, level, NULL, false, "%s", desc); - subd_send_msg(uc->peer->ld->connectd, msg); + /* NULL when we're shutting down */ + if (uc->peer->ld->connectd) + subd_send_msg(uc->peer->ld->connectd, msg); if (uc->fc && uc->fc->cmd) was_pending(command_fail(uc->fc->cmd, LIGHTNINGD, "%s", desc)); notify_disconnect(uc->peer->ld, &uc->peer->id); @@ -191,9 +193,11 @@ void handle_reestablish(struct lightningd *ld, "Unknown channel for reestablish"); log_debug(ld->log, "Reestablish on UNKNOWN channel %s", type_to_string(tmpctx, struct channel_id, channel_id)); - subd_send_msg(ld->connectd, - take(towire_connectd_peer_final_msg(NULL, peer_id, - err))); + /* Unless we're shutting down */ + if (ld->connectd) + subd_send_msg(ld->connectd, + take(towire_connectd_peer_final_msg(NULL, peer_id, + err))); tal_free(peer_fd); } } diff --git a/lightningd/subd.c b/lightningd/subd.c index f563a32f1f79..633976191db4 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -895,6 +895,20 @@ struct subd *subd_shutdown(struct subd *sd, unsigned int seconds) return tal_free(sd); } +void subd_shutdown_remaining(struct lightningd *ld) +{ + struct subd *subd; + + /* We give them a second to finish exiting, before we kill + * them in destroy_subd() */ + sleep(1); + + while ((subd = list_top(&ld->subds, struct subd, list)) != NULL) { + /* Destructor removes from list */ + io_close(subd->conn); + } +} + void subd_release_channel(struct subd *owner, const void *channel) { /* If owner is a per-peer-daemon, and not already freeing itself... */ diff --git a/lightningd/subd.h b/lightningd/subd.h index 564b2f35ff86..d721b14a1440 100644 --- a/lightningd/subd.h +++ b/lightningd/subd.h @@ -222,6 +222,15 @@ void subd_release_channel(struct subd *owner, const void *channel); */ struct subd *subd_shutdown(struct subd *subd, unsigned int seconds); +/** + * subd_shutdown_remaining - kill all remaining (per-peer) subds + * @ld: lightningd + * + * They should already be exiting (since we shutdown hsmd), but + * make sure they have. + */ +void subd_shutdown_remaining(struct lightningd *ld); + /* Ugly helper to get full pathname of the current binary. */ const char *find_my_abspath(const tal_t *ctx, const char *argv0); From 93f8a11bf60ad9809ced69c9be0ae7ccf922b2eb Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 30 Jan 2022 14:07:30 +1030 Subject: [PATCH 31/34] dual_funding: don't steal inflight field in update_channel_from_inflight. If we call update_channel_from_inflight *twice* with the same inflight, we will get bad results. Using tal_steal() here was a premature optimization: ``` Valgrind error file: valgrind-errors.496395 ==496395== Invalid read of size 8 ==496395== at 0x22A9D3: to_tal_hdr (tal.c:174) ==496395== by 0x22B4B5: tal_steal_ (tal.c:498) ==496395== by 0x16A13D: update_channel_from_inflight (peer_control.c:1225) ==496395== by 0x16A4C7: funding_depth_cb (peer_control.c:1299) ==496395== by 0x182807: txw_fire (watch.c:232) ==496395== by 0x182AA9: watch_topology_changed (watch.c:300) ==496395== by 0x1290ED: updates_complete (chaintopology.c:624) ==496395== by 0x129BF4: get_new_block (chaintopology.c:835) ==496395== by 0x125EEF: getrawblockbyheight_callback (bitcoind.c:362) ==496395== by 0x176ECC: plugin_response_handle (plugin.c:584) ==496395== by 0x1770F5: plugin_read_json_one (plugin.c:690) ==496395== by 0x1772D9: plugin_read_json (plugin.c:735) ==496395== Address 0x89fbb08 is 24 bytes inside a block of size 104 free'd ==496395== at 0x483CA3F: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==496395== by 0x22B193: del_tree (tal.c:421) ==496395== by 0x22B461: tal_free (tal.c:486) ==496395== by 0x16A123: update_channel_from_inflight (peer_control.c:1223) ==496395== by 0x16A4C7: funding_depth_cb (peer_control.c:1299) ==496395== by 0x182807: txw_fire (watch.c:232) ==496395== by 0x182AA9: watch_topology_changed (watch.c:300) ==496395== by 0x1290ED: updates_complete (chaintopology.c:624) ==496395== by 0x129BF4: get_new_block (chaintopology.c:835) ==496395== by 0x125EEF: getrawblockbyheight_callback (bitcoind.c:362) ==496395== by 0x176ECC: plugin_response_handle (plugin.c:584) ==496395== by 0x1770F5: plugin_read_json_one (plugin.c:690) ==496395== Block was alloc'd at ==496395== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==496395== by 0x22AC1C: allocate (tal.c:250) ==496395== by 0x22B1DD: tal_alloc_ (tal.c:428) ==496395== by 0x22B3A6: tal_alloc_arr_ (tal.c:471) ==496395== by 0x22C094: tal_dup_ (tal.c:805) ==496395== by 0x12B274: new_inflight (channel.c:187) ==496395== by 0x136D4C: wallet_commit_channel (dual_open_control.c:1260) ==496395== by 0x13B084: handle_commit_received (dual_open_control.c:2839) ==496395== by 0x13B6AF: dual_opend_msg (dual_open_control.c:2976) ==496395== by 0x1809FF: sd_msg_read (subd.c:553) ==496395== by 0x218F5D: next_plan (io.c:59) ==496395== by 0x219B65: do_plan (io.c:407) ``` Signed-off-by: Rusty Russell --- lightningd/peer_control.c | 4 ++-- tests/test_closing.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 5d7627011ba4..fd22f10f6165 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1209,7 +1209,7 @@ static bool check_funding_tx(const struct bitcoin_tx *tx, static void update_channel_from_inflight(struct lightningd *ld, struct channel *channel, - struct channel_inflight *inflight) + const struct channel_inflight *inflight) { struct wally_psbt *psbt_copy; @@ -1222,7 +1222,7 @@ static void update_channel_from_inflight(struct lightningd *ld, channel->push = inflight->lease_fee; tal_free(channel->lease_commit_sig); channel->lease_commit_sig - = tal_steal(channel, inflight->lease_commit_sig); + = tal_dup_or_null(channel, secp256k1_ecdsa_signature, inflight->lease_commit_sig); channel->lease_chan_max_msat = inflight->lease_chan_max_msat; channel->lease_chan_max_ppt = inflight->lease_chan_max_ppt; diff --git a/tests/test_closing.py b/tests/test_closing.py index 8ade7d63d5d8..3123c10cb79b 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -810,7 +810,7 @@ def test_channel_lease_falls_behind(node_factory, bitcoind): compact_lease=rates['compact_lease']) # sink the funding transaction - bitcoind.generate_block(1) + bitcoind.generate_block(1, wait_for_mempool=1) # stop l1 l1.stop() From 333b0e836a3e20399eebb03a41b10b571b1142a2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 31 Jan 2022 13:09:07 +1030 Subject: [PATCH 32/34] pytest: make test_mpp_adaptive more reliable If the HTLCs are completely negotiated, we can get a channel break when we mine a pile of blocks. This is mainly seen with Postgres, due to the db speed. Signed-off-by: Rusty Russell --- tests/test_pay.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_pay.py b/tests/test_pay.py index 50eb721f857a..33910f28802a 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -3630,6 +3630,16 @@ def test_mpp_adaptive(node_factory, bitcoind): assert(c12['spendable_msat'].millisatoshis < amt) assert(c34['spendable_msat'].millisatoshis < amt) + # Make sure all HTLCs entirely resolved before we mine more blocks! + def all_htlcs(n): + htlcs = [] + for p in n.rpc.listpeers()['peers']: + for c in p['channels']: + htlcs += c['htlcs'] + return htlcs + + wait_for(lambda: all([all_htlcs(n) == [] for n in [l1, l2, l3, l4]])) + mine_funding_to_announce(bitcoind, [l1, l2, l3, l4]) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 8) From 7530018014128a24a42f816ab0676cb85f9e96c8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 31 Jan 2022 13:11:46 +1030 Subject: [PATCH 33/34] pytest: note unfixable test_htlc_rexmit_while_closing test. We really need our own lnprototest tests for packet-based stuff; these message-based tests are inherently delicate and awkward. In particular, connectd now does dev-disconnect, so the socket is not immediately closed after a dev-disconnect command. In this case, the WIRE_SHUTDOWN has often already been written from connectd to channeld. But it sometimes works, too. Signed-off-by: Rusty Russell --- tests/test_closing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_closing.py b/tests/test_closing.py index 3123c10cb79b..396c269df561 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -3438,6 +3438,7 @@ def test_closing_higherfee(node_factory, bitcoind, executor): @pytest.mark.developer("needs dev_disconnect") def test_htlc_rexmit_while_closing(node_factory, executor): """Retranmitting an HTLC revocation while shutting down should work""" + # FIXME: This should be in lnprototest! UNRELIABLE. # l1 disconnects after sending second COMMITMENT_SIGNED. # Then it stops receiving after sending WIRE_SHUTDOWN (which is before it # reads the revoke_and_ack). From 73e325ca1241ace1d532077198b458901ff1dc7f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 7 Feb 2022 14:02:32 +1030 Subject: [PATCH 34/34] misc: clarifications from cdecker review. Signed-off-by: Rusty Russell --- connectd/multiplex.h | 2 +- gossipd/gossip_generation.c | 6 ++++++ gossipd/gossipd.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/connectd/multiplex.h b/connectd/multiplex.h index 13c37e298221..1c87ccb59a35 100644 --- a/connectd/multiplex.h +++ b/connectd/multiplex.h @@ -22,7 +22,7 @@ void multiplex_final_msg(struct peer *peer, const u8 *final_msg TAKES); /* Inject a message into the output stream. Unlike a raw msg_enqueue, - * this does io logging if required. */ + * this does io logging. */ void inject_peer_msg(struct peer *peer, const u8 *msg TAKES); void setup_peer_gossip_store(struct peer *peer, diff --git a/gossipd/gossip_generation.c b/gossipd/gossip_generation.c index 70b8f854b15f..e7c9e8e01e42 100644 --- a/gossipd/gossip_generation.c +++ b/gossipd/gossip_generation.c @@ -821,6 +821,12 @@ void handle_used_local_channel_update(struct daemon *daemon, const u8 *msg) &scid)); return; } + + /* This whole idea is racy: they might have used a *previous* update. + * But that's OK: the notification is an optimization to avoid + * broadcasting updates we never use (route flapping). In this case, + * we might broadcast a more recent update than the one we sent to a + * peer. */ local_channel_update_latest(daemon, chan); } diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index 6113dc8cae87..4b607afb7f50 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -442,7 +442,7 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg) peer = find_peer(daemon, &id); if (!peer) { - status_broken("connectd sent gossip msg %s for unknown peer %s", + status_broken("connectd sent gossip msg %s from unknown peer %s", peer_wire_name(fromwire_peektype(msg)), type_to_string(tmpctx, struct node_id, &id)); return;