diff --git a/channeld/channeld.c b/channeld/channeld.c index eae8b46f5..4511b5aee 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -139,7 +139,6 @@ struct peer { /* If master told us to send wrong_funding */ struct bitcoin_outpoint *shutdown_wrong_funding; -#if EXPERIMENTAL_FEATURES /* Do we want quiescence? */ bool stfu; /* Which side is considered the initiator? */ @@ -148,7 +147,6 @@ struct peer { bool stfu_sent[NUM_SIDES]; /* Updates master asked, which we've deferred while quiescing */ struct msg_queue *update_queue; -#endif #if DEVELOPER /* If set, don't fire commit counter when this hits 0 */ @@ -227,7 +225,6 @@ const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES) return msg; } -#if EXPERIMENTAL_FEATURES static void maybe_send_stfu(struct peer *peer) { if (!peer->stfu) @@ -252,6 +249,12 @@ static void handle_stfu(struct peer *peer, const u8 *stfu) struct channel_id channel_id; u8 remote_initiated; + if (!feature_negotiated(peer->our_features, + peer->their_features, + OPT_QUIESCE)) + peer_failed_warn(peer->pps, &peer->channel_id, + "stfu not supported"); + if (!fromwire_stfu(stfu, &channel_id, &remote_initiated)) peer_failed_warn(peer->pps, &peer->channel_id, "Bad stfu %s", tal_hex(peer, stfu)); @@ -312,6 +315,7 @@ static bool handle_master_request_later(struct peer *peer, const u8 *msg) return false; } +#if EXPERIMENTAL_FEATURES /* Compare, with false if either is NULL */ static bool match_type(const u8 *t1, const u8 *t2) { @@ -341,16 +345,7 @@ static void set_channel_type(struct channel *channel, const u8 *type) wire_sync_write(MASTER_FD, take(towire_channeld_upgraded(NULL, channel->type))); } -#else /* !EXPERIMENTAL_FEATURES */ -static bool handle_master_request_later(struct peer *peer, const u8 *msg) -{ - return false; -} - -static void maybe_send_stfu(struct peer *peer) -{ -} -#endif +#endif /* EXPERIMENTAL_FEATURES */ /* Tell gossipd to create channel_update (then it goes into * gossip_store, then streams out to peers, or sends it directly if @@ -1144,11 +1139,10 @@ static bool want_fee_update(const struct peer *peer, u32 *target) if (peer->channel->opener != LOCAL) return false; -#if EXPERIMENTAL_FEATURES /* No fee update while quiescing! */ if (peer->stfu) return false; -#endif + current = channel_feerate(peer->channel, REMOTE); /* max is *approximate*: only take it into account if we're @@ -1184,11 +1178,10 @@ static bool want_blockheight_update(const struct peer *peer, u32 *height) if (peer->channel->lease_expiry == 0) return false; -#if EXPERIMENTAL_FEATURES /* No fee update while quiescing! */ if (peer->stfu) return false; -#endif + /* What's the current blockheight */ last = get_blockheight(peer->channel->blockheight_states, peer->channel->opener, LOCAL); @@ -2245,12 +2238,9 @@ static void peer_in(struct peer *peer, const u8 *msg) case WIRE_SHUTDOWN: handle_peer_shutdown(peer, msg); return; - -#if EXPERIMENTAL_FEATURES case WIRE_STFU: handle_stfu(peer, msg); return; -#endif case WIRE_INIT: case WIRE_OPEN_CHANNEL: case WIRE_ACCEPT_CHANNEL: @@ -3636,7 +3626,6 @@ static void handle_dev_memleak(struct peer *peer, const u8 *msg) found_leak))); } -#if EXPERIMENTAL_FEATURES static void handle_dev_quiesce(struct peer *peer, const u8 *msg) { if (!fromwire_channeld_dev_quiesce(msg)) @@ -3650,7 +3639,6 @@ static void handle_dev_quiesce(struct peer *peer, const u8 *msg) peer->stfu_initiator = LOCAL; maybe_send_stfu(peer); } -#endif /* EXPERIMENTAL_FEATURES */ #endif /* DEVELOPER */ static void req_in(struct peer *peer, const u8 *msg) @@ -3708,10 +3696,8 @@ static void req_in(struct peer *peer, const u8 *msg) handle_dev_memleak(peer, msg); return; case WIRE_CHANNELD_DEV_QUIESCE: -#if EXPERIMENTAL_FEATURES handle_dev_quiesce(peer, msg); return; -#endif /* EXPERIMENTAL_FEATURES */ #else case WIRE_CHANNELD_DEV_REENABLE_COMMIT: case WIRE_CHANNELD_DEV_MEMLEAK: @@ -3980,11 +3966,9 @@ int main(int argc, char *argv[]) peer->shutdown_wrong_funding = NULL; peer->last_update_timestamp = 0; peer->last_empty_commitment = 0; -#if EXPERIMENTAL_FEATURES peer->stfu = false; peer->stfu_sent[LOCAL] = peer->stfu_sent[REMOTE] = false; peer->update_queue = msg_queue_new(peer, false); -#endif /* We send these to HSM to get real signatures; don't have valgrind * complain. */ diff --git a/common/interactivetx.c b/common/interactivetx.c index 76b6de927..c6222b997 100644 --- a/common/interactivetx.c +++ b/common/interactivetx.c @@ -196,9 +196,7 @@ static u8 *read_next_msg(const tal_t *ctx, case WIRE_PING: case WIRE_PONG: case WIRE_SHUTDOWN: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif *error = tal_fmt(ctx, "Received invalid message from peer: %d", t); return NULL; @@ -715,10 +713,10 @@ char *process_interactivetx_updates(const tal_t *ctx, case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_PING: case WIRE_PONG: + case WIRE_STFU: #if EXPERIMENTAL_FEATURES case WIRE_SPLICE: case WIRE_SPLICE_ACK: - case WIRE_STFU: #endif return tal_fmt(ctx, "Unexpected wire message %s", tal_hex(ctx, msg)); diff --git a/connectd/gossip_rcvd_filter.c b/connectd/gossip_rcvd_filter.c index 740b52957..93a58fe3c 100644 --- a/connectd/gossip_rcvd_filter.c +++ b/connectd/gossip_rcvd_filter.c @@ -91,9 +91,7 @@ static bool is_msg_gossip_broadcast(const u8 *cursor) case WIRE_YOUR_PEER_STORAGE: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif break; } return false; diff --git a/connectd/gossip_store.c b/connectd/gossip_store.c index 2dbf6bb51..e387f55d9 100644 --- a/connectd/gossip_store.c +++ b/connectd/gossip_store.c @@ -94,9 +94,7 @@ static bool public_msg_type(enum peer_wire type) case WIRE_ONION_MESSAGE: case WIRE_PEER_STORAGE: case WIRE_YOUR_PEER_STORAGE: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif return false; case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_NODE_ANNOUNCEMENT: diff --git a/connectd/multiplex.c b/connectd/multiplex.c index beb4706d8..a79ddf531 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -389,9 +389,7 @@ static bool is_urgent(enum peer_wire type) case WIRE_ONION_MESSAGE: case WIRE_PEER_STORAGE: case WIRE_YOUR_PEER_STORAGE: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif return false; /* These are time-sensitive, and so send without delay. */ diff --git a/doc/lightning-listconfigs.7.md b/doc/lightning-listconfigs.7.md index c2e1d68b1..cd0b3baaa 100644 --- a/doc/lightning-listconfigs.7.md +++ b/doc/lightning-listconfigs.7.md @@ -63,6 +63,7 @@ On success, an object is returned, containing: - **experimental-shutdown-wrong-funding** (boolean, optional): `experimental-shutdown-wrong-funding` field from config or cmdline, or default - **experimental-websocket-port** (u16, optional): `experimental-websocket-port` field from config or cmdline, or default - **experimental-peer-storage** (boolean, optional): `experimental-peer-storage` field from config or cmdline, or default *(added v23.02)* +- **experimental-quiesce** (boolean, optional): `experimental-quiesce` field from config or cmdline, or default *(added v23.08)* - **database-upgrade** (boolean, optional): `database-upgrade` field from config or cmdline - **rgb** (hex, optional): `rgb` field from config or cmdline, or default (always 6 characters) - **alias** (string, optional): `alias` field from config or cmdline, or default @@ -224,4 +225,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:b24158a61bb79aaf3f0f6d1c20a4b10d474613b371e80aede4aeb59ab471a989) +[comment]: # ( SHA256STAMP:62e8c380f4fa7b063c145ad43428c4ce48cb142cab61da72a26c2961375fabab) diff --git a/doc/lightningd-config.5.md b/doc/lightningd-config.5.md index 4ba84d860..775976f18 100644 --- a/doc/lightningd-config.5.md +++ b/doc/lightningd-config.5.md @@ -720,6 +720,11 @@ frames once the connection is upgraded. data for our peers, and give them our (encrypted!) backup data to store as well, based on a protocol similar to [bolt][bolt] #881. +* **experimental-quiesce** + + Specifying this option advertizes `option_quiesce`. Not very useful +by itself, except for testing. + BUGS ---- diff --git a/doc/schemas/listconfigs.schema.json b/doc/schemas/listconfigs.schema.json index 32e7b096d..f4801fd94 100644 --- a/doc/schemas/listconfigs.schema.json +++ b/doc/schemas/listconfigs.schema.json @@ -142,6 +142,11 @@ "added": "v23.02", "description": "`experimental-peer-storage` field from config or cmdline, or default" }, + "experimental-quiesce": { + "type": "boolean", + "added": "v23.08", + "description": "`experimental-quiesce` field from config or cmdline, or default" + }, "database-upgrade": { "type": "boolean", "description": "`database-upgrade` field from config or cmdline" diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index c8276f1cd..a94d51120 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -628,9 +628,7 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg) case WIRE_ONION_MESSAGE: case WIRE_PEER_STORAGE: case WIRE_YOUR_PEER_STORAGE: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif break; } diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 2bbcef4aa..62adebe71 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -1164,7 +1164,6 @@ static const struct json_command dev_feerate_command = { }; AUTODATA(json_command, &dev_feerate_command); -#if EXPERIMENTAL_FEATURES static void quiesce_reply(struct subd *channeld UNUSED, const u8 *reply, const int *fds UNUSED, @@ -1196,6 +1195,7 @@ static struct command_result *json_dev_quiesce(struct command *cmd, if (!peer) return command_fail(cmd, LIGHTNINGD, "Peer not connected"); + /* FIXME: If this becomes a real API, check for OPT_QUIESCE! */ channel = peer_any_active_channel(peer, &more_than_one); if (!channel || !channel->owner || channel->state != CHANNELD_NORMAL) return command_fail(cmd, LIGHTNINGD, "Peer bad state"); @@ -1216,5 +1216,4 @@ static const struct json_command dev_quiesce_command = { "Initiate quiscence protocol with peer" }; AUTODATA(json_command, &dev_quiesce_command); -#endif /* EXPERIMENTAL_FEATURES */ #endif /* DEVELOPER */ diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 817edc81f..f3da50b5e 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -861,7 +861,6 @@ static struct feature_set *default_features(const tal_t *ctx) OPTIONAL_FEATURE(OPT_ROUTE_BLINDING), #if EXPERIMENTAL_FEATURES OPTIONAL_FEATURE(OPT_ANCHOR_OUTPUTS), - OPTIONAL_FEATURE(OPT_QUIESCE), OPTIONAL_FEATURE(OPT_ONION_MESSAGES), #endif }; diff --git a/lightningd/options.c b/lightningd/options.c index 101077a9f..7045355a8 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -1101,6 +1101,14 @@ static char *opt_set_peer_storage(struct lightningd *ld) return NULL; } +static char *opt_set_quiesce(struct lightningd *ld) +{ + feature_set_or(ld->our_features, + take(feature_set_for_feature(NULL, + OPTIONAL_FEATURE(OPT_QUIESCE)))); + return NULL; +} + static char *opt_set_offers(struct lightningd *ld) { ld->config.exp_offers = true; @@ -1182,6 +1190,10 @@ static void register_opts(struct lightningd *ld) opt_register_early_noarg("--experimental-peer-storage", opt_set_peer_storage, ld, "EXPERIMENTAL: enable peer backup storage and restore"); + opt_register_early_noarg("--experimental-quiesce", + opt_set_quiesce, ld, + "experimental: Advertise ability to quiesce" + " channels."); opt_register_early_arg("--announce-addr-dns", opt_set_bool_arg, opt_show_bool, &ld->announce_dns, @@ -1675,6 +1687,11 @@ static void add_config(struct lightningd *ld, feature_offered(ld->our_features ->bits[INIT_FEATURE], OPT_PROVIDE_PEER_BACKUP_STORAGE)); + } else if (opt->cb == (void *)opt_set_quiesce) { + json_add_bool(response, name0, + feature_offered(ld->our_features + ->bits[INIT_FEATURE], + OPT_QUIESCE)); } else if (opt->cb == (void *)plugin_opt_flag_set) { /* Noop, they will get added below along with the * OPT_HASARG options. */ diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 49ce872d1..757bdc745 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1450,9 +1450,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) case WIRE_PONG: case WIRE_PEER_STORAGE: case WIRE_YOUR_PEER_STORAGE: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif break; } @@ -1826,9 +1824,7 @@ static bool run_tx_interactive(struct state *state, case WIRE_PONG: case WIRE_PEER_STORAGE: case WIRE_YOUR_PEER_STORAGE: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif open_abort(state, "Unexpected wire message %s", tal_hex(tmpctx, msg)); return false; @@ -4196,9 +4192,7 @@ static u8 *handle_peer_in(struct state *state) case WIRE_PONG: case WIRE_PEER_STORAGE: case WIRE_YOUR_PEER_STORAGE: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif break; } diff --git a/tests/test_connection.py b/tests/test_connection.py index b1cf7d970..d303e2adf 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -3943,10 +3943,9 @@ def test_upgrade_statickey_fail(node_factory, executor, bitcoind): assert 'option_static_remotekey' in only_one(l2.rpc.listpeerchannels()['channels'])['features'] -@unittest.skipIf(not EXPERIMENTAL_FEATURES, "quiescence is experimental") @pytest.mark.developer("quiescence triggering is dev only") def test_quiescence(node_factory, executor): - l1, l2 = node_factory.line_graph(2) + l1, l2 = node_factory.line_graph(2, opts={'experimental-quiesce': None}) # Works fine. l1.pay(l2, 1000) diff --git a/wire/extracted_peer_exp_quiescence-protocol.patch b/wire/extracted_peer_09_quiescence-protocol.patch similarity index 100% rename from wire/extracted_peer_exp_quiescence-protocol.patch rename to wire/extracted_peer_09_quiescence-protocol.patch diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 1d3772c8f..b7d838e1a 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -49,9 +49,7 @@ static bool unknown_type(enum peer_wire t) case WIRE_YOUR_PEER_STORAGE: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif return false; } return true; @@ -105,9 +103,7 @@ bool is_msg_for_gossipd(const u8 *cursor) case WIRE_ONION_MESSAGE: case WIRE_PEER_STORAGE: case WIRE_YOUR_PEER_STORAGE: -#if EXPERIMENTAL_FEATURES case WIRE_STFU: -#endif break; } return false; @@ -363,14 +359,12 @@ bool extract_channel_id(const u8 *in_pkt, struct channel_id *channel_id) * 2. data: * * [`channel_id`:`channel_id`] */ -#if EXPERIMENTAL_FEATURES case WIRE_STFU: /* BOLT-quiescent #2: * 1. type: 2 (`stfu`) * 2. data: * * [`channel_id`:`channel_id`] */ -#endif return fromwire_channel_id(&cursor, &max, channel_id); } return false; diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv index 45f304be2..1773adb48 100644 --- a/wire/peer_wire.csv +++ b/wire/peer_wire.csv @@ -203,6 +203,9 @@ subtypedata,lease_rates,lease_fee_basis,u16, subtypedata,lease_rates,channel_fee_max_proportional_thousandths,u16, subtypedata,lease_rates,lease_fee_base_sat,u32, subtypedata,lease_rates,channel_fee_max_base_msat,tu32, +msgtype,stfu,2 +msgdata,stfu,channel_id,channel_id, +msgdata,stfu,initiator,u8, msgtype,shutdown,38 msgdata,shutdown,channel_id,channel_id, msgdata,shutdown,len,u16,