From 50fe819f47c02df435f96803a4324581830f0fc1 Mon Sep 17 00:00:00 2001 From: Dusty Daemon Date: Thu, 27 Jul 2023 13:17:33 -0700 Subject: [PATCH] splicing: Add channel state AWAITING_SPLICE Update gossip routiens and various other hecks on the channel state to consider AWAITING_SPLICE to be routable and treated similar to CHANNELD_NORMAL. Small updates to psbt interface Changelog-None --- bitcoin/psbt.c | 2 +- bitcoin/psbt.h | 2 +- common/jsonrpc_errors.h | 7 +++++++ common/psbt_internal.c | 6 +++++- common/psbt_internal.h | 4 +++- gossipd/routing.c | 4 ++-- lightningd/channel.c | 22 +++++++++++++++++++--- lightningd/channel.h | 10 ++++++++-- lightningd/channel_control.c | 7 ++++--- lightningd/channel_state.h | 5 ++++- lightningd/closing_control.c | 1 + lightningd/peer_control.c | 7 ++++++- lightningd/peer_htlcs.c | 2 +- openingd/dualopend.c | 2 +- plugins/libplugin-pay.c | 3 ++- plugins/test/run-route-overlong.c | 7 +++++-- plugins/topology.c | 5 ++++- 17 files changed, 74 insertions(+), 22 deletions(-) diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index fe9510b25..fe97ceb41 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -95,7 +95,7 @@ bool psbt_is_finalized(const struct wally_psbt *psbt) } struct wally_psbt_input *psbt_add_input(struct wally_psbt *psbt, - struct wally_tx_input *input, + const struct wally_tx_input *input, size_t insert_at) { const u32 flags = WALLY_PSBT_FLAG_NON_FINAL; /* Skip script/witness */ diff --git a/bitcoin/psbt.h b/bitcoin/psbt.h index 309dd9517..31e84e533 100644 --- a/bitcoin/psbt.h +++ b/bitcoin/psbt.h @@ -108,7 +108,7 @@ struct wally_tx *psbt_final_tx(const tal_t *ctx, const struct wally_psbt *psbt); u8 *psbt_make_key(const tal_t *ctx, u8 key_subtype, const u8 *key_data); struct wally_psbt_input *psbt_add_input(struct wally_psbt *psbt, - struct wally_tx_input *input, + const struct wally_tx_input *input, size_t insert_at); /* One stop shop for adding an input + metadata to a PSBT */ diff --git a/common/jsonrpc_errors.h b/common/jsonrpc_errors.h index ee4f4d6d4..4b0b52601 100644 --- a/common/jsonrpc_errors.h +++ b/common/jsonrpc_errors.h @@ -65,6 +65,13 @@ enum jsonrpc_errcode { FUNDING_STATE_INVALID = 312, FUND_CANNOT_AFFORD_WITH_EMERGENCY = 313, + /* Splice errors */ + SPLICE_BROADCAST_FAIL = 350, + SPLICE_WRONG_OWNER = 351, + SPLICE_UNKNOWN_CHANNEL = 352, + SPLICE_INVALID_CHANNEL_STATE = 353, + SPLICE_NOT_SUPPORTED = 354, + /* `connect` errors */ CONNECT_NO_KNOWN_ADDRESS = 400, CONNECT_ALL_ADDRESSES_FAILED = 401, diff --git a/common/psbt_internal.c b/common/psbt_internal.c index dc329c6ca..8a9176395 100644 --- a/common/psbt_internal.c +++ b/common/psbt_internal.c @@ -116,7 +116,8 @@ void psbt_finalize_input(const tal_t *ctx, const struct witness ** psbt_to_witnesses(const tal_t *ctx, const struct wally_psbt *psbt, - enum tx_role side_to_stack) + enum tx_role side_to_stack, + int input_index_to_ignore) { u64 serial_id; const struct witness **witnesses = @@ -128,6 +129,9 @@ psbt_to_witnesses(const tal_t *ctx, /* FIXME: throw an error ? */ return tal_free(witnesses); + if (input_index_to_ignore == i) + continue; + /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: * - if is the *initiator*: * - MUST send even `serial_id`s diff --git a/common/psbt_internal.h b/common/psbt_internal.h index b3a121b7c..9d7bf2a0a 100644 --- a/common/psbt_internal.h +++ b/common/psbt_internal.h @@ -27,11 +27,13 @@ void psbt_finalize_input(const tal_t *ctx, * @ctx - allocation context * @psbt - PSBT to copy sigs from * @side_to_stack - which side to stack witnesses of + * @input_index_to_ignore - which input to not include. Pass -1 to include all. */ const struct witness ** psbt_to_witnesses(const tal_t *ctx, const struct wally_psbt *psbt, - enum tx_role side_to_stack); + enum tx_role side_to_stack, + int input_index_to_ignore); /* psbt_input_weight - Calculate the tx weight for input index `in` */ size_t psbt_input_weight(struct wally_psbt *psbt, diff --git a/gossipd/routing.c b/gossipd/routing.c index 244d54a0d..740be6d98 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -505,7 +505,7 @@ static void remove_chan_from_node(struct routing_state *rstate, /* Last channel? Simply delete node (and associated announce) */ if (num_chans == 0) { - if(node->rgraph.index != node->bcast.index) + if (node->rgraph.index != node->bcast.index) gossip_store_delete(rstate->gs, &node->rgraph, WIRE_NODE_ANNOUNCEMENT); @@ -522,7 +522,7 @@ static void remove_chan_from_node(struct routing_state *rstate, /* Removed only public channel? Remove node announcement. */ if (!node_has_broadcastable_channels(node)) { - if(node->rgraph.index != node->bcast.index) + if (node->rgraph.index != node->bcast.index) gossip_store_delete(rstate->gs, &node->rgraph, WIRE_NODE_ANNOUNCEMENT); diff --git a/lightningd/channel.c b/lightningd/channel.c index 73a9430f2..0d87f83df 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -152,8 +152,11 @@ new_inflight(struct channel *channel, inflight->funding_psbt = tal_steal(inflight, psbt); /* Make a 'clone' of this tx */ - last_tx_psbt_clone = clone_psbt(inflight, last_tx->psbt); - inflight->last_tx = bitcoin_tx_with_psbt(inflight, last_tx_psbt_clone); + inflight->last_tx = NULL; + if (last_tx) { + last_tx_psbt_clone = clone_psbt(inflight, last_tx->psbt); + inflight->last_tx = bitcoin_tx_with_psbt(inflight, last_tx_psbt_clone); + } inflight->last_sig = last_sig; inflight->tx_broadcast = false; @@ -580,6 +583,18 @@ const char *channel_state_str(enum channel_state state) return "unknown"; } +bool channel_state_normalish(const struct channel *channel) +{ + return channel->state == CHANNELD_NORMAL + || channel->state == CHANNELD_AWAITING_SPLICE; +} + +bool channel_state_awaitish(const struct channel *channel) +{ + return channel->state == CHANNELD_AWAITING_LOCKIN + || channel->state == CHANNELD_AWAITING_SPLICE; +} + struct channel *peer_any_active_channel(struct peer *peer, bool *others) { struct channel *channel, *ret = NULL; @@ -793,7 +808,8 @@ void channel_set_state(struct channel *channel, struct timeabs timestamp; /* set closer, if known */ - if (state > CHANNELD_NORMAL && channel->closer == NUM_SIDES) { + if (!(state == CHANNELD_AWAITING_SPLICE) + && state > CHANNELD_NORMAL && channel->closer == NUM_SIDES) { if (reason == REASON_LOCAL) channel->closer = LOCAL; if (reason == REASON_USER) channel->closer = LOCAL; if (reason == REASON_REMOTE) channel->closer = REMOTE; diff --git a/lightningd/channel.h b/lightningd/channel.h index a34de93e0..7eae370c1 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -384,6 +384,12 @@ void delete_channel(struct channel *channel STEALS); const char *channel_state_name(const struct channel *channel); const char *channel_state_str(enum channel_state state); +/* Is the channel in NORMAL or AWAITING_SPLICE state? */ +bool channel_state_normalish(const struct channel *channel); + +/* Is the channel in AWAITING_*? */ +bool channel_state_awaitish(const struct channel *channel); + void channel_set_owner(struct channel *channel, struct subd *owner); /* Channel has failed, but can try again. */ @@ -454,12 +460,12 @@ void channel_set_last_tx(struct channel *channel, static inline bool channel_can_add_htlc(const struct channel *channel) { - return channel->state == CHANNELD_NORMAL; + return channel_state_normalish(channel); } static inline bool channel_fees_can_change(const struct channel *channel) { - return channel->state == CHANNELD_NORMAL + return channel_state_normalish(channel) || channel->state == CHANNELD_SHUTTING_DOWN; } diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 21bf7b7a9..0f18226b5 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -888,7 +888,8 @@ bool channel_tell_depth(struct lightningd *ld, txid, depth); return true; } else if (channel->state != CHANNELD_AWAITING_LOCKIN - && channel->state != CHANNELD_NORMAL) { + && channel->state != CHANNELD_NORMAL + && channel->state != CHANNELD_AWAITING_SPLICE) { /* If not awaiting lockin/announce, it doesn't * care any more */ log_debug(channel->log, @@ -1187,7 +1188,7 @@ static struct command_result *json_dev_feerate(struct command *cmd, return command_fail(cmd, LIGHTNINGD, "Peer not connected"); channel = peer_any_active_channel(peer, &more_than_one); - if (!channel || !channel->owner || channel->state != CHANNELD_NORMAL) + if (!channel || !channel->owner || !channel_state_normalish(channel)) return command_fail(cmd, LIGHTNINGD, "Peer bad state"); /* This is a dev command: fix the api if you need this! */ if (more_than_one) @@ -1247,7 +1248,7 @@ static struct command_result *json_dev_quiesce(struct command *cmd, /* 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) + if (!channel || !channel->owner || !channel_state_normalish(channel)) return command_fail(cmd, LIGHTNINGD, "Peer bad state"); /* This is a dev command: fix the api if you need this! */ if (more_than_one) diff --git a/lightningd/channel_state.h b/lightningd/channel_state.h index bb871fbb9..8ba616fbe 100644 --- a/lightningd/channel_state.h +++ b/lightningd/channel_state.h @@ -40,8 +40,11 @@ enum channel_state { /* Dual-funded channel, waiting for lock-in */ DUALOPEND_AWAITING_LOCKIN, + + /* Channel has started splice and is awaiting lock-in */ + CHANNELD_AWAITING_SPLICE, }; -#define CHANNEL_STATE_MAX DUALOPEND_AWAITING_LOCKIN +#define CHANNEL_STATE_MAX CHANNELD_AWAITING_SPLICE /* These are in the database, so don't renumber them! */ enum state_change { diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index f5ba5babb..eaad43efd 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -836,6 +836,7 @@ static struct command_result *json_close(struct command *cmd, * waiting) */ switch (channel->state) { case CHANNELD_NORMAL: + case CHANNELD_AWAITING_SPLICE: case CHANNELD_AWAITING_LOCKIN: case DUALOPEND_AWAITING_LOCKIN: channel_set_state(channel, diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 229cc3682..c866af3f7 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1170,6 +1170,7 @@ static void connect_activate_subd(struct lightningd *ld, struct channel *channel case CHANNELD_AWAITING_LOCKIN: case CHANNELD_NORMAL: + case CHANNELD_AWAITING_SPLICE: case CHANNELD_SHUTTING_DOWN: case CLOSINGD_SIGEXCHANGE: assert(!channel->owner); @@ -1827,10 +1828,13 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, tal_free(txidstr); bool min_depth_reached = depth >= channel->minimum_depth; + bool min_depth_no_scid = min_depth_reached && !channel->scid; + bool some_depth_has_scid = depth && channel->scid; /* Reorg can change scid, so always update/save scid when possible (depth=0 * means the stale block with our funding tx was removed) */ - if ((min_depth_reached && !channel->scid) || (depth && channel->scid)) { + if (channel->state != CHANNELD_AWAITING_SPLICE + && (min_depth_no_scid || some_depth_has_scid)) { struct txlocator *loc; struct channel_inflight *inf; @@ -2632,6 +2636,7 @@ static struct command_result *param_channel_or_all(struct command *cmd, *channels = tal_arr(cmd, struct channel *, 0); list_for_each(&peer->channels, channel, list) { if (channel->state != CHANNELD_NORMAL + && channel->state != CHANNELD_AWAITING_SPLICE && channel->state != CHANNELD_AWAITING_LOCKIN && channel->state != DUALOPEND_AWAITING_LOCKIN) continue; diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 21e6cf3ab..7334aca18 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -582,7 +582,7 @@ static void htlc_offer_timeout(struct htlc_out *out) assert(out->hstate == SENT_ADD_HTLC); /* If owner died, we should already be taken care of. */ - if (!channel->owner || channel->state != CHANNELD_NORMAL) + if (!channel->owner || !channel_state_normalish(channel)) return; log_unusual(channel->owner->log, diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 442576cb7..7340df20d 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -993,7 +993,7 @@ static u8 *psbt_to_tx_sigs_msg(const tal_t *ctx, const struct wally_psbt *psbt) { const struct witness **ws = - psbt_to_witnesses(tmpctx, psbt, state->our_role); + psbt_to_witnesses(tmpctx, psbt, state->our_role, -1); return towire_tx_signatures(ctx, &state->channel_id, &state->tx_state->funding.txid, diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index 9f75a4ad4..b4ae81d6c 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -3291,7 +3291,8 @@ static struct command_result *direct_pay_listpeerchannels(struct command *cmd, if (!chan->connected) continue; - if (!streq(chan->state, "CHANNELD_NORMAL")) + if (!streq(chan->state, "CHANNELD_NORMAL") + && !streq(chan->state, "CHANNELD_AWAITING_SPLICE")) continue; /* Must have either a local alias for zeroconf diff --git a/plugins/test/run-route-overlong.c b/plugins/test/run-route-overlong.c index c78350126..f78f0fa56 100644 --- a/plugins/test/run-route-overlong.c +++ b/plugins/test/run-route-overlong.c @@ -255,8 +255,12 @@ static void update_connection(int store_fd, bool disable) { secp256k1_ecdsa_signature dummy_sig; + u8 flags = node_id_idx(from, to); u8 *msg; + if (disable) + flags |= ROUTING_FLAGS_DISABLED; + /* So valgrind doesn't complain */ memset(&dummy_sig, 0, sizeof(dummy_sig)); @@ -265,8 +269,7 @@ static void update_connection(int store_fd, &chainparams->genesis_blockhash, scid, 0, ROUTING_OPT_HTLC_MAX_MSAT, - node_id_idx(from, to) - + (disable ? ROUTING_FLAGS_DISABLED : 0), + flags, delay, min, base_fee, diff --git a/plugins/topology.c b/plugins/topology.c index c6def06ce..32c2bea4a 100644 --- a/plugins/topology.c +++ b/plugins/topology.c @@ -317,7 +317,10 @@ static struct node_map *local_connected(const tal_t *ctx, /* Must also have a channel in CHANNELD_NORMAL */ normal_chan = json_tok_streq(buf, json_get_member(buf, channel, "state"), - "CHANNELD_NORMAL"); + "CHANNELD_NORMAL") + || json_tok_streq(buf, + json_get_member(buf, channel, "state"), + "CHANNELD_AWAITING_SPLICE"); if (normal_chan) node_map_add(connected,