From 5e5ad012df979aab40961ec98b0a8aa6a93ee66b Mon Sep 17 00:00:00 2001 From: Dustin Dettmer Date: Sun, 5 Mar 2023 16:36:03 -0500 Subject: [PATCH] channeld: Code to implement splicing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update the lightningd <-> channeld interface with lots of new commands to needed to facilitate spicing. Implement the channeld splicing protocol leveraging the interactivetx protocol. Implement lightningd’s channel_control to support channeld in its splicing efforts. Changelog-Added: Added the features to enable splicing & resizing of active channels. --- channeld/Makefile | 2 + channeld/channeld.c | 2191 +++++++++++++++-- channeld/channeld_wire.csv | 86 + channeld/inflight.h | 13 + common/initial_channel.c | 103 + common/initial_channel.h | 15 + common/interactivetx.c | 131 +- common/interactivetx.h | 23 +- connectd/gossip_rcvd_filter.c | 5 +- connectd/gossip_store.c | 5 +- connectd/multiplex.c | 5 +- contrib/pyln-client/pyln/client/lightning.py | 33 + gossipd/gossipd.c | 5 +- lightningd/channel_control.c | 899 ++++++- lightningd/lightningd.c | 2 + lightningd/lightningd.h | 3 + lightningd/peer_control.c | 38 +- lightningd/peer_control.h | 7 + lightningd/peer_htlcs.c | 43 +- lightningd/routehint.c | 7 +- lightningd/test/run-invoice-select-inchan.c | 6 + openingd/dualopend.c | 47 +- tests/test_splicing.py | 48 + wallet/test/run-wallet.c | 2 +- ...racted_peer_06_funding_outpoint_sigs.patch | 18 + ...tracted_peer_exp_quiescence-protocol.patch | 12 - wire/fromwire.c | 6 + wire/peer_wire.c | 36 +- wire/peer_wire.csv | 23 + wire/test/run-peer-wire.c | 7 +- wire/towire.c | 6 + wire/wire.h | 5 + 32 files changed, 3495 insertions(+), 337 deletions(-) create mode 100644 channeld/inflight.h create mode 100644 tests/test_splicing.py create mode 100644 wire/extracted_peer_06_funding_outpoint_sigs.patch delete mode 100644 wire/extracted_peer_exp_quiescence-protocol.patch diff --git a/channeld/Makefile b/channeld/Makefile index 5e98db2f0147..731cd7955c02 100644 --- a/channeld/Makefile +++ b/channeld/Makefile @@ -53,6 +53,7 @@ CHANNELD_COMMON_OBJS := \ common/status_wiregen.o \ common/gossip_store.o \ common/hmac.o \ + common/interactivetx.o \ common/htlc_state.o \ common/htlc_trim.o \ common/htlc_tx.o \ @@ -73,6 +74,7 @@ CHANNELD_COMMON_OBJS := \ common/ping.o \ common/psbt_keypath.o \ common/psbt_open.o \ + common/psbt_internal.o \ common/private_channel_announcement.o \ common/pseudorand.o \ common/read_peer_msg.o \ diff --git a/channeld/channeld.c b/channeld/channeld.c index feba13169f9e..3cf73d225719 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -11,6 +11,7 @@ * limits, unlikely as that is. */ #include "config.h" +#include #include #include #include @@ -18,14 +19,18 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -45,11 +50,16 @@ #include #include #include +#include /* stdin == requests, 3 == peer, 4 = HSM */ #define MASTER_FD STDIN_FILENO #define HSM_FD 4 +#define VALID_STFU_MESSAGE(msg) \ + ((msg) == WIRE_SPLICE || \ + (msg) == WIRE_SPLICE_ACK) + struct peer { struct per_peer_state *pps; bool channel_ready[NUM_SIDES]; @@ -113,6 +123,7 @@ struct peer { secp256k1_ecdsa_signature announcement_node_sigs[NUM_SIDES]; secp256k1_ecdsa_signature announcement_bitcoin_sigs[NUM_SIDES]; bool have_sigs[NUM_SIDES]; + bool send_duplicate_announce_sigs; /* Which direction of the channel do we control? */ u16 channel_direction; @@ -140,16 +151,52 @@ 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; + bool stfu_request; /* Which side is considered the initiator? */ enum side stfu_initiator; /* Has stfu been sent by each side? */ bool stfu_sent[NUM_SIDES]; + /* After STFU mode is enabled, wait for a signle message flag */ + bool stfu_wait_single_msg; /* Updates master asked, which we've deferred while quiescing */ struct msg_queue *update_queue; -#endif + /* The opener side's share of post splice channel balance */ + struct amount_sat splice_opener_funding; + /* The accepter side's share of post splice channel balance */ + struct amount_sat splice_accepter_funding; + /* The feerate for the splice (on set for the initiator) */ + u32 splice_feerate_per_kw; + /* If the feerate is higher than max, don't abort the splice */ + bool splice_force_feerate; + /* Make our side sign first */ + bool splice_force_sign_first; + /* Callback for when when stfu is negotiated successfully */ + void (*on_stfu_success)(struct peer*); + /* The number of splices that have been signed & committed */ + u32 committed_splice_count; + /* the number of splices that have been revoke_and_ack'ed */ + u32 revoked_splice_count; + /* The number of splices that are active (awaiting confirmation) */ + u32 splice_count; + /* Track how many of each tx collab msg we receive */ + u16 tx_add_input_count, tx_add_output_count; + /* Current negoitated psbt */ + struct wally_psbt *current_psbt; + /* If, in the last splice_update, we tx_complete was received */ + bool received_tx_complete; + /* The pending short channel id for a splice. Set when mutual lock. */ + struct short_channel_id splice_short_channel_id; + /* Set to old short channel id when mutual lock occurs. */ + struct short_channel_id last_short_channel_id; + /* Tally of which sides are locked, or not */ + bool splice_locked_ready[NUM_SIDES]; + /* Set to true when commitment cycle completes successfully */ + bool splice_await_commitment_succcess; + /* The txid of which splice inflight was confirmed */ + struct bitcoin_txid splice_locked_txid; + /* The active inflights */ + struct inflight *inflights; #if DEVELOPER /* If set, don't fire commit counter when this hits 0 */ @@ -228,28 +275,53 @@ const u8 *hsm_req(const tal_t *ctx, const u8 *req TAKES) return msg; } -#if EXPERIMENTAL_FEATURES +static bool is_stfu_active(const struct peer *peer) +{ + return peer->stfu_sent[LOCAL] && peer->stfu_sent[REMOTE]; +} + +static void end_stfu_mode(struct peer *peer) +{ + peer->stfu_request = false; + peer->stfu_sent[LOCAL] = peer->stfu_sent[REMOTE] = false; + peer->stfu_wait_single_msg = false; + peer->on_stfu_success = NULL; + + status_debug("Left STFU mode."); +} + static void maybe_send_stfu(struct peer *peer) { - if (!peer->stfu) + if (!peer->stfu_request) return; if (!peer->stfu_sent[LOCAL] && !pending_updates(peer->channel, LOCAL, false)) { + status_debug("Sending peer that we want to STFU."); u8 *msg = towire_stfu(NULL, &peer->channel_id, peer->stfu_initiator == LOCAL); peer_write(peer->pps, take(msg)); peer->stfu_sent[LOCAL] = true; + } else if(pending_updates(peer->channel, LOCAL, false)) { + status_info("Pending updates prevent us from STFU mode at this time."); } if (peer->stfu_sent[LOCAL] && peer->stfu_sent[REMOTE]) { - status_unusual("STFU complete: we are quiescent"); wire_sync_write(MASTER_FD, towire_channeld_dev_quiesce_reply(tmpctx)); + + peer->stfu_wait_single_msg = true; + peer->stfu_request = false; + if (peer->on_stfu_success) { + peer->on_stfu_success(peer); + peer->on_stfu_success = NULL; + } } } static void handle_stfu(struct peer *peer, const u8 *stfu) { + status_debug("handle_stfu happening"); + struct channel_id channel_id; u8 remote_initiated; @@ -271,13 +343,15 @@ static void handle_stfu(struct peer *peer, const u8 *stfu) peer_failed_warn(peer->pps, &peer->channel_id, "STFU but you still have updates pending?"); - if (!peer->stfu) { - peer->stfu = true; + if (!peer->stfu_request) { + peer->stfu_request = true; if (!remote_initiated) peer_failed_warn(peer->pps, &peer->channel_id, "Unsolicited STFU but you said" " you didn't initiate?"); peer->stfu_initiator = REMOTE; + + status_debug("STFU intiator was remote."); } else { /* BOLT-quiescent #2: * @@ -286,8 +360,14 @@ static void handle_stfu(struct peer *peer, const u8 *stfu) * arbitrarily considered to be the channel funder (the sender * of `open_channel`). */ - if (remote_initiated) + if (remote_initiated) { + status_debug("Dual STFU intiation tiebreaker. Setting intiator to %s", + peer->channel->opener == LOCAL ? "LOCAL" : "REMOTE"); peer->stfu_initiator = peer->channel->opener; + } + else { + status_debug("STFU intiator local."); + } } /* BOLT-quiescent #2: @@ -306,13 +386,14 @@ static void handle_stfu(struct peer *peer, const u8 *stfu) /* Returns true if we queued this for later handling (steals if true) */ static bool handle_master_request_later(struct peer *peer, const u8 *msg) { - if (peer->stfu) { + if (is_stfu_active(peer)) { msg_enqueue(peer->update_queue, take(msg)); return true; } return false; } +#if EXPERIMENTAL_FEATURES /* Compare, with false if either is NULL */ static bool match_type(const u8 *t1, const u8 *t2) { @@ -342,22 +423,15 @@ 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 * it's a private channel) */ static void send_channel_update(struct peer *peer, int disable_flag) { + status_debug("send_channel_update %d", disable_flag); + u8 *msg; assert(disable_flag == 0 || disable_flag == ROUTING_FLAGS_DISABLED); @@ -508,17 +582,27 @@ static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer) /* Once we have both, we'd better make sure we agree what they are! */ static void check_short_ids_match(struct peer *peer) { + bool grace_period_msg; assert(peer->have_sigs[LOCAL]); assert(peer->have_sigs[REMOTE]); - if (!short_channel_id_eq(&peer->short_channel_ids[LOCAL], - &peer->short_channel_ids[REMOTE])) + grace_period_msg = peer->splice_await_commitment_succcess + && short_channel_id_eq(&peer->short_channel_ids[REMOTE], + &peer->last_short_channel_id); + if (grace_period_msg) + status_info("Ignoring stale scid: expected %s, got %s", + type_to_string(tmpctx, struct short_channel_id, + &peer->short_channel_ids[REMOTE]), + type_to_string(tmpctx, struct short_channel_id, + &peer->short_channel_ids[LOCAL])); + else if (!short_channel_id_eq(&peer->short_channel_ids[LOCAL], + &peer->short_channel_ids[REMOTE])) peer_failed_warn(peer->pps, &peer->channel_id, "We disagree on short_channel_ids:" " I have %s, you say %s", - type_to_string(peer, struct short_channel_id, + type_to_string(tmpctx, struct short_channel_id, &peer->short_channel_ids[LOCAL]), - type_to_string(peer, struct short_channel_id, + type_to_string(tmpctx, struct short_channel_id, &peer->short_channel_ids[REMOTE])); } @@ -531,10 +615,12 @@ static void announce_channel(struct peer *peer) wire_sync_write(MASTER_FD, take(towire_channeld_local_channel_announcement(NULL, cannounce))); + send_channel_update(peer, 0); } -static void channel_announcement_negotiate(struct peer *peer) +static void channel_announcement_negotiate(struct peer *peer, + bool *sent_announcement) { /* Don't do any announcement work if we're shutting down */ if (peer->shutdown_sent[LOCAL]) @@ -544,6 +630,10 @@ static void channel_announcement_negotiate(struct peer *peer) if (!peer->channel_ready[LOCAL] || !peer->channel_ready[REMOTE]) return; + /* Don't announce channel if we're in stfu mode */ + if (peer->stfu_request || is_stfu_active(peer)) + return; + if (!peer->channel_local_active) { peer->channel_local_active = true; make_channel_local_active(peer); @@ -583,6 +673,8 @@ static void channel_announcement_negotiate(struct peer *peer) send_announcement_signatures(peer); peer->have_sigs[LOCAL] = true; billboard_update(peer); + if (sent_announcement) + *sent_announcement = true; } /* If we've completed the signature exchange, we can send a real @@ -604,10 +696,220 @@ static void channel_announcement_negotiate(struct peer *peer) } } +// static void handle_peer_splice_locked_ack(struct peer *peer, const u8 *msg) +// { +// int type; +// char *error; +// struct inflight *inflight; +// struct amount_msat local_funding_msat; +// struct channel_id chanid; + +// peer_write(peer->pps, +// take(towire_splice_locked_ack(NULL, &peer->channel_id))); + +// if (!msg) +// msg = peer_read(tmpctx, peer->pps); + +// type = fromwire_peektype(msg); +// if (handle_peer_error(peer->pps, &peer->channel_id, msg)) +// return; +// if (type != WIRE_SPLICE_LOCKED_ACK) +// peer_failed_warn(peer->pps, &peer->channel_id, +// "Splicing got incorrect message from peer: %s " +// "(should be WIRE_SPLICE_LOCKED_ACK)", +// peer_wire_name(type)); + +// if (!fromwire_splice_locked_ack(msg, &chanid)) +// peer_failed_warn(peer->pps, &peer->channel_id, +// "wire_splice_locked_ack %s", +// tal_hex(msg, msg)); + +// if (!channel_id_eq(&chanid, &peer->channel_id)) +// peer_failed_warn(peer->pps, &peer->channel_id, +// "wire_splice_locked_ack mismatched channelid"); + +// peer->have_sigs[LOCAL] = false; +// peer->have_sigs[REMOTE] = false; +// peer->send_duplicate_announce_sigs = true; + +// peer->last_short_channel_id = peer->short_channel_ids[LOCAL]; +// peer->short_channel_ids[LOCAL] = peer->splice_short_channel_id; +// peer->short_channel_ids[REMOTE] = peer->splice_short_channel_id; + +// status_debug("mutual splice_locked, scid LOCAL & REMOTE updated to: %s", +// type_to_string(tmpctx, struct short_channel_id, +// &peer->splice_short_channel_id)); + +// inflight = NULL; +// for (size_t i = 0; i < tal_count(peer->inflights); i++) +// if (bitcoin_txid_eq(&peer->inflights[i].outpoint.txid, +// &peer->splice_locked_txid)) +// inflight = &peer->inflights[i]; + +// if (!inflight) +// peer_failed_warn(peer->pps, &peer->channel_id, +// "Unable to find inflight txid."); + +// if (!amount_sat_to_msat(&local_funding_msat, inflight->local_funding)) +// peer_failed_warn(peer->pps, &peer->channel_id, +// "Uabled to convert local funding to msats."); + +// status_debug("mutual splice_locked, updating change from: %s", +// type_to_string(tmpctx, struct channel, peer->channel)); + +// error = channel_update_funding(peer->channel, &inflight->outpoint, +// inflight->amnt, +// peer->channel->starting_local_msats, +// inflight->local_funding); +// if (error) +// peer_failed_warn(peer->pps, &peer->channel_id, +// "Splice lock unable to update funding. %s", +// error); + +// status_debug("mutual splice_locked, channel updated to: %s", +// type_to_string(tmpctx, struct channel, peer->channel)); + +// msg = towire_channeld_got_splice_locked(NULL, inflight->amnt, +// peer->channel->starting_local_msats, +// local_funding_msat, +// &inflight->outpoint.txid); +// wire_sync_write(MASTER_FD, take(msg)); + +// end_stfu_mode(peer); + +// channel_announcement_negotiate(peer, NULL); +// billboard_update(peer); +// send_channel_update(peer, 0); + +// peer->inflights = tal_free(peer->inflights); +// peer->splice_count = 0; +// peer->revoked_splice_count = 0; +// peer->committed_splice_count = 0; +// } + +// static void mutual_splice_lock_and_stfu(struct peer *peer) +// { +// handle_peer_splice_locked_ack(peer, NULL); +// } + +/* Call this method when splice_locked status are changed. If both sides have + * splice_locked'ed than this function consumes the `splice_locked_ready` values + * and moves the channel to STFU and then a post-splice state */ +static void check_mutual_splice_locked(struct peer *peer) +{ + u8 *msg; + char *error; + struct inflight *inflight; + struct amount_msat local_funding_msat; + + /* If both sides haven't splice_locked we're not ready */ + if (!peer->splice_locked_ready[LOCAL] + || !peer->splice_locked_ready[REMOTE]) + return; + + if (short_channel_id_eq(&peer->short_channel_ids[LOCAL], + &peer->splice_short_channel_id)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Duplicate splice_locked events detected"); + + peer->splice_await_commitment_succcess = true; + + /* This splice_locked event is used, so reset the flags to false */ + peer->splice_locked_ready[LOCAL] = false; + peer->splice_locked_ready[REMOTE] = false; + + + peer->have_sigs[LOCAL] = false; + peer->have_sigs[REMOTE] = false; + peer->send_duplicate_announce_sigs = true; + + peer->last_short_channel_id = peer->short_channel_ids[LOCAL]; + peer->short_channel_ids[LOCAL] = peer->splice_short_channel_id; + peer->short_channel_ids[REMOTE] = peer->splice_short_channel_id; + + status_debug("mutual splice_locked, scid LOCAL & REMOTE updated to: %s", + type_to_string(tmpctx, struct short_channel_id, + &peer->splice_short_channel_id)); + + inflight = NULL; + for (size_t i = 0; i < tal_count(peer->inflights); i++) + if (bitcoin_txid_eq(&peer->inflights[i].outpoint.txid, + &peer->splice_locked_txid)) + inflight = &peer->inflights[i]; + + if (!inflight) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to find inflight txid amoung %zu" + " inflights. new funding txid: %s", + tal_count(peer->inflights), + type_to_string(tmpctx, struct bitcoin_txid, + &peer->splice_locked_txid)); + + if (!amount_sat_to_msat(&local_funding_msat, inflight->local_funding)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Uabled to convert local funding to msats."); + + status_debug("mutual splice_locked, updating change from: %s", + type_to_string(tmpctx, struct channel, peer->channel)); + + /* DTODO: Payments during splice lock appeara to be off by precisely the + * amount of channel increase on the intiator side */ + error = channel_update_funding(peer->channel, &inflight->outpoint, + inflight->amnt, + peer->channel->starting_local_msats, + inflight->local_funding); + if (error) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splice lock unable to update funding. %s", + error); + + status_debug("mutual splice_locked, channel updated to: %s", + type_to_string(tmpctx, struct channel, peer->channel)); + + msg = towire_channeld_got_splice_locked(NULL, inflight->amnt, + peer->channel->starting_local_msats, + local_funding_msat, + &inflight->outpoint.txid); + wire_sync_write(MASTER_FD, take(msg)); + + channel_announcement_negotiate(peer, NULL); + billboard_update(peer); + send_channel_update(peer, 0); + + peer->inflights = tal_free(peer->inflights); + peer->splice_count = 0; + peer->revoked_splice_count = 0; + peer->committed_splice_count = 0; +} + +/* Our peer told us they saw our splice confirm on chain with `splice_locked`. + * If we see it to we jump into tansitioning to post-splice, otherwise we mark + * a flag and wait until we see it on chain too. */ +static void handle_peer_splice_locked(struct peer *peer, const u8 *msg) +{ + struct channel_id chanid; + + if (!fromwire_splice_locked(msg, &chanid)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Bad splice_locked %s", tal_hex(msg, msg)); + + if (!channel_id_eq(&chanid, &peer->channel_id)) + peer_failed_err(peer->pps, &chanid, + "Wrong splice lock channel id in %s " + "(expected %s)", + tal_hex(tmpctx, msg), + type_to_string(msg, struct channel_id, + &peer->channel_id)); + + peer->splice_locked_ready[REMOTE] = true; + check_mutual_splice_locked(peer); +} + static void handle_peer_channel_ready(struct peer *peer, const u8 *msg) { struct channel_id chanid; struct tlv_channel_ready_tlvs *tlvs; + /* BOLT #2: * * A node: @@ -648,13 +950,15 @@ static void handle_peer_channel_ready(struct peer *peer, const u8 *msg) take(towire_channeld_got_channel_ready( NULL, &peer->remote_per_commit, tlvs->short_channel_id))); - channel_announcement_negotiate(peer); + channel_announcement_negotiate(peer, NULL); billboard_update(peer); + peer->send_duplicate_announce_sigs = true; } static void handle_peer_announcement_signatures(struct peer *peer, const u8 *msg) { struct channel_id chanid; + bool sent_announcement; if (!fromwire_announcement_signatures(msg, &chanid, @@ -677,7 +981,11 @@ static void handle_peer_announcement_signatures(struct peer *peer, const u8 *msg peer->have_sigs[REMOTE] = true; billboard_update(peer); - channel_announcement_negotiate(peer); + channel_announcement_negotiate(peer, &sent_announcement); + if (!sent_announcement && peer->send_duplicate_announce_sigs) { + peer->send_duplicate_announce_sigs = false; + send_announcement_signatures(peer); + } } static void handle_peer_add_htlc(struct peer *peer, const u8 *msg) @@ -919,6 +1227,9 @@ static void maybe_send_shutdown(struct peer *peer) if (!peer->send_shutdown) return; + /* DTODO: Ensure 'shutdown' rules around splice are followed once those + * rules get settled on spec */ + /* Send a disable channel_update so others don't try to route * over us */ send_channel_update(peer, ROUTING_FLAGS_DISABLED); @@ -1013,7 +1324,8 @@ static struct simple_htlc **collect_htlcs(const tal_t *ctx, const struct htlc ** return htlcs; } -/* Returns HTLC sigs, sets commit_sig */ +/* Returns HTLC sigs, sets commit_sig. Also used for making commitsigs for each + * splice awaiting on-chain confirmation. */ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx, const struct peer *peer, struct bitcoin_tx **txs, @@ -1145,11 +1457,9 @@ 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) + if (is_stfu_active(peer)) return false; -#endif current = channel_feerate(peer->channel, REMOTE); /* max is *approximate*: only take it into account if we're @@ -1185,11 +1495,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) + if (is_stfu_active(peer)) return false; -#endif + /* What's the current blockheight */ last = get_blockheight(peer->channel->blockheight_states, peer->channel->opener, LOCAL); @@ -1209,19 +1518,85 @@ static bool want_blockheight_update(const struct peer *peer, u32 *height) return true; } -static void send_commit(struct peer *peer) +static u8 *send_commit_part(struct peer *peer, + const struct bitcoin_outpoint *funding, + struct amount_sat funding_sats, + const struct htlc **changed_htlcs, + bool notify_master) { u8 *msg; - const struct htlc **changed_htlcs; struct bitcoin_signature commit_sig, *htlc_sigs; struct bitcoin_tx **txs; const u8 *funding_wscript; const struct htlc **htlc_map; struct wally_tx_output *direct_outputs[NUM_SIDES]; struct penalty_base *pbase; + + struct tlv_commitment_signed_tlvs *cs_tlv + = tlv_commitment_signed_tlvs_new(tmpctx); + cs_tlv->splice_info = tal(cs_tlv, struct channel_id); + derive_channel_id(cs_tlv->splice_info, funding); + + txs = channel_splice_txs(tmpctx, funding, funding_sats, &htlc_map, + direct_outputs, &funding_wscript, + peer->channel, &peer->remote_per_commit, + peer->next_index[REMOTE], REMOTE); + + htlc_sigs = + calc_commitsigs(tmpctx, peer, txs, funding_wscript, htlc_map, + peer->next_index[REMOTE], &commit_sig); + + if (direct_outputs[LOCAL] != NULL) { + pbase = penalty_base_new(tmpctx, peer->next_index[REMOTE], + txs[0], direct_outputs[LOCAL]); + + /* Add the penalty_base to our in-memory list as well, so we + * can find it again later. */ + tal_arr_expand(&peer->pbases, tal_steal(peer, pbase)); + } else + pbase = NULL; + +#if DEVELOPER + if (peer->dev_disable_commit) { + (*peer->dev_disable_commit)--; + if (*peer->dev_disable_commit == 0) + status_unusual("dev-disable-commit-after: disabling"); + } +#endif + + if (notify_master) { + status_debug("Telling master we're about to commit..."); + /* Tell master to save this next commit to database, then wait. + */ + msg = sending_commitsig_msg(NULL, peer->next_index[REMOTE], + pbase, + peer->channel->fee_states, + peer->channel->blockheight_states, + changed_htlcs, + &commit_sig, + htlc_sigs); + /* Message is empty; receiving it is the point. */ + master_wait_sync_reply(tmpctx, peer, take(msg), + WIRE_CHANNELD_SENDING_COMMITSIG_REPLY); + + status_debug("Sending commit_sig with %zu htlc sigs", + tal_count(htlc_sigs)); + } + + msg = towire_commitment_signed(NULL, &peer->channel_id, + &commit_sig.s, + raw_sigs(tmpctx, htlc_sigs), + cs_tlv); + return msg; +} + +static void send_commit(struct peer *peer) +{ + const struct htlc **changed_htlcs; u32 our_blockheight; u32 feerate_target; - + u8 **msgs = tal_arr(tmpctx, u8*, 1); + u8 *msg; #if DEVELOPER if (peer->dev_disable_commit && !*peer->dev_disable_commit) { peer->commit_timer = NULL; @@ -1324,7 +1699,10 @@ static void send_commit(struct peer *peer) * any updates. */ changed_htlcs = tal_arr(tmpctx, const struct htlc *, 0); - if (!channel_sending_commit(peer->channel, &changed_htlcs)) { + + if (peer->committed_splice_count == peer->splice_count + && !channel_sending_commit(peer->channel, &changed_htlcs)) { + status_debug("Can't send commit: nothing to send," " feechange %s (%s)" " blockheight %s (%s)", @@ -1340,54 +1718,27 @@ static void send_commit(struct peer *peer) return; } - txs = channel_txs(tmpctx, &htlc_map, direct_outputs, - &funding_wscript, peer->channel, &peer->remote_per_commit, - peer->next_index[REMOTE], REMOTE); - - htlc_sigs = - calc_commitsigs(tmpctx, peer, txs, funding_wscript, htlc_map, - peer->next_index[REMOTE], &commit_sig); - - if (direct_outputs[LOCAL] != NULL) { - pbase = penalty_base_new(tmpctx, peer->next_index[REMOTE], - txs[0], direct_outputs[LOCAL]); - - /* Add the penalty_base to our in-memory list as well, so we - * can find it again later. */ - tal_arr_expand(&peer->pbases, tal_steal(peer, pbase)); - } else - pbase = NULL; - -#if DEVELOPER - if (peer->dev_disable_commit) { - (*peer->dev_disable_commit)--; - if (*peer->dev_disable_commit == 0) - status_unusual("dev-disable-commit-after: disabling"); - } -#endif - - status_debug("Telling master we're about to commit..."); - /* Tell master to save this next commit to database, then wait. */ - msg = sending_commitsig_msg(NULL, peer->next_index[REMOTE], - pbase, - peer->channel->fee_states, - peer->channel->blockheight_states, - changed_htlcs, - &commit_sig, - htlc_sigs); - /* Message is empty; receiving it is the point. */ - master_wait_sync_reply(tmpctx, peer, take(msg), - WIRE_CHANNELD_SENDING_COMMITSIG_REPLY); + msgs[0] = send_commit_part(peer, &peer->channel->funding, + peer->channel->funding_sats, changed_htlcs, + true); - status_debug("Sending commit_sig with %zu htlc sigs", - tal_count(htlc_sigs)); + /* Loop over current inflights + * BOLT #2: + * MUST send a commitsigs for each splice in progress, in increasing feerate order. + */ + for (u32 i = 0; i < tal_count(peer->inflights); i++) + tal_arr_expand(&msgs, + send_commit_part(peer, + &peer->inflights[i].outpoint, + peer->inflights[i].amnt, + changed_htlcs, false)); peer->next_index[REMOTE]++; - msg = towire_commitment_signed(NULL, &peer->channel_id, - &commit_sig.s, - raw_sigs(tmpctx, htlc_sigs)); - peer_write(peer->pps, take(msg)); + for(u32 i = 0; i < tal_count(msgs); i++) + peer_write(peer->pps, take(msgs[i])); + + peer->committed_splice_count = peer->splice_count; maybe_send_shutdown(peer); @@ -1514,7 +1865,8 @@ static void send_revocation(struct peer *peer, const struct htlc **changed_htlcs, const struct bitcoin_tx *committx, const struct secret *old_secret, - const struct pubkey *next_point) + const struct pubkey *next_point, + const struct commitsig **splice_commitsigs) { struct changed_htlc *changed; struct fulfilled_htlc *fulfilled; @@ -1560,42 +1912,94 @@ static void send_revocation(struct peer *peer, fulfilled, failed, changed, - committx); + committx, + splice_commitsigs); master_wait_sync_reply(tmpctx, peer, take(msg_for_master), WIRE_CHANNELD_GOT_COMMITSIG_REPLY); + peer->splice_await_commitment_succcess = false; + /* Now we can finally send revoke_and_ack to peer */ peer_write(peer->pps, take(msg)); } -static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) +/* Calling `handle_peer_commit_sig` with a `commit_index` of 0 and + * `changed_htlcs` of NULL will process the message, then read & process coming + * consecutive commitment messages equal to the number of inflight splices. */ +static struct commitsig *handle_peer_commit_sig(struct peer *peer, + const u8 *msg, + u32 commit_index, + const struct htlc **changed_htlcs) { + struct commitsig *result; struct channel_id channel_id; struct bitcoin_signature commit_sig; secp256k1_ecdsa_signature *raw_sigs; struct bitcoin_signature *htlc_sigs; struct pubkey remote_htlckey; struct bitcoin_tx **txs; - const struct htlc **htlc_map, **changed_htlcs; + const struct htlc **htlc_map; const u8 *funding_wscript; size_t i; struct simple_htlc **htlcs; const u8 * msg2; + u8 *splice_msg; + int type; + struct bitcoin_outpoint outpoint; + struct amount_sat funding_sats; + struct channel_id active_id; + const struct commitsig **commitsigs; - changed_htlcs = tal_arr(msg, const struct htlc *, 0); - if (!channel_rcvd_commit(peer->channel, &changed_htlcs)) { - /* BOLT #2: - * - * A sending node: - * - MUST NOT send a `commitment_signed` message that does not - * include any updates. - */ - status_debug("Oh hi LND! Empty commitment at #%"PRIu64, - peer->next_index[LOCAL]); - if (peer->last_empty_commitment == peer->next_index[LOCAL] - 1) - peer_failed_warn(peer->pps, &peer->channel_id, - "commit_sig with no changes (again!)"); - peer->last_empty_commitment = peer->next_index[LOCAL]; + struct tlv_commitment_signed_tlvs *cs_tlv + = tlv_commitment_signed_tlvs_new(tmpctx); + if (!fromwire_commitment_signed(tmpctx, msg, + &channel_id, &commit_sig.s, &raw_sigs, + &cs_tlv)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Bad commit_sig %s", tal_hex(msg, msg)); + + /* Until we have a valid commitment signed, we safely drop commitments + * we don't recognize. */ + derive_channel_id(&active_id, &peer->channel->funding); + if (peer->splice_await_commitment_succcess + && !tal_count(peer->inflights) && cs_tlv && cs_tlv->splice_info) { + if (!channel_id_eq(&active_id, cs_tlv->splice_info)) { + status_info("Ignoring stale commit_sig for channel_id" + " %s, as %s is locked in now.", + type_to_string(tmpctx, struct channel_id, + cs_tlv->splice_info), + type_to_string(tmpctx, struct channel_id, + &active_id)); + return NULL; + } + } + + // In a race we can get here with a commitsig with too many splcies attached. + // In that case we ignore the main commit msg for the old funding tx, and + // for the splice candidates that didnt win. But we must listen to the one + // that is for the winning splice candidate + + //DTODO Q: does channel_rcvd_commit have a side effect + // A: Yes, it increments the htlc state counter + if (!changed_htlcs) { + changed_htlcs = tal_arr(msg, const struct htlc *, 0); + if (!channel_rcvd_commit(peer->channel, &changed_htlcs) + && peer->splice_count == peer->revoked_splice_count) { + /* BOLT #2: + * + * A sending node: + * - MUST NOT send a `commitment_signed` message that does not + * include any updates. + * + * DTODO: Update this bolt reference with the splice PR addition + */ + status_debug("Oh hi LND! Empty commitment at #%"PRIu64, + peer->next_index[LOCAL]); + if (peer->last_empty_commitment == peer->next_index[LOCAL] - 1) + peer_failed_warn(peer->pps, &peer->channel_id, + "commit_sig with no changes (again!)"); + peer->last_empty_commitment = peer->next_index[LOCAL]; + } } /* We were supposed to check this was affordable as we go. */ @@ -1608,19 +2012,22 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) LOCAL))); } - if (!fromwire_commitment_signed(tmpctx, msg, - &channel_id, &commit_sig.s, &raw_sigs)) - peer_failed_warn(peer->pps, &peer->channel_id, - "Bad commit_sig %s", tal_hex(msg, msg)); /* SIGHASH_ALL is implied. */ commit_sig.sighash_type = SIGHASH_ALL; htlc_sigs = unraw_sigs(tmpctx, raw_sigs, channel_has(peer->channel, OPT_ANCHOR_OUTPUTS)); - txs = - channel_txs(tmpctx, &htlc_map, NULL, - &funding_wscript, peer->channel, &peer->next_local_per_commit, - peer->next_index[LOCAL], LOCAL); + outpoint = peer->channel->funding; + funding_sats = peer->channel->funding_sats; + if (commit_index) { + outpoint = peer->inflights[commit_index - 1].outpoint; + funding_sats = peer->inflights[commit_index - 1].amnt; + } + + txs = channel_splice_txs(tmpctx, &outpoint, funding_sats, &htlc_map, + NULL, &funding_wscript, peer->channel, + &peer->next_local_per_commit, + peer->next_index[LOCAL], LOCAL); /* Set the commit_sig on the commitment tx psbt */ if (!psbt_input_set_signature(txs[0]->psbt, 0, @@ -1652,7 +2059,10 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) &peer->channel->funding_pubkey[REMOTE], &commit_sig)) { dump_htlcs(peer->channel, "receiving commit_sig"); peer_failed_warn(peer->pps, &peer->channel_id, - "Bad commit_sig signature %"PRIu64" %s for tx %s wscript %s key %s feerate %u", + "Bad commit_sig signature %"PRIu64" %s for tx" + " %s wscript %s key %s feerate %u. Cur funding" + " %s, splice_info: %s, race_await_commit: %s," + " inflight splice count: %zu", peer->next_index[LOCAL], type_to_string(msg, struct bitcoin_signature, &commit_sig), @@ -1661,7 +2071,15 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) type_to_string(msg, struct pubkey, &peer->channel->funding_pubkey [REMOTE]), - channel_feerate(peer->channel, LOCAL)); + channel_feerate(peer->channel, LOCAL), + type_to_string(tmpctx, struct channel_id, + &active_id), + type_to_string(tmpctx, struct channel_id, + (cs_tlv ? cs_tlv->splice_info + : NULL)), + peer->splice_await_commitment_succcess ? "yes" + : "no", + tal_count(peer->inflights)); } /* BOLT #2: @@ -1705,6 +2123,19 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) status_debug("Received commit_sig with %zu htlc sigs", tal_count(htlc_sigs)); + /* First pass some common error scenarios for nicer log outputs */ + if (peer->splice_count) { + if (!cs_tlv) + peer_failed_warn(peer->pps, &peer->channel_id, + "Bad commitment_signed mesage" + " without a splice commit sig" + " section during a splice."); + if (tal_count(peer->inflights) != peer->splice_count) + peer_failed_warn(peer->pps, &peer->channel_id, + "Internal splice inflight counting " + "error"); + } + /* Validate the counterparty's signatures, returns prior per_commitment_secret. */ htlcs = collect_htlcs(NULL, htlc_map); msg2 = towire_hsmd_validate_commitment_tx(NULL, @@ -1723,16 +2154,50 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) "Reading validate_commitment_tx reply: %s", tal_hex(tmpctx, msg2)); + /* Only the parent call continues from here. + * Return for all child calls. */ + if(commit_index) { + result = tal(tmpctx, struct commitsig); + result->tx = tal_steal(result, txs[0]); + result->commit_signature = commit_sig; + result->htlc_signatures = tal_steal(result, htlc_sigs); + return result; + } + + commitsigs = tal_arr(tmpctx, const struct commitsig*, 0); + /* We expect multiple consequtive commit_sig messages if we have + * inflight splices. Since consequtive is requred, we recurse for + * each expected message, blocking until all are received. */ + for (i = 0; i < tal_count(peer->inflights); i++) { + splice_msg = peer_read(tmpctx, peer->pps); + /* Check type for cleaner failure message */ + type = fromwire_peektype(msg); + if (type != WIRE_COMMITMENT_SIGNED) + peer_failed_err(peer->pps, &peer->channel_id, + "Expected splice related " + "WIRE_COMMITMENT_SIGNED but got %s", + peer_wire_name(type)); + tal_arr_expand(&commitsigs, + handle_peer_commit_sig(peer, splice_msg, i + 1, + changed_htlcs)); + } + + peer->revoked_splice_count = peer->splice_count; + send_revocation(peer, &commit_sig, htlc_sigs, changed_htlcs, txs[0], - old_secret, &next_point); + old_secret, &next_point, commitsigs); - /* We may now be quiescent on our side. */ + /* STFU can't be activated during pending updates. + * With updates finish let's handle a potentially queued stfu request. + */ maybe_send_stfu(peer); /* This might have synced the feerates: if so, we may want to * update */ if (want_fee_update(peer, NULL)) start_commit_timer(peer); + + return NULL; } /* Pops the penalty base for the given commitnum from our internal list. There @@ -1780,6 +2245,7 @@ static u8 *got_revoke_msg(struct peer *peer, u64 revoke_num, pbase = penalty_base_by_commitnum(tmpctx, peer, revoke_num); if (pbase) { + /* DTODO we need penalty tx's per splice candidate */ ptx = penalty_tx_create( NULL, peer->channel, peer->feerate_penalty, peer->final_index, peer->final_ext_key, @@ -1876,7 +2342,11 @@ static void handle_peer_revoke_and_ack(struct peer *peer, const u8 *msg) type_to_string(tmpctx, struct pubkey, &peer->old_remote_per_commit)); - /* We may now be quiescent on our side. */ + peer->splice_await_commitment_succcess = false; + + /* STFU can't be activated during pending updates. + * With updates finish let's handle a potentially queued stfu request. + */ maybe_send_stfu(peer); start_commit_timer(peer); @@ -2016,6 +2486,9 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown) struct tlv_shutdown_tlvs *tlvs; struct bitcoin_outpoint *wrong_funding; + /* DTODO: Ensure `shutdown` follows new splice related rules once + * completed in the spec */ + /* Disable the channel. */ send_channel_update(peer, ROUTING_FLAGS_DISABLED); @@ -2112,11 +2585,14 @@ static void handle_unexpected_tx_sigs(struct peer *peer, const u8 *msg) struct channel_id cid; struct bitcoin_txid txid; + struct tlv_txsigs_tlvs *txsig_tlvs = tlv_txsigs_tlvs_new(tmpctx); + /* In a rare case, a v2 peer may re-send a tx_sigs message. * This happens when they've/we've exchanged channel_ready, * but they did not receive our channel_ready. */ if (!fromwire_tx_signatures(tmpctx, msg, &cid, &txid, - cast_const3(struct witness_stack ***, &ws))) + cast_const3(struct witness_stack ***, &ws), + &txsig_tlvs)) peer_failed_warn(peer->pps, &peer->channel_id, "Bad tx_signatures %s", tal_hex(msg, msg)); @@ -2199,68 +2675,1338 @@ static void handle_unexpected_reestablish(struct peer *peer, const u8 *msg) &channel_id)); } -static void peer_in(struct peer *peer, const u8 *msg) +static bool is_openers(const struct wally_map *unknowns) { - enum peer_wire type = fromwire_peektype(msg); + /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: + * The sending node: ... + * - if is the *initiator*: + * - MUST send even `serial_id`s + * - if is the *non-initiator*: + * - MUST send odd `serial_id`s + */ + u64 serial_id; + if (!psbt_get_serial_id(unknowns, &serial_id)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "PSBTs must have serial_ids set"); - if (handle_peer_error(peer->pps, &peer->channel_id, msg)) - return; + return serial_id % 2 == TX_INITIATOR; +} - /* Must get channel_ready before almost anything. */ - if (!peer->channel_ready[REMOTE]) { - if (type != WIRE_CHANNEL_READY - && type != WIRE_SHUTDOWN - /* We expect these for v2 !! */ - && type != WIRE_TX_SIGNATURES - /* lnd sends these early; it's harmless. */ - && type != WIRE_UPDATE_FEE - && type != WIRE_ANNOUNCEMENT_SIGNATURES) { +static bool do_i_sign_first(struct peer *peer, struct wally_psbt *psbt, + enum tx_role our_role) +{ + if (peer->splice_force_sign_first) + return true; + + struct amount_sat opener_in = AMOUNT_SAT(0); + struct amount_sat accepter_in = AMOUNT_SAT(0); + + for (int i = 0; i < psbt->tx->num_inputs; i++) { + struct amount_sat *in = is_openers(&psbt->inputs[i].unknowns) ? + &opener_in : &accepter_in; + if (!amount_sat_add(in, *in, psbt_input_get_amount(psbt, i))) peer_failed_warn(peer->pps, &peer->channel_id, - "%s (%u) before funding locked", - peer_wire_name(type), type); - } + "Unable to add input amounts for " + "signing order"); } - switch (type) { - case WIRE_CHANNEL_READY: - handle_peer_channel_ready(peer, msg); - return; - case WIRE_ANNOUNCEMENT_SIGNATURES: - handle_peer_announcement_signatures(peer, msg); - return; - case WIRE_UPDATE_ADD_HTLC: - handle_peer_add_htlc(peer, msg); - return; - case WIRE_COMMITMENT_SIGNED: - handle_peer_commit_sig(peer, msg); - return; - case WIRE_UPDATE_FEE: - handle_peer_feechange(peer, msg); - return; - case WIRE_UPDATE_BLOCKHEIGHT: - handle_peer_blockheight_change(peer, msg); - return; - case WIRE_REVOKE_AND_ACK: - handle_peer_revoke_and_ack(peer, msg); - return; - case WIRE_UPDATE_FULFILL_HTLC: - handle_peer_fulfill_htlc(peer, msg); - return; - case WIRE_UPDATE_FAIL_HTLC: - handle_peer_fail_htlc(peer, msg); - return; - case WIRE_UPDATE_FAIL_MALFORMED_HTLC: - handle_peer_fail_malformed_htlc(peer, msg); - return; - case WIRE_SHUTDOWN: - handle_peer_shutdown(peer, msg); - return; + if (amount_sat_less(accepter_in, opener_in)) + return our_role == TX_ACCEPTER; -#if EXPERIMENTAL_FEATURES + if (amount_sat_less(opener_in, accepter_in)) + return our_role == TX_INITIATOR; + + /* Current tiebreaker is initiator goes first but may change as signing + * order spec is finalized */ + return our_role == TX_INITIATOR; +} + +static struct wally_psbt *next_splice_step(const tal_t *ctx, + struct interactivetx_context *ictx) +{ + /* DTODO: add plugin wrapper for accepter side of splice to add to the + * negotiated splice. */ + if (ictx->our_role == TX_ACCEPTER) + return NULL; + + return ictx->desired_psbt; +} + +/* The question of "who signs splice commitments first" is the same order as the + * splice `tx_signature`s are. This function handles sending & receiving the + * required commitments as part of the splicing process. */ +static void interactive_send_commitments(struct peer *peer, + struct wally_psbt *psbt, + enum tx_role our_role) +{ + const u8 *msg; + enum peer_wire type; + bool got_commit = false; + + if (do_i_sign_first(peer, psbt, our_role)) { + + status_debug("Splice %s: we commit first", + our_role == TX_INITIATOR ? "initiator" : "accepter"); + + send_commit(peer); + + msg = peer_read(tmpctx, peer->pps); + type = fromwire_peektype(msg); + /* If both sides commit simultaneously, that's fine. */ + if (type == WIRE_COMMITMENT_SIGNED) { + got_commit = true; + handle_peer_commit_sig(peer, msg, 0, NULL); + msg = peer_read(tmpctx, peer->pps); + type = fromwire_peektype(msg); + } + if (type != WIRE_REVOKE_AND_ACK) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing got incorrect message from peer: %s " + "(should be WIRE_REVOKE_AND_ACK) [%s]", + peer_wire_name(type), + sanitize_error(tmpctx, msg, + &peer->channel_id)); + handle_peer_revoke_and_ack(peer, msg); + } + + if (!got_commit) { + msg = peer_read(tmpctx, peer->pps); + type = fromwire_peektype(msg); + if (type != WIRE_COMMITMENT_SIGNED) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing got incorrect message from " + "peer: %s (should be " + "WIRE_COMMITMENT_SIGNED)", + peer_wire_name(type)); + handle_peer_commit_sig(peer, msg, 0, NULL); + } + + if (!do_i_sign_first(peer, psbt, our_role)) { + + status_debug("Splice %s: we commit second", + our_role == TX_INITIATOR ? "initiator" : "accepter"); + + send_commit(peer); + + msg = peer_read(tmpctx, peer->pps); + type = fromwire_peektype(msg); + if (type != WIRE_REVOKE_AND_ACK) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing got incorrect message from peer: %s " + "(should be WIRE_REVOKE_AND_ACK)", + peer_wire_name(type)); + + handle_peer_revoke_and_ack(peer, msg); + } +} + +static struct wally_tx_output *find_channel_output(struct peer *peer, + struct wally_psbt *psbt, + int *chan_output_index) +{ + const u8 *wit_script; + u8 *scriptpubkey; + + wit_script = bitcoin_redeem_2of2(tmpctx, + &peer->channel->funding_pubkey[0], + &peer->channel->funding_pubkey[1]); + + scriptpubkey = scriptpubkey_p2wsh(psbt, wit_script); + + for (int i = 0; i < psbt->tx->num_outputs; i++) { + if (memeq(psbt->tx->outputs[i].script, + psbt->tx->outputs[i].script_len, + scriptpubkey, + tal_bytelen(scriptpubkey))) { + if (chan_output_index) + *chan_output_index = i; + return &psbt->tx->outputs[i]; + } + } + + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to find channel output"); + if (chan_output_index) + *chan_output_index = -1; + return NULL; +} + +static size_t calc_weight(enum tx_role role, struct wally_psbt *psbt) +{ + size_t weight = 0; + + if (role == TX_INITIATOR) + weight += bitcoin_tx_core_weight(psbt->num_inputs, + psbt->num_outputs); + + for (size_t i = 0; i < psbt->num_inputs; i++) + if (is_openers(&psbt->inputs[i].unknowns)) { + if (role == TX_INITIATOR) + weight += psbt_input_weight(psbt, i); + } + else + if (role != TX_INITIATOR) + weight += psbt_input_weight(psbt, i); + + return weight; +} + +/* Returns the total channel funding output amount if all checks pass */ +static struct amount_sat check_balances(struct peer *peer, + enum tx_role our_role, + struct wally_psbt *psbt, + int chan_output_index) +{ + struct amount_sat funding_amount, total_in, change_out, + opener_in, opener_out, + accepter_in, accepter_out, + initiator_fee, accepter_fee, + min_initiator_fee, min_accepter_fee, + max_initiator_fee, max_accepter_fee; + bool opener = our_role == TX_INITIATOR; + u8 *msg; + + total_in = AMOUNT_SAT(0); + opener_in = AMOUNT_SAT(0); + accepter_in = AMOUNT_SAT(0); + + for (int i = 0; i < psbt->tx->num_inputs; i++) { + struct amount_sat amount = psbt_input_get_amount(psbt, i); + bool res; + if (!amount.satoshis) + peer_failed_warn(peer->pps, &peer->channel_id, + "Input %d of splice does not have an" + " input amount", + i); + if (!amount_sat_add(&total_in, total_in, amount)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to amount_sat_add input" + " amounts"); + /* amount_sat_add would have failed above so no need to check */ + if (is_openers(&psbt->inputs[i].unknowns)) + res = amount_sat_add(&opener_in, opener_in, amount); + else + res = amount_sat_add(&accepter_in, accepter_in, amount); + assert(res); + } + + change_out = AMOUNT_SAT(0); + opener_out = AMOUNT_SAT(0); + accepter_out = AMOUNT_SAT(0); + + for (int i = 0; i < psbt->tx->num_outputs; i++) { + struct amount_sat amount = psbt_output_get_amount(psbt, i); + bool res; + if (i == chan_output_index) + continue; + + if (!amount_sat_add(&change_out, change_out, amount)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to amount_sat_add output amounts"); + /* amount_sat_add would have already failed above */ + if (is_openers(&psbt->outputs[i].unknowns)) + res = amount_sat_add(&opener_out, opener_out, amount); + else + res = amount_sat_add(&accepter_out, accepter_out, amount); + assert(res); + } + + /* Calculate total channel output amount */ + if (!amount_sat_add(&funding_amount, + peer->splice_opener_funding, + peer->splice_accepter_funding)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to calculate channel amount"); + + min_initiator_fee = amount_tx_fee(peer->splice_feerate_per_kw, + calc_weight(TX_INITIATOR, psbt)); + min_accepter_fee = amount_tx_fee(peer->splice_feerate_per_kw, + calc_weight(TX_ACCEPTER, psbt)); + + /* As a safeguard max feerate is checked (only) locally, if it's + * particularly high we fail and tell the user but allow them to + * override with `splice_force_feerate` */ + max_accepter_fee = amount_tx_fee(peer->feerate_max, + calc_weight(TX_ACCEPTER, psbt)); + max_initiator_fee = amount_tx_fee(peer->feerate_max, + calc_weight(TX_INITIATOR, psbt)); + + /* Calculate intiator fee contribution */ + if (!amount_sat_sub(&initiator_fee, opener_in, opener_out)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to calculate intiator fee"); + /* An extra check for cleaner log messages */ + if (amount_sat_less(initiator_fee, peer->splice_opener_funding)) { + msg = towire_channeld_splice_funding_error(NULL, initiator_fee, + peer->splice_opener_funding, + true); + wire_sync_write(MASTER_FD, take(msg)); + peer_failed_warn(peer->pps, &peer->channel_id, + "Initiator funding is less than commited " + "amount. Accepter adding %s and taking %s out " + " and they committed to %s.", + fmt_amount_sat(tmpctx, opener_in), + fmt_amount_sat(tmpctx, opener_out), + fmt_amount_sat(tmpctx, peer->splice_opener_funding)); + } + if (!amount_sat_sub(&initiator_fee, initiator_fee, + peer->splice_opener_funding)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to calculate intiator fee."); + + /* Calculate accepter fee contribution */ + if (!amount_sat_sub(&accepter_fee, accepter_in, accepter_out)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to calculate accepter fee"); + /* An extra check for cleaner log messages */ + if (amount_sat_less(accepter_fee, peer->splice_accepter_funding)) { + msg = towire_channeld_splice_funding_error(NULL, accepter_fee, + peer->splice_accepter_funding, + false); + wire_sync_write(MASTER_FD, take(msg)); + peer_failed_warn(peer->pps, &peer->channel_id, + "Accepter funding is less than commited " + "amount. Accepter adding %s and taking %s out " + " and they committed to %s.", + fmt_amount_sat(tmpctx, accepter_in), + fmt_amount_sat(tmpctx, accepter_out), + fmt_amount_sat(tmpctx, peer->splice_accepter_funding)); + } + if (!amount_sat_sub(&accepter_fee, accepter_fee, + peer->splice_accepter_funding)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to calculate accepter fee."); + + /* Check intiator fee */ + if (amount_sat_less(initiator_fee, min_initiator_fee)) { + msg = towire_channeld_splice_feerate_error(NULL, initiator_fee, + false); + wire_sync_write(MASTER_FD, take(msg)); + peer_failed_warn(peer->pps, &peer->channel_id, + "%s fee was too low", opener ? "Our" : "Your"); + } + if (!peer->splice_force_feerate && opener + && amount_sat_greater(initiator_fee, max_initiator_fee)) { + msg = towire_channeld_splice_feerate_error(NULL, initiator_fee, + true); + wire_sync_write(MASTER_FD, take(msg)); + /* DTODO: Swap `peer_failed_warn` out for `tx_abort` */ + peer_failed_warn(peer->pps, &peer->channel_id, + "Our own fee was too high"); + } + /* Check accepter fee */ + if (amount_sat_less(accepter_fee, min_accepter_fee)) { + msg = towire_channeld_splice_feerate_error(NULL, accepter_fee, + false); + wire_sync_write(MASTER_FD, take(msg)); + peer_failed_warn(peer->pps, &peer->channel_id, + "%s fee was too low", opener ? "Your" : "Our"); + } + if (!peer->splice_force_feerate && !opener + && amount_sat_greater(accepter_fee, max_accepter_fee)) { + msg = towire_channeld_splice_feerate_error(NULL, accepter_fee, + true); + wire_sync_write(MASTER_FD, take(msg)); + /* DTODO: Swap `peer_failed_warn` out for `tx_abort` */ + peer_failed_warn(peer->pps, &peer->channel_id, + "Our own fee was too high"); + } + + return funding_amount; +} + +static void reset_splice(struct peer *peer) +{ + peer->splice_opener_funding = AMOUNT_SAT(0); + peer->splice_accepter_funding = AMOUNT_SAT(0); + peer->splice_feerate_per_kw = 0; + peer->splice_force_feerate = false; + peer->splice_force_sign_first = false; + peer->on_stfu_success = NULL; + peer->tx_add_input_count = 0; + peer->tx_add_output_count = 0; + peer->current_psbt = NULL; + peer->received_tx_complete = false; +} + +/* ACCEPTER side of the splice. Here we handle all the accepter's steps for the + * splice. Since the channel must be in STFU mode we block the daemon here until + * the splice is finished or aborted. */ +static void splice_accepter(struct peer *peer, const u8 *inmsg) +{ + const u8 *wit_script; + const u8 *msg, *sigmsg; + u8 **wit_stack; + enum peer_wire type; + struct interactivetx_context *ictx; + struct witness_stack **inws, **outws; + struct channel_id cid; + struct bitcoin_tx *final_tx; + struct bitcoin_txid txid; + int splice_funding_index = -1; + struct bitcoin_blkid genesis_blockhash; + struct channel_id channel_id; + struct amount_sat both_amount; + u32 funding_feerate_perkw; + u32 locktime; + struct pubkey splice_remote_pubkey; + char *error; + struct bitcoin_outpoint outpoint; + struct bitcoin_tx *bitcoin_tx; + struct wally_tx_output *new_chan_outpoint; + struct bitcoin_signature splice_sig; + u8 der[73]; + size_t der_len; + struct tlv_txsigs_tlvs *our_txsigs_tlvs, *their_txsigs_tlvs; + int chan_output_index; + struct bitcoin_signature their_sig; + struct pubkey *their_pubkey; + + ictx = new_interactivetx_context(tmpctx, TX_ACCEPTER, + peer->pps, peer->channel_id); + + if (!fromwire_splice(inmsg, + &channel_id, + &genesis_blockhash, + &peer->splice_opener_funding, + &funding_feerate_perkw, + &locktime, + &splice_remote_pubkey)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Bad wire_splice %s", tal_hex(tmpctx, inmsg)); + + if (!is_stfu_active(peer)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Must be in STFU mode before intiating splice"); + + if (!bitcoin_blkid_eq(&genesis_blockhash, &chainparams->genesis_blockhash)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Bad splice blockhash"); + + if (!channel_id_eq(&channel_id, &peer->channel_id)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splice internal error: mismatched channelid"); + + if (!pubkey_eq(&splice_remote_pubkey, + &peer->channel->funding_pubkey[REMOTE])) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splice doesnt support changing pubkeys"); + + /* TODO: Add plugin hook for user to adjust accepter amount */ + peer->splice_accepter_funding = amount_msat_to_sat_round(peer->channel->view->owed[LOCAL]); + + msg = towire_splice_ack(tmpctx, + &peer->channel_id, + &chainparams->genesis_blockhash, + peer->splice_accepter_funding, + &peer->channel->funding_pubkey[LOCAL]); + + peer_write(peer->pps, take(msg)); + + /* Now we wait for the other side to go first. + * + * BOLT #2: + * The receiver of `splice_ack`: + * - MUST begin splice negotiation. + */ + + ictx->next_update_fn = next_splice_step; + ictx->desired_psbt = NULL; + ictx->pause_when_complete = false; + + error = process_interactivetx_updates(tmpctx, ictx, NULL); + if (error) + peer_failed_err(peer->pps, &peer->channel_id, + "Interactive splicing error: %s", error); + + /* DTODO validate locktime */ + ictx->current_psbt->tx->locktime = locktime; + + wit_script = bitcoin_redeem_2of2(tmpctx, + &peer->channel->funding_pubkey[1], + &peer->channel->funding_pubkey[0]); + + for (int i = 0; i < ictx->current_psbt->num_inputs; i++) { + struct wally_tx_input *in = + &ictx->current_psbt->tx->inputs[i]; + + if (0 != memcmp(in->txhash, + &peer->channel->funding.txid, + sizeof(in->txhash))) + continue; + + if (peer->channel->funding.n == in->index) { + splice_funding_index = i; + break; + } + } + + if (splice_funding_index == -1) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to find splice funding tx"); + + new_chan_outpoint = find_channel_output(peer, ictx->current_psbt, + &chan_output_index); + + both_amount = check_balances(peer, TX_ACCEPTER, ictx->current_psbt, + chan_output_index); + new_chan_outpoint->satoshi = both_amount.satoshis; + + psbt_elements_normalize_fees(ictx->current_psbt); + + psbt_txid(tmpctx, ictx->current_psbt, &outpoint.txid, NULL); + + outpoint.n = chan_output_index; + + psbt_finalize(ictx->current_psbt); + + status_debug("Splice accepter adding inflight: %s", psbt_to_b64(tmpctx, ictx->current_psbt)); + + msg = towire_channeld_add_inflight(NULL, + &outpoint.txid, + outpoint.n, + funding_feerate_perkw, + both_amount, + peer->splice_accepter_funding, + ictx->current_psbt); + + master_wait_sync_reply(tmpctx, peer, take(msg), + WIRE_CHANNELD_GOT_INFLIGHT); + + struct inflight new_inflight; + + new_inflight.outpoint = outpoint; + new_inflight.amnt = both_amount; + new_inflight.local_funding = peer->splice_accepter_funding; + + if (peer->inflights) + tal_arr_expand(&peer->inflights, new_inflight); + else { + peer->inflights = tal_arr(peer, struct inflight, 1); + peer->inflights[0] = new_inflight; + } + + peer->splice_count++; + + interactive_send_commitments(peer, ictx->current_psbt, TX_ACCEPTER); + + psbt_sort_by_serial_id(ictx->current_psbt); + + /* DTODO Validate splice tx takes none of our funds in either: + * 1) channel balance + * 2) other side sneakily adding other outputs we own + */ + + splice_sig.sighash_type = SIGHASH_ALL; + + bitcoin_tx = bitcoin_tx_with_psbt(tmpctx, ictx->current_psbt); + + status_info("Splice[ACK] signing tx: %s", tal_hex(tmpctx, linearize_tx(tmpctx, bitcoin_tx))); + + msg = towire_hsmd_sign_splice_tx(tmpctx, bitcoin_tx, + &peer->channel->funding_pubkey[REMOTE], + splice_funding_index); + + msg = hsm_req(tmpctx, take(msg)); + if (!fromwire_hsmd_sign_tx_reply(msg, &splice_sig)) + status_failed(STATUS_FAIL_HSM_IO, + "Reading sign_splice_tx reply: %s", + tal_hex(tmpctx, msg)); + + /* Set the splice_sig on the splice funding tx psbt */ + if (!psbt_input_set_signature(ictx->current_psbt, splice_funding_index, + &peer->channel->funding_pubkey[LOCAL], + &splice_sig)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to set signature internally " + "funding_index: %d " + "my pubkey: %s " + "my signature: %s " + "psbt: %s", + splice_funding_index, + type_to_string(tmpctx, struct pubkey, &peer->channel->funding_pubkey[LOCAL]), + type_to_string(tmpctx, struct bitcoin_signature, &splice_sig), + type_to_string(tmpctx, struct wally_psbt, ictx->current_psbt)); + + + /* DTODO: Replace below with psbt_to_witness_stacks */ + + outws = tal_arr(tmpctx, struct witness_stack *, 1); + + outws[0] = tal(tmpctx, struct witness_stack); + outws[0]->witness_elements = tal_arr(tmpctx, struct witness_element *, + 1); + outws[0]->witness_elements[0] = tal(tmpctx, struct witness_element); + + der_len = signature_to_der(der, &splice_sig); + outws[0]->witness_elements[0]->witness_data = tal_dup_arr(tmpctx, u8, + der, der_len, + 0); + + our_txsigs_tlvs = tlv_txsigs_tlvs_new(tmpctx); + + der_len = signature_to_der(der, &splice_sig); + our_txsigs_tlvs->funding_outpoint_sig = tal_dup_arr(tmpctx, u8, der, + der_len, 0); + + sigmsg = towire_tx_signatures(tmpctx, &peer->channel_id, + &outpoint.txid, + (const struct witness_stack**)outws, + our_txsigs_tlvs); + + if (do_i_sign_first(peer, ictx->current_psbt, TX_ACCEPTER)) { + status_debug("Splice accepter: we sign first"); + msg = towire_channeld_update_inflight(NULL, ictx->current_psbt); + wire_sync_write(MASTER_FD, take(msg)); + peer_write(peer->pps, sigmsg); + } + + msg = peer_read(tmpctx, peer->pps); + + type = fromwire_peektype(msg); + + if (handle_peer_error(peer->pps, &peer->channel_id, msg)) + return; + + if (type != WIRE_TX_SIGNATURES) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing got incorrect message from peer: %s " + "(should be WIRE_TX_SIGNATURES)", + peer_wire_name(type)); + + their_txsigs_tlvs = tlv_txsigs_tlvs_new(tmpctx); + if (!fromwire_tx_signatures(tmpctx, msg, &cid, &txid, + cast_const3(struct witness_stack ***, &inws), + &their_txsigs_tlvs)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing bad tx_signatures %s", + tal_hex(msg, msg)); + + /* Sending TX_SIGNATURES implies the ending of stfu mode */ + end_stfu_mode(peer); + + their_sig.sighash_type = SIGHASH_ALL; + + if (!signature_from_der(their_txsigs_tlvs->funding_outpoint_sig, + tal_count(their_txsigs_tlvs->funding_outpoint_sig), + &their_sig)) { + + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing bad tx_signatures %s", + tal_hex(msg, msg)); + } + + their_pubkey = &peer->channel->funding_pubkey[REMOTE]; + + /* Set the commit_sig on the commitment tx psbt */ + if (!psbt_input_set_signature(ictx->current_psbt, + splice_funding_index, + their_pubkey, + &their_sig)) { + + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to set signature internally " + "funding_index: %d " + "pubkey: %s " + "signature: %s " + "psbt: %s", + splice_funding_index, + type_to_string(tmpctx, struct pubkey, their_pubkey), + type_to_string(tmpctx, struct bitcoin_signature, &their_sig), + type_to_string(tmpctx, struct wally_psbt, ictx->current_psbt)); + } + + psbt_input_set_witscript(ictx->current_psbt, + splice_funding_index, + wit_script); + + if (tal_count(inws) > ictx->current_psbt->num_inputs) + peer_failed_warn(peer->pps, &peer->channel_id, + "%lu too many witness elements received", + tal_count(inws) - ictx->current_psbt->num_inputs); + + /* We put the PSBT + sigs all together */ + for (size_t j = 0, i = 0; i < ictx->current_psbt->num_inputs; i++) { + struct wally_psbt_input *in = + &ictx->current_psbt->inputs[i]; + u64 in_serial; + const struct witness_element **elem; + + if (!psbt_get_serial_id(&in->unknowns, &in_serial)) { + status_broken("PSBT input %zu missing serial_id %s", + i, type_to_string(tmpctx, + struct wally_psbt, + ictx->current_psbt)); + return; + } + if (in_serial % 2 != TX_INITIATOR) + continue; + + if (i == splice_funding_index) + continue; + + if (j == tal_count(inws)) + peer_failed_warn(peer->pps, + &peer->channel_id, + "Mismatch witness stack count %s", + tal_hex(msg, msg)); + + elem = cast_const2(const struct witness_element **, + inws[j++]->witness_elements); + psbt_finalize_input(ictx->current_psbt, in, elem); + } + + final_tx = bitcoin_tx_with_psbt(tmpctx, ictx->current_psbt); + + wit_stack = bitcoin_witness_2of2(ictx->current_psbt, &splice_sig, &their_sig, + &peer->channel->funding_pubkey[LOCAL], + their_pubkey); + + bitcoin_tx_input_set_witness(final_tx, splice_funding_index, wit_stack); + + /* DTODO: validate our peer's signatures are correct */ + + msg = towire_channeld_update_inflight(NULL, ictx->current_psbt); + wire_sync_write(MASTER_FD, take(msg)); + + if (!do_i_sign_first(peer, ictx->current_psbt, TX_ACCEPTER)) { + status_debug("Splice accepter: we sign second"); + peer_write(peer->pps, sigmsg); + } + + msg = towire_channeld_splice_confirmed_signed(tmpctx, final_tx, chan_output_index); + wire_sync_write(MASTER_FD, take(msg)); + + send_channel_update(peer, 0); + + reset_splice(peer); +} + +static struct bitcoin_tx *bitcoin_tx_from_txid(struct peer *peer, + struct bitcoin_txid txid) +{ + u8 *msg; + struct bitcoin_tx *tx = NULL; + enum channeld_wire type; + + msg = towire_channeld_splice_lookup_tx(tmpctx, &txid); + + if (!wire_sync_write(MASTER_FD, msg)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Could not set sync write to master: %s", + strerror(errno)); + + msg = wire_sync_read(tmpctx, MASTER_FD); + if (!msg) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Could not set sync read from master: %s", + strerror(errno)); + + type = fromwire_peektype(msg); + + if (type != WIRE_CHANNELD_SPLICE_LOOKUP_TX_RESULT) + peer_failed_err(peer->pps, &peer->channel_id, + "Splicing got incorrect message from lightningd: %s " + "(should be WIRE_CHANNELD_SPLICE_LOOKUP_TX_RESULT)", + peer_wire_name(type)); + else if (!fromwire_channeld_splice_lookup_tx_result(tmpctx, msg, &tx)) + peer_failed_err(peer->pps, + &peer->channel_id, + "Invalid 'splice_lookup_tx_result' mesage" + " from daemon %s", tal_hex(tmpctx, msg)); + + return tx; +} + +/* splice_intiator runs when splice_ack is received by the other side. It + * handles the initial splice creation while callbacks will handle later + * stages. */ +static void splice_intiator(struct peer *peer, const u8 *inmsg) +{ + struct bitcoin_blkid genesis_blockhash; + struct channel_id channel_id; + struct pubkey splice_remote_pubkey; + size_t input_index; + const u8 *wit_script; + u8 *outmsg; + struct interactivetx_context *ictx; + struct bitcoin_tx *prev_tx; + u32 sequence = 0; + u8 *scriptPubkey; + char *error; + + ictx = new_interactivetx_context(tmpctx, TX_INITIATOR, + peer->pps, peer->channel_id); + + if (!fromwire_splice_ack(inmsg, + &channel_id, + &genesis_blockhash, + &peer->splice_accepter_funding, + &splice_remote_pubkey)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Bad wire_splice_ack %s", tal_hex(tmpctx, inmsg)); + + if (!bitcoin_blkid_eq(&genesis_blockhash, &chainparams->genesis_blockhash)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Bad splice[ACK] blockhash"); + + if (!channel_id_eq(&channel_id, &peer->channel_id)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splice[ACK] internal error: mismatched channelid"); + + if (!pubkey_eq(&splice_remote_pubkey, &peer->channel->funding_pubkey[REMOTE])) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splice[ACK] doesnt support changing pubkeys"); + + peer->received_tx_complete = false; + peer->splice_locked_ready[LOCAL] = false; + peer->splice_locked_ready[REMOTE] = false; + + ictx->next_update_fn = next_splice_step; + ictx->pause_when_complete = true; + ictx->desired_psbt = peer->current_psbt; + + /* We go first as the receiver of the ack. + * + * BOLT #2: + * The receiver of `splice_ack`: + * - MUST begin splice negotiation. + */ + + BUILD_ASSERT(NUM_SIDES == 2); + wit_script = bitcoin_redeem_2of2(tmpctx, + &peer->channel->funding_pubkey[0], + &peer->channel->funding_pubkey[1]); + + input_index = ictx->desired_psbt->tx->num_inputs; + + /* First we spend the existing channel outpoint + * + * Bolt #2 + * The initiator: + * - MUST `tx_add_input` an input which spends the current funding + * transaction output. + */ + psbt_append_input(ictx->desired_psbt, &peer->channel->funding, sequence, + NULL, wit_script, NULL); + + /* Segwit requires us to store the value of the outpoint being spent, + * so let's do that */ + scriptPubkey = scriptpubkey_p2wsh(ictx->desired_psbt, wit_script); + psbt_input_set_wit_utxo(ictx->desired_psbt, input_index, + scriptPubkey, peer->channel->funding_sats); + + /* We must loading the funding tx as our previous utxo */ + prev_tx = bitcoin_tx_from_txid(peer, peer->channel->funding.txid); + psbt_input_set_utxo(ictx->desired_psbt, input_index, prev_tx->wtx); + + /* Next we add the new channel outpoint, with a 0 amount for now. It + * will be filled in later. + * + * Bolt #2 + * The initiator: + * ... + * - MUST `tx_add_output` a zero-value output which pays to the two + * funding keys using the higher of the two `generation` fields. + */ + psbt_append_output(ictx->desired_psbt, + scriptpubkey_p2wsh(ictx->desired_psbt, wit_script), + amount_sat(0)); + + psbt_add_serials(ictx->desired_psbt, ictx->our_role); + + error = process_interactivetx_updates(tmpctx, + ictx, + &peer->received_tx_complete); + + if (error) + peer_failed_warn(peer->pps, &peer->channel_id, + "Interactive splicing_ack error: %s", error); + + psbt_add_serials(ictx->current_psbt, ictx->our_role); + + peer->tx_add_input_count = ictx->tx_add_input_count; + peer->tx_add_output_count = ictx->tx_add_output_count; + + if (peer->current_psbt != ictx->current_psbt) + tal_free(peer->current_psbt); + peer->current_psbt = tal_steal(peer, ictx->current_psbt); + + /* Return the current PSBT to the channel_control to give to user. + */ + outmsg = towire_channeld_splice_confirmed_init(NULL, + ictx->current_psbt); + wire_sync_write(MASTER_FD, take(outmsg)); +} + +/* This occurs when the user has marked they are done making changes to the + * PSBT. Now we continually send `tx_complete` and intake our peer's changes + * inside `process_interactivetx_updates`. Once they are onboard indicated + * with their sending of `tx_complete` we clean up the final PSBT and return + * to the user for their final signing steps. */ +static void splice_initiator_user_finalized(struct peer *peer) +{ + u8 *outmsg; + struct interactivetx_context *ictx; + char *error; + int chan_output_index; + struct wally_tx_output *new_chan_outpoint; + struct inflight new_inflight; + struct bitcoin_txid current_psbt_txid; + + ictx = new_interactivetx_context(tmpctx, TX_INITIATOR, + peer->pps, peer->channel_id); + + ictx->next_update_fn = next_splice_step; + ictx->pause_when_complete = false; + ictx->current_psbt = peer->current_psbt; + ictx->desired_psbt = ictx->current_psbt; + ictx->tx_add_input_count = peer->tx_add_input_count; + ictx->tx_add_output_count = peer->tx_add_output_count; + + error = process_interactivetx_updates(tmpctx, ictx, + &peer->received_tx_complete); + if (error) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splice finalize error: %s", error); + + /* With pause_when_complete fase, this assert should never fail */ + assert(peer->received_tx_complete); + + psbt_sort_by_serial_id(ictx->current_psbt); + + new_chan_outpoint = find_channel_output(peer, ictx->current_psbt, + &chan_output_index); + + new_chan_outpoint->satoshi = check_balances(peer, TX_INITIATOR, + ictx->current_psbt, + chan_output_index).satoshis; + + psbt_elements_normalize_fees(ictx->current_psbt); + + status_debug("Splice adding inflight: %s", + psbt_to_b64(tmpctx, ictx->current_psbt)); + + psbt_txid(tmpctx, ictx->current_psbt, ¤t_psbt_txid, NULL); + + outmsg = towire_channeld_add_inflight(tmpctx, + ¤t_psbt_txid, + chan_output_index, + peer->splice_feerate_per_kw, + amount_sat(new_chan_outpoint->satoshi), + peer->splice_opener_funding, + ictx->current_psbt); + + master_wait_sync_reply(tmpctx, peer, take(outmsg), + WIRE_CHANNELD_GOT_INFLIGHT); + + psbt_txid(tmpctx, ictx->current_psbt, &new_inflight.outpoint.txid, + NULL); + new_inflight.outpoint.n = chan_output_index; + new_inflight.amnt = amount_sat(new_chan_outpoint->satoshi); + new_inflight.local_funding = peer->splice_opener_funding; + + if (peer->inflights) + tal_arr_expand(&peer->inflights, new_inflight); + else { + peer->inflights = tal_arr(peer, struct inflight, 1); + peer->inflights[0] = new_inflight; + } + + peer->splice_count++; + + interactive_send_commitments(peer, ictx->current_psbt, TX_INITIATOR); + + status_debug("user_finalized peer->stfu_wait_single_msg: %d", (int)peer->stfu_wait_single_msg); + + peer->current_psbt = tal_steal(peer, ictx->current_psbt); + outmsg = towire_channeld_splice_confirmed_update(NULL, + ictx->current_psbt, + true); + wire_sync_write(MASTER_FD, take(outmsg)); +} + +/* During a splice the user may call splice_update mulitple times adding + * new details to the active PSBT. Each user call enters here: */ +static void splice_intiator_user_update(struct peer *peer, const u8 *inmsg) +{ + u8 *outmsg; + struct interactivetx_context *ictx; + char *error; + + ictx = new_interactivetx_context(tmpctx, TX_INITIATOR, + peer->pps, peer->channel_id); + + ictx->next_update_fn = next_splice_step; + ictx->pause_when_complete = true; + + /* Should already have a current_psbt from a previously initiated one */ + assert(peer->current_psbt); + ictx->current_psbt = peer->current_psbt; + ictx->tx_add_input_count = peer->tx_add_input_count; + ictx->tx_add_output_count = peer->tx_add_output_count; + + if (!fromwire_channeld_splice_update(ictx, inmsg, &ictx->desired_psbt)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Invalid splice update message: %s", + tal_hex(tmpctx, inmsg)); + + /* User may not have setup serial numbers on their modifeid PSBT, so we + * ensure that for them here */ + psbt_add_serials(ictx->desired_psbt, ictx->our_role); + + /* If there no are no changes, we consider the splice 'user finalized' */ + if (!interactivetx_has_changes(ictx, ictx->desired_psbt)) { + splice_initiator_user_finalized(peer); + return; + } + + error = process_interactivetx_updates(tmpctx, ictx, &peer->received_tx_complete); + if (error) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splice update error: %s", error); + + peer->tx_add_input_count = ictx->tx_add_input_count; + peer->tx_add_output_count = ictx->tx_add_output_count; + + if (peer->current_psbt != ictx->current_psbt) + tal_free(peer->current_psbt); + peer->current_psbt = tal_steal(peer, ictx->current_psbt); + + /* Peer may have modified our PSBT so we return it to the user here */ + outmsg = towire_channeld_splice_confirmed_update(NULL, + ictx->current_psbt, + false); + wire_sync_write(MASTER_FD, take(outmsg)); +} + +/* This occurs when the user has signed the final version of the PSBT. At this + * point we do a commitment transaciton round with our peer via + * `interactive_send_commitments`. + * + * Then we finalize the PSBT some more and sign away our funding output, + * place that signature in the PSBT, and pass our signature to the peer and get + * theirs back. */ +static void splice_intiator_user_signed(struct peer *peer, const u8 *inmsg) +{ + struct wally_psbt *signed_psbt; + struct bitcoin_txid current_psbt_txid, signed_psbt_txid; + struct bitcoin_tx *bitcoin_tx, *final_tx; + struct bitcoin_signature splice_sig; + struct bitcoin_signature their_sig; + struct pubkey *their_pubkey; + struct tlv_txsigs_tlvs *txsig_tlvs; + struct channel_id cid; + struct bitcoin_txid txid; + const struct witness_stack **ws; + const u8 *wit_script; + const u8 *msg; + u8 **wit_stack; + u8 *sigout_msg, *outmsg; + u8 der[73]; + size_t der_len; + int splice_funding_index = -1; + int chan_output_index; + + if (!fromwire_channeld_splice_signed(tmpctx, inmsg, &signed_psbt, &peer->splice_force_sign_first)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Invalid splice signed message: %s", + tal_hex(tmpctx, inmsg)); + + psbt_txid(tmpctx, peer->current_psbt, ¤t_psbt_txid, NULL); + psbt_txid(tmpctx, signed_psbt, &signed_psbt_txid, NULL); + + if (!bitcoin_txid_eq(&signed_psbt_txid, ¤t_psbt_txid)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Signed PSBT txid %s does match " + "current_psbt_txid %s", + type_to_string(tmpctx, struct bitcoin_txid, + &signed_psbt_txid), + type_to_string(tmpctx, struct bitcoin_txid, + ¤t_psbt_txid)); + + peer->current_psbt = tal_free(peer->current_psbt); + + wit_script = bitcoin_redeem_2of2(tmpctx, + &peer->channel->funding_pubkey[REMOTE], + &peer->channel->funding_pubkey[LOCAL]); + + find_channel_output(peer, signed_psbt, &chan_output_index); + + splice_sig.sighash_type = SIGHASH_ALL; + bitcoin_tx = bitcoin_tx_with_psbt(tmpctx, signed_psbt); + + /* Find splice_funding_index */ + for (int i = 0; i < signed_psbt->num_inputs; i++) { + struct wally_tx_input *in = &signed_psbt->tx->inputs[i]; + + if (0 != memcmp(in->txhash, + &peer->channel->funding.txid, + sizeof(in->txhash))) + continue; + + if (peer->channel->funding.n == in->index) { + splice_funding_index = i; + break; + } + } + + if (splice_funding_index == -1) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to find splice funding tx"); + + status_debug("Splice signing tx: %s", tal_hex(tmpctx, linearize_tx(tmpctx, bitcoin_tx))); + + /* Have HSMD sign over the funding tx -> splice tx */ + msg = towire_hsmd_sign_splice_tx(tmpctx, bitcoin_tx, + &peer->channel->funding_pubkey[REMOTE], + splice_funding_index); + msg = hsm_req(tmpctx, take(msg)); + if (!fromwire_hsmd_sign_tx_reply(msg, &splice_sig)) + status_failed(STATUS_FAIL_HSM_IO, + "Reading sign_splice_tx reply: %s", + tal_hex(tmpctx, msg)); + + /* Set the splice_sig on the splice funding tx psbt */ + if (!psbt_input_set_signature(signed_psbt, splice_funding_index, + &peer->channel->funding_pubkey[LOCAL], + &splice_sig)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to set signature internally " + "funding_index: %d " + "my pubkey: %s " + "my signature: %s " + "psbt: %s", + splice_funding_index, + type_to_string(tmpctx, struct pubkey, &peer->channel->funding_pubkey[LOCAL]), + type_to_string(tmpctx, struct bitcoin_signature, &splice_sig), + type_to_string(tmpctx, struct wally_psbt, signed_psbt)); + + txsig_tlvs = tlv_txsigs_tlvs_new(tmpctx); + der_len = signature_to_der(der, &splice_sig); + txsig_tlvs->funding_outpoint_sig = tal_dup_arr(tmpctx, u8, der, + der_len, 0); + + ws = psbt_to_witness_stacks(tmpctx, signed_psbt, + TX_INITIATOR, splice_funding_index); + sigout_msg = towire_tx_signatures(tmpctx, &peer->channel_id, + &signed_psbt_txid, ws, txsig_tlvs); + + if (do_i_sign_first(peer, signed_psbt, TX_INITIATOR)) { + status_debug("Splice initiator: we sign first"); + outmsg = towire_channeld_update_inflight(NULL, signed_psbt); + wire_sync_write(MASTER_FD, take(outmsg)); + peer_write(peer->pps, take(sigout_msg)); + } + + msg = peer_read(tmpctx, peer->pps); + if (handle_peer_error(peer->pps, &peer->channel_id, msg)) + return; + + if (fromwire_peektype(msg) != WIRE_TX_SIGNATURES) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing got incorrect message from peer: %s " + "(should be WIRE_TX_SIGNATURES)", + peer_wire_name(fromwire_peektype(msg))); + + if (!fromwire_tx_signatures(tmpctx, msg, &cid, &txid, + cast_const3(struct witness_stack ***, &ws), + &txsig_tlvs)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing bad tx_signatures %s", + tal_hex(msg, msg)); + + their_sig.sighash_type = SIGHASH_ALL; + + if (!signature_from_der(txsig_tlvs->funding_outpoint_sig, + tal_count(txsig_tlvs->funding_outpoint_sig), + &their_sig)) { + + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing bad tx_signatures %s", + tal_hex(msg, msg)); + } + + their_pubkey = &peer->channel->funding_pubkey[REMOTE]; + + /* Set the commit_sig on the commitment tx psbt */ + if (!psbt_input_set_signature(signed_psbt, + splice_funding_index, + their_pubkey, + &their_sig)) { + + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to set signature internally " + "funding_index: %d " + "pubkey: %s " + "signature: %s " + "psbt: %s", + splice_funding_index, + type_to_string(tmpctx, struct pubkey, their_pubkey), + type_to_string(tmpctx, struct bitcoin_signature, &their_sig), + type_to_string(tmpctx, struct wally_psbt, signed_psbt)); + } + + psbt_input_set_witscript(signed_psbt, + splice_funding_index, + wit_script); + + final_tx = bitcoin_tx_with_psbt(tmpctx, signed_psbt); + + wit_stack = bitcoin_witness_2of2(signed_psbt, &splice_sig, &their_sig, + &peer->channel->funding_pubkey[LOCAL], + their_pubkey); + + bitcoin_tx_input_set_witness(final_tx, splice_funding_index, wit_stack); + + /* DTODO: validate our peer's signatures are correct + * see closingd.c receive_offer close_tx / check_tx_sig */ + + outmsg = towire_channeld_update_inflight(NULL, signed_psbt); + wire_sync_write(MASTER_FD, take(outmsg)); + + if (!do_i_sign_first(peer, signed_psbt, TX_INITIATOR)) { + status_debug("Splice accepter: we sign first"); + peer_write(peer->pps, take(sigout_msg)); + } + + /* Sending of TX_SIGNATURE implies the end of stfu mode */ + end_stfu_mode(peer); + + outmsg = towire_channeld_update_inflight(NULL, signed_psbt); + wire_sync_write(MASTER_FD, take(outmsg)); + + if (!psbt_finalize(signed_psbt)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Splice psbt_finalize failed"); + + outmsg = towire_channeld_splice_confirmed_signed(tmpctx, final_tx, + chan_output_index); + wire_sync_write(MASTER_FD, take(outmsg)); + send_channel_update(peer, 0); + + reset_splice(peer); +} + +/* This occurs once our 'stfu' transition was successful. */ +static void handle_splice_stfu_success(struct peer *peer) +{ + u8 *msg = towire_splice(tmpctx, + &peer->channel_id, + &chainparams->genesis_blockhash, + peer->splice_opener_funding, + peer->splice_feerate_per_kw, + peer->current_psbt->tx->locktime, + &peer->channel->funding_pubkey[LOCAL]); + peer_write(peer->pps, take(msg)); +} + +/* User has begun a splice with `splice_init` command. Here we request entry + * into STFU mode, when we get it, send `splice` to our peer. + * Later the peer will send `splice_ack` and the code that starts the actual + * splice happens at that point in `splice_intiator()`. */ +static void handle_splice_init(struct peer *peer, const u8 *inmsg) +{ + peer->current_psbt = tal_free(peer->current_psbt); + + if (!fromwire_channeld_splice_init(peer, inmsg, &peer->current_psbt, + &peer->splice_opener_funding, + &peer->splice_feerate_per_kw, + &peer->splice_force_feerate)) + master_badmsg(WIRE_CHANNELD_SPLICE_INIT, inmsg); + + if (peer->on_stfu_success) + peer_failed_err(peer->pps, &peer->channel_id, + "Can't start a splice request" + "with a pending 'stfu' on the" + "channel."); + + peer->on_stfu_success = handle_splice_stfu_success; + + /* First things first we must STFU the channel */ + peer->stfu_initiator = LOCAL; + peer->stfu_request = true; + maybe_send_stfu(peer); +} + +static void peer_in(struct peer *peer, const u8 *msg) +{ + enum peer_wire type = fromwire_peektype(msg); + + if (handle_peer_error(peer->pps, &peer->channel_id, msg)) + return; + + /* Must get channel_ready before almost anything. */ + if (!peer->channel_ready[REMOTE]) { + if (type != WIRE_CHANNEL_READY + && type != WIRE_SHUTDOWN + /* We expect these for v2 !! */ + && type != WIRE_TX_SIGNATURES + /* lnd sends these early; it's harmless. */ + && type != WIRE_UPDATE_FEE + && type != WIRE_ANNOUNCEMENT_SIGNATURES) { + peer_failed_warn(peer->pps, &peer->channel_id, + "%s (%u) before funding locked", + peer_wire_name(type), type); + } + } + + /* For cleaner errors, we check message is valid during STFU mode */ + if (peer->stfu_wait_single_msg) + if (!VALID_STFU_MESSAGE(type)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Got invalid message during STFU " + "mode: %s", + peer_wire_name(type)); + + peer->stfu_wait_single_msg = false; + + switch (type) { + case WIRE_CHANNEL_READY: + handle_peer_channel_ready(peer, msg); + return; + case WIRE_ANNOUNCEMENT_SIGNATURES: + handle_peer_announcement_signatures(peer, msg); + return; + case WIRE_UPDATE_ADD_HTLC: + handle_peer_add_htlc(peer, msg); + return; + case WIRE_COMMITMENT_SIGNED: + handle_peer_commit_sig(peer, msg, 0, NULL); + return; + case WIRE_UPDATE_FEE: + handle_peer_feechange(peer, msg); + return; + case WIRE_UPDATE_BLOCKHEIGHT: + handle_peer_blockheight_change(peer, msg); + return; + case WIRE_REVOKE_AND_ACK: + handle_peer_revoke_and_ack(peer, msg); + return; + case WIRE_UPDATE_FULFILL_HTLC: + handle_peer_fulfill_htlc(peer, msg); + return; + case WIRE_UPDATE_FAIL_HTLC: + handle_peer_fail_htlc(peer, msg); + return; + case WIRE_UPDATE_FAIL_MALFORMED_HTLC: + handle_peer_fail_malformed_htlc(peer, msg); + return; + case WIRE_SHUTDOWN: + handle_peer_shutdown(peer, msg); + return; case WIRE_STFU: handle_stfu(peer, msg); return; -#endif + case WIRE_SPLICE: + splice_accepter(peer, msg); + return; + case WIRE_SPLICE_ACK: + splice_intiator(peer, msg); + return; + case WIRE_SPLICE_LOCKED: + handle_peer_splice_locked(peer, msg); + return; case WIRE_INIT: case WIRE_OPEN_CHANNEL: case WIRE_ACCEPT_CHANNEL: @@ -2462,9 +4208,11 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) htlc_sigs = calc_commitsigs(tmpctx, peer, txs, funding_wscript, htlc_map, peer->next_index[REMOTE]-1, &commit_sig); + msg = towire_commitment_signed(NULL, &peer->channel_id, &commit_sig.s, - raw_sigs(tmpctx, htlc_sigs)); + raw_sigs(tmpctx, htlc_sigs), + NULL); peer_write(peer->pps, take(msg)); /* If we have already received the revocation for the previous, the @@ -3225,32 +4973,49 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) struct short_channel_id *scid, *alias_local; struct tlv_channel_ready_tlvs *tlvs; struct pubkey point; + bool splicing; + struct bitcoin_txid txid; if (!fromwire_channeld_funding_depth(tmpctx, msg, &scid, &alias_local, - &depth)) + &depth, + &splicing, + &txid)) master_badmsg(WIRE_CHANNELD_FUNDING_DEPTH, msg); /* Too late, we're shutting down! */ if (peer->shutdown_sent[LOCAL]) return; - if (depth < peer->channel->minimum_depth) { + if (depth < peer->channel->minimum_depth) peer->depth_togo = peer->channel->minimum_depth - depth; - - } else { + else { peer->depth_togo = 0; - /* If we know an actual short_channel_id prefer to use - * that, otherwise fill in the alias. From channeld's - * point of view switching from zeroconf to an actual - * funding scid is just a reorg. */ - if (scid) - peer->short_channel_ids[LOCAL] = *scid; - else if (alias_local) - peer->short_channel_ids[LOCAL] = *alias_local; + /* For splicing we only update the short channel id on mutual + * splice lock */ + if (splicing) { + peer->splice_short_channel_id = *scid; + status_debug("Current channel id is %s, " + "splice_short_channel_id now set to %s", + type_to_string(tmpctx, + struct short_channel_id, + &peer->short_channel_ids[LOCAL]), + type_to_string(tmpctx, + struct short_channel_id, + &peer->splice_short_channel_id)); + } else { + /* If we know an actual short_channel_id prefer to use + * that, otherwise fill in the alias. From channeld's + * point of view switching from zeroconf to an actual + * funding scid is just a reorg. */ + if (scid) + peer->short_channel_ids[LOCAL] = *scid; + else if (alias_local) + peer->short_channel_ids[LOCAL] = *alias_local; + } if (!peer->channel_ready[LOCAL]) { status_debug("channel_ready: sending commit index" @@ -3272,11 +5037,25 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) peer->channel_ready[LOCAL] = true; } + else if(splicing && !peer->splice_locked_ready[LOCAL]) { + assert(scid); + + msg = towire_splice_locked(NULL, &peer->channel_id); + + peer->have_sigs[LOCAL] = false; + peer->have_sigs[REMOTE] = false; + peer->splice_locked_txid = txid; + + peer_write(peer->pps, take(msg)); + + peer->splice_locked_ready[LOCAL] = true; + check_mutual_splice_locked(peer); + } peer->announce_depth_reached = (depth >= ANNOUNCE_MIN_DEPTH); /* Send temporary or final announcements */ - channel_announcement_negotiate(peer); + channel_announcement_negotiate(peer, NULL); } billboard_update(peer); @@ -3652,10 +5431,10 @@ static void handle_dev_quiesce(struct peer *peer, const u8 *msg) master_badmsg(WIRE_CHANNELD_DEV_QUIESCE, msg); /* Don't do this twice. */ - if (peer->stfu) + if (peer->stfu_request) status_failed(STATUS_FAIL_MASTER_IO, "dev_quiesce already"); - peer->stfu = true; + peer->stfu_request = true; peer->stfu_initiator = LOCAL; maybe_send_stfu(peer); } @@ -3709,6 +5488,23 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_CHANNEL_UPDATE: handle_channel_update(peer, msg); return; + case WIRE_CHANNELD_SPLICE_INIT: + handle_splice_init(peer, msg); + return; + case WIRE_CHANNELD_SPLICE_UPDATE: + splice_intiator_user_update(peer, msg); + return; + case WIRE_CHANNELD_SPLICE_SIGNED: + splice_intiator_user_signed(peer, msg); + return; + case WIRE_CHANNELD_SPLICE_CONFIRMED_INIT: + case WIRE_CHANNELD_SPLICE_CONFIRMED_SIGNED: + case WIRE_CHANNELD_SPLICE_CONFIRMED_UPDATE: + case WIRE_CHANNELD_SPLICE_LOOKUP_TX: + case WIRE_CHANNELD_SPLICE_LOOKUP_TX_RESULT: + case WIRE_CHANNELD_SPLICE_FEERATE_ERROR: + case WIRE_CHANNELD_SPLICE_FUNDING_ERROR: + break; #if DEVELOPER case WIRE_CHANNELD_DEV_REENABLE_COMMIT: handle_dev_reenable_commit(peer); @@ -3735,6 +5531,7 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_GOT_COMMITSIG_REPLY: case WIRE_CHANNELD_GOT_REVOKE_REPLY: case WIRE_CHANNELD_GOT_CHANNEL_READY: + case WIRE_CHANNELD_GOT_SPLICE_LOCKED: case WIRE_CHANNELD_GOT_ANNOUNCEMENT: case WIRE_CHANNELD_GOT_SHUTDOWN: case WIRE_CHANNELD_SHUTDOWN_COMPLETE: @@ -3748,6 +5545,9 @@ static void req_in(struct peer *peer, const u8 *msg) case WIRE_CHANNELD_LOCAL_CHANNEL_UPDATE: case WIRE_CHANNELD_LOCAL_CHANNEL_ANNOUNCEMENT: case WIRE_CHANNELD_LOCAL_PRIVATE_CHANNEL: + case WIRE_CHANNELD_ADD_INFLIGHT: + case WIRE_CHANNELD_UPDATE_INFLIGHT: + case WIRE_CHANNELD_GOT_INFLIGHT: break; } master_badmsg(-1, msg); @@ -3845,12 +5645,16 @@ static void init_channel(struct peer *peer) &dev_disable_commit, &pbases, &reestablish_only, - &peer->channel_update)) { + &peer->channel_update, + &peer->inflights)) { master_badmsg(WIRE_CHANNELD_INIT, msg); } peer->final_index = tal_dup(peer, u32, &final_index); peer->final_ext_key = tal_dup(peer, struct ext_key, &final_ext_key); + peer->committed_splice_count = tal_count(peer->inflights); + peer->revoked_splice_count = tal_count(peer->inflights); + peer->splice_count = tal_count(peer->inflights); #if DEVELOPER peer->dev_disable_commit = dev_disable_commit; @@ -3960,7 +5764,7 @@ static void init_channel(struct peer *peer) peer_write(peer->pps, take(fwd_msg)); /* Reenable channel */ - channel_announcement_negotiate(peer); + channel_announcement_negotiate(peer, NULL); billboard_update(peer); } @@ -3989,12 +5793,20 @@ int main(int argc, char *argv[]) peer->shutdown_wrong_funding = NULL; peer->last_update_timestamp = 0; peer->last_empty_commitment = 0; + peer->send_duplicate_announce_sigs = false; peer->commit_timer_attempts = 0; -#if EXPERIMENTAL_FEATURES - peer->stfu = false; + peer->stfu_request = false; peer->stfu_sent[LOCAL] = peer->stfu_sent[REMOTE] = false; + peer->stfu_wait_single_msg = false; peer->update_queue = msg_queue_new(peer, false); -#endif + reset_splice(peer); + peer->committed_splice_count = 0; + peer->revoked_splice_count = 0; + peer->splice_count = 0; + peer->splice_locked_ready[LOCAL] = false; + peer->splice_locked_ready[REMOTE] = false; + peer->splice_await_commitment_succcess = false; + peer->inflights = NULL; /* We send these to HSM to get real signatures; don't have valgrind * complain. */ @@ -4056,6 +5868,11 @@ int main(int argc, char *argv[]) tptr = &timeout; } + /* If we're in STFU mode and aren't waiting for a STFU mode + * specific message, don't read from the peer. */ + if (!peer->stfu_wait_single_msg && is_stfu_active(peer)) + FD_CLR(peer->pps->peer_fd, &rfds); + if (select(nfds, &rfds, NULL, NULL, tptr) < 0) { /* Signals OK, eg. SIGUSR1 */ if (errno == EINTR) diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index f4b60fe8b75f..80cc620bb5c1 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -82,6 +83,8 @@ msgdata,channeld_init,pbases,penalty_base,num_penalty_bases msgdata,channeld_init,reestablish_only,bool, msgdata,channeld_init,channel_update_len,u16, msgdata,channeld_init,channel_update,u8,channel_update_len +msgdata,channeld_init,inflight_count,u32, +msgdata,channeld_init,inflights,inflight,inflight_count # master->channeld funding hit new depth(funding locked if >= lock depth) # alias != NULL if zeroconf and short_channel_id == NULL @@ -90,6 +93,8 @@ msgtype,channeld_funding_depth,1002 msgdata,channeld_funding_depth,short_channel_id,?short_channel_id, msgdata,channeld_funding_depth,alias_local,?short_channel_id, msgdata,channeld_funding_depth,depth,u32, +msgdata,channeld_funding_depth,splicing,bool, +msgdata,channeld_funding_depth,txid,bitcoin_txid, # Tell channel to offer this htlc msgtype,channeld_offer_htlc,1004 @@ -121,6 +126,13 @@ msgtype,channeld_got_channel_ready,1019 msgdata,channeld_got_channel_ready,next_per_commit_point,pubkey, msgdata,channeld_got_channel_ready,alias,?short_channel_id, +# When we receive funding_locked. +msgtype,channeld_got_splice_locked,1119 +msgdata,channeld_got_splice_locked,funding_sats,amount_sat, +msgdata,channeld_got_splice_locked,old_local_funding_msats,amount_msat, +msgdata,channeld_got_splice_locked,new_local_funding_sats,amount_msat, +msgdata,channeld_got_splice_locked,locked_txid,bitcoin_txid, + #include # When we send a commitment_signed message, tell master. @@ -159,6 +171,14 @@ msgdata,channeld_got_commitsig,failed,failed_htlc,num_failed msgdata,channeld_got_commitsig,num_changed,u16, msgdata,channeld_got_commitsig,changed,changed_htlc,num_changed msgdata,channeld_got_commitsig,tx,bitcoin_tx, +# Inflight splice commitments +msgdata,channeld_got_commitsig,num_inflight_commitsigs,u16, +msgdata,channeld_got_commitsig,inflight_commitsigs,commitsig,num_inflight_commitsigs +subtype,commitsig +subtypedata,commitsig,tx,bitcoin_tx, +subtypedata,commitsig,commit_signature,bitcoin_signature, +subtypedata,commitsig,num_htlcs,u16, +subtypedata,commitsig,htlc_signatures,bitcoin_signature,num_htlcs # Wait for reply, to make sure it's on disk before we send revocation. msgtype,channeld_got_commitsig_reply,1121 @@ -181,6 +201,72 @@ msgdata,channeld_got_revoke,penalty_tx,?bitcoin_tx, msgtype,channeld_got_revoke_reply,1122 #include + +# master->channeld: hello, I'd like to start a channel splice open +msgtype,channeld_splice_init,7204 +msgdata,channeld_splice_init,psbt,wally_psbt, +msgdata,channeld_splice_init,funding_amount,amount_sat, +msgdata,channeld_splice_init,feerate_per_kw,u32, +msgdata,channeld_splice_init,force_feerate,bool, + +# channeld->master: hello, I started a channel splice open +msgtype,channeld_splice_confirmed_init,7205 +msgdata,channeld_splice_confirmed_init,psbt,wally_psbt, + +# master->channeld: Update an active splice +msgtype,channeld_splice_update,7206 +msgdata,channeld_splice_update,psbt,wally_psbt, + +# channeld->master: Splice update complete +msgtype,channeld_splice_confirmed_update,7207 +msgdata,channeld_splice_confirmed_update,psbt,wally_psbt, +msgdata,channeld_splice_confirmed_update,commitments_secured,bool, + +# channeld->master: Lookup a transaction +msgtype,channeld_splice_lookup_tx,7208 +msgdata,channeld_splice_lookup_tx,txid,bitcoin_txid, + +# master->channeld: Retrieved transaction +msgtype,channeld_splice_lookup_tx_result,7209 +msgdata,channeld_splice_lookup_tx_result,tx,bitcoin_tx, + +# master->channeld: User has signed psbt and it's ready to complete +msgtype,channeld_splice_signed,7212 +msgdata,channeld_splice_signed,psbt,wally_psbt, +msgdata,channeld_splice_signed,force_sign_first,bool, + +# channeld->master: Signed psbt is completed +msgtype,channeld_splice_confirmed_signed,7213 +msgdata,channeld_splice_confirmed_signed,tx,bitcoin_tx, +msgdata,channeld_splice_confirmed_signed,output_index,u32, + +# channeld->master: A feerate error has occured +msgtype,channeld_splice_feerate_error,7215 +msgdata,channeld_splice_feerate_error,fee,amount_sat, +msgdata,channeld_splice_feerate_error,too_high,bool, + +# channeld->master: Add an inflight to the DB +msgtype,channeld_add_inflight,7216 +msgdata,channeld_add_inflight,tx_id,bitcoin_txid, +msgdata,channeld_add_inflight,tx_outnum,u32, +msgdata,channeld_add_inflight,feerate,u32, +msgdata,channeld_add_inflight,satoshis,amount_sat, +msgdata,channeld_add_inflight,our_funding_satoshis,amount_sat, +msgdata,channeld_add_inflight,psbt,wally_psbt, + +# master->channeld: Inflight saved successfully +msgtype,channeld_got_inflight,7217 + +# channeld->master: Update inflight with sigs +msgtype,channeld_update_inflight,7219 +msgdata,channeld_update_inflight,psbt,wally_psbt, + +# channeld->master: A funding error has occured +msgtype,channeld_splice_funding_error,7220 +msgdata,channeld_splice_funding_error,funding,amount_sat, +msgdata,channeld_splice_funding_error,req_funding,amount_sat, +msgdata,channeld_splice_funding_error,opener_error,bool, + # Tell peer to shut down channel. msgtype,channeld_send_shutdown,1023 msgdata,channeld_send_shutdown,final_index,?u32, diff --git a/channeld/inflight.h b/channeld/inflight.h new file mode 100644 index 000000000000..b69fd11332c8 --- /dev/null +++ b/channeld/inflight.h @@ -0,0 +1,13 @@ +#ifndef CHANNELD_INFLIGHT +#define CHANNELD_INFLIGHT + +#include +#include + +struct inflight { + struct bitcoin_outpoint outpoint; + struct amount_sat amnt; + struct amount_sat local_funding; +}; + +#endif /* CHANNELD_INFLIGHT */ diff --git a/common/initial_channel.c b/common/initial_channel.c index cae1ad140201..900f53529750 100644 --- a/common/initial_channel.c +++ b/common/initial_channel.c @@ -35,6 +35,7 @@ struct channel *new_initial_channel(const tal_t *ctx, channel->cid = *cid; channel->funding = *funding; channel->funding_sats = funding_sats; + channel->starting_local_msats = local_msatoshi; channel->minimum_depth = minimum_depth; channel->lease_expiry = lease_expiry; if (!amount_sat_sub_msat(&remote_msatoshi, @@ -146,6 +147,108 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, return init_tx; } +char *channel_update_funding(struct channel *channel, + const struct bitcoin_outpoint *funding, + struct amount_sat funding_sats, + struct amount_msat old_local_funding_msats, + struct amount_sat new_local_funding_sats) +{ + struct amount_msat new_local_funding_msats; + struct amount_msat old_remote_funding_msats, new_remote_funding_msats; + struct amount_msat local_change, remote_change; + bool local_negative, remote_negative; + bool res; + + if (!amount_sat_to_msat(&new_local_funding_msats, + new_local_funding_sats)) + return tal_fmt(tmpctx, "Unable to convert new local funding " + "sats to msats"); + + if (!amount_sat_sub_msat(&old_remote_funding_msats, channel->funding_sats, + channel->starting_local_msats)) + return tal_fmt(tmpctx, "Unable to calculate starting_remote_msats"); + + if (!amount_sat_sub_msat(&new_remote_funding_msats, funding_sats, + new_local_funding_msats)) + return tal_fmt(tmpctx, "Unable to calculate new_remote_msats"); + + channel->funding = *funding; + channel->funding_sats = funding_sats; + channel->starting_local_msats = new_local_funding_msats; + + local_negative = amount_msat_greater(old_local_funding_msats, + new_local_funding_msats); + + if (local_negative) + res = amount_msat_sub(&local_change, old_local_funding_msats, + new_local_funding_msats); + else + res = amount_msat_sub(&local_change, new_local_funding_msats, + old_local_funding_msats); + if (!res) + return tal_fmt(tmpctx, "Unable to calculate local funding change"); + + if (local_negative) { + if (!amount_msat_sub(&channel->view[LOCAL].owed[LOCAL], + channel->view[LOCAL].owed[LOCAL], + local_change)) + return tal_fmt(tmpctx, "Unable to change local funding"); + if (!amount_msat_sub(&channel->view[REMOTE].owed[LOCAL], + channel->view[REMOTE].owed[LOCAL], + local_change)) + return tal_fmt(tmpctx, "Unable to change [remote view] " + "local funding"); + } + else { + if (!amount_msat_add(&channel->view[LOCAL].owed[LOCAL], + channel->view[LOCAL].owed[LOCAL], + local_change)) + return tal_fmt(tmpctx, "Unable to change local funding"); + if (!amount_msat_add(&channel->view[REMOTE].owed[LOCAL], + channel->view[REMOTE].owed[LOCAL], + local_change)) + return tal_fmt(tmpctx, "Unable to change [remote view] " + "local funding"); + } + + remote_negative = amount_msat_greater(old_remote_funding_msats, + new_remote_funding_msats); + + if (remote_negative) + res = amount_msat_sub(&remote_change, old_remote_funding_msats, + new_remote_funding_msats); + else + res = amount_msat_sub(&remote_change, new_remote_funding_msats, + old_remote_funding_msats); + if (!res) + return tal_fmt(tmpctx, "Unable to calculate remote funding change"); + + if (remote_negative) { + if (!amount_msat_sub(&channel->view[LOCAL].owed[REMOTE], + channel->view[LOCAL].owed[REMOTE], + remote_change)) + return tal_fmt(tmpctx, "Unable to change remote funding"); + if (!amount_msat_sub(&channel->view[REMOTE].owed[REMOTE], + channel->view[REMOTE].owed[REMOTE], + remote_change)) + return tal_fmt(tmpctx, "Unable to change [remote view] " + "remote funding"); + } + else { + if (!amount_msat_add(&channel->view[LOCAL].owed[REMOTE], + channel->view[LOCAL].owed[REMOTE], + remote_change)) + return tal_fmt(tmpctx, "Unable to change remote funding"); + if (!amount_msat_add(&channel->view[REMOTE].owed[REMOTE], + channel->view[REMOTE].owed[REMOTE], + remote_change)) + return tal_fmt(tmpctx, "Unable to change [remote view] " + "remote funding"); + } + + return NULL; +} + u32 channel_feerate(const struct channel *channel, enum side side) { return get_feerate(channel->fee_states, channel->opener, side); diff --git a/common/initial_channel.h b/common/initial_channel.h index 713d55f5fc76..128e7a4b7d6c 100644 --- a/common/initial_channel.h +++ b/common/initial_channel.h @@ -34,6 +34,9 @@ struct channel { /* satoshis in from commitment tx */ struct amount_sat funding_sats; + /* Our portion of funding_sats at start */ + struct amount_msat starting_local_msats; + /* confirmations needed for locking funding */ u32 minimum_depth; @@ -135,6 +138,18 @@ struct bitcoin_tx *initial_channel_tx(const tal_t *ctx, struct wally_tx_output *direct_outputs[NUM_SIDES], char** err_reason); +/* channel_update_funding: Changes the funding for the channel and updates the + * balance by the difference between `old_local_funding_msatoshi` and + * `new_local_funding_msatoshi`. + * + * Returns NULL on success or an error on failure. + */ +char *channel_update_funding(struct channel *channel, + const struct bitcoin_outpoint *funding, + struct amount_sat funding_sats, + struct amount_msat old_local_funding_msats, + struct amount_sat new_local_funding_sats); + /** * channel_feerate: Get fee rate for this side of channel. * @channel: The channel diff --git a/common/interactivetx.c b/common/interactivetx.c index 76b6de927678..fc9d94c19af0 100644 --- a/common/interactivetx.c +++ b/common/interactivetx.c @@ -8,8 +8,6 @@ #include #include #include -#include -#include #include #include #include @@ -18,13 +16,14 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include /* * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: @@ -64,14 +63,13 @@ struct interactivetx_context *new_interactivetx_context(const tal_t *ctx, { struct interactivetx_context *ictx = tal(ctx, struct interactivetx_context); - ictx->ctx = NULL; ictx->our_role = our_role; ictx->pps = pps; ictx->channel_id = channel_id; ictx->tx_add_input_count = 0; ictx->tx_add_output_count = 0; - ictx->next_update = default_next_update; - ictx->current_psbt = NULL; + ictx->next_update_fn = default_next_update; + ictx->current_psbt = create_psbt(ictx, 0, 0, 0); ictx->desired_psbt = NULL; ictx->pause_when_complete = false; ictx->change_set = NULL; @@ -83,6 +81,11 @@ static bool is_segwit_output(const tal_t *ctx, struct wally_tx_output *output, const u8 *redeemscript) { + /* Since redeemscript was removed from the spce, we assume it is + * segwit without checking for now. */ + if (!redeemscript) + return true; + const u8 *wit_prog; if (tal_bytelen(redeemscript) > 0) wit_prog = redeemscript; @@ -102,26 +105,14 @@ static u8 *read_next_msg(const tal_t *ctx, for (;;) { char *desc; bool warning; - struct channel_id actual; enum peer_wire t; - bool from_gossipd; /* Prevent runaway memory usage from many messages */ if (msg) tal_free(msg); /* This helper routine polls the peer. */ - msg = peer_or_gossip_sync_read(ctx, state->pps, &from_gossipd); - - /* Line should be in STFU mode and not receiving gossip */ - if (from_gossipd) { - *error = tal_fmt(ctx, "interactivetx got gossip but" - " should be in STFU mode."); - - tal_free(msg); - /* Return NULL so caller knows to stop negotiating. */ - return NULL; - } + msg = peer_read(ctx, state->pps); /* BOLT #1: * @@ -140,7 +131,7 @@ static u8 *read_next_msg(const tal_t *ctx, if (!desc) continue; - *error = tal_fmt(ctx, "They sent a %s: %s" + *error = tal_fmt(ctx, "They sent a %s: %s", warning ? "warning" : "error", desc); @@ -160,9 +151,11 @@ static u8 *read_next_msg(const tal_t *ctx, case WIRE_TX_REMOVE_OUTPUT: case WIRE_TX_COMPLETE: return msg; + case WIRE_TX_ABORT: + /* TODO */ case WIRE_TX_SIGNATURES: - case WIRE_FUNDING_LOCKED: - case WIRE_INIT_RBF: + case WIRE_CHANNEL_READY: + case WIRE_TX_INIT_RBF: case WIRE_OPEN_CHANNEL2: case WIRE_INIT: case WIRE_ERROR: @@ -184,7 +177,7 @@ static u8 *read_next_msg(const tal_t *ctx, case WIRE_GOSSIP_TIMESTAMP_FILTER: case WIRE_ONION_MESSAGE: case WIRE_ACCEPT_CHANNEL2: - case WIRE_ACK_RBF: + case WIRE_TX_ACK_RBF: case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_CHANNEL_UPDATE: case WIRE_NODE_ANNOUNCEMENT: @@ -196,9 +189,12 @@ static u8 *read_next_msg(const tal_t *ctx, case WIRE_PING: case WIRE_PONG: case WIRE_SHUTDOWN: -#if EXPERIMENTAL_FEATURES + case WIRE_PEER_STORAGE: + case WIRE_YOUR_PEER_STORAGE: case WIRE_STFU: -#endif + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: *error = tal_fmt(ctx, "Received invalid message from peer: %d", t); return NULL; @@ -213,7 +209,7 @@ static char *send_next(const tal_t *ctx, struct channel_id *cid = &ictx->channel_id; struct psbt_changeset *set = ictx->change_set; u64 serial_id; - u8 *msg = NULL; + u8 *msg; *finished = false; if (!set) @@ -225,13 +221,14 @@ static char *send_next(const tal_t *ctx, u8 *prevtx; if (!psbt_get_serial_id(&in->input.unknowns, &serial_id)) - return "interactivetx ADD_INPUT PSBT has invalid serial_id."; + return "interactivetx ADD_INPUT PSBT has invalid" + " serial_id."; if (in->input.utxo) - prevtx = linearize_wtx(ctx, - in->input.utxo); + prevtx = linearize_wtx(ctx, in->input.utxo); else - return "interactivetx ADD_INPUT PSBT needs the previous transaction set."; + return "interactivetx ADD_INPUT PSBT needs the previous" + " transaction set."; memcpy(outpoint.txid.shad.sha.u.u8, in->tx_input.txhash, @@ -241,15 +238,15 @@ static char *send_next(const tal_t *ctx, msg = towire_tx_add_input(NULL, cid, serial_id, prevtx, in->tx_input.index, - in->tx_input.sequence, - NULL); + in->tx_input.sequence); tal_arr_remove(&set->added_ins, 0); } else if (tal_count(set->rm_ins) != 0) { if (!psbt_get_serial_id(&set->rm_ins[0].input.unknowns, &serial_id)) - return "interactivetx RM_INPUT PSBT has invalid serial_id."; + return "interactivetx RM_INPUT PSBT has invalid" + " serial_id."; msg = towire_tx_remove_input(NULL, cid, serial_id); @@ -264,7 +261,8 @@ static char *send_next(const tal_t *ctx, out = &set->added_outs[0]; if (!psbt_get_serial_id(&out->output.unknowns, &serial_id)) - return "interactivetx ADD_OUTPUT PSBT has invalid serial_id."; + return "interactivetx ADD_OUTPUT PSBT has invalid" + " serial_id."; asset_amt = wally_tx_output_get_amount(&out->tx_output); sats = amount_asset_to_sat(&asset_amt); @@ -292,33 +290,47 @@ static char *send_next(const tal_t *ctx, if (!msg) return "Interactivetx send_next failed to build a message"; - sync_crypto_write(ictx->pps, take(msg)); + peer_write(ictx->pps, take(msg)); return NULL; tx_complete: - *finished = true; if (!ictx->pause_when_complete) { if (ictx->current_psbt->num_inputs > MAX_FUNDING_INPUTS) return tal_fmt(ctx, "Humbly refusing to `tx_complete` " "because we have too many inputs (%zu). " - "Limit is %zu." + "Limit is %d.", ictx->current_psbt->num_inputs, MAX_FUNDING_INPUTS); - + if (ictx->current_psbt->num_outputs > MAX_FUNDING_OUTPUTS) return tal_fmt(ctx, "Humbly refusing to `tx_complete` " "because we have too many outputs (%zu). " - "Limit is %zu." + "Limit is %d.", ictx->current_psbt->num_outputs, MAX_FUNDING_OUTPUTS); - msg = towire_tx_complete(ctx, cid); - sync_crypto_write(ictx->pps, msg); + msg = towire_tx_complete(NULL, cid); + peer_write(ictx->pps, take(msg)); } + *finished = true; return NULL; } +bool interactivetx_has_changes(struct interactivetx_context *ictx, + struct wally_psbt *next_psbt) +{ + struct psbt_changeset *set = psbt_get_changeset(tmpctx, + ictx->current_psbt, + next_psbt); + + if (!set) + return true; + + return tal_count(set->added_ins) || tal_count(set->rm_ins) + || tal_count(set->added_outs) || tal_count(set->rm_outs); +} + char *process_interactivetx_updates(const tal_t *ctx, struct interactivetx_context *ictx, bool *received_tx_complete) @@ -328,19 +340,16 @@ char *process_interactivetx_updates(const tal_t *ctx, char *error = NULL; struct wally_psbt *next_psbt; - if (ictx->current_psbt == NULL) - ictx->current_psbt = create_psbt(ictx, 0, 0, 0); - if (received_tx_complete) they_complete = *received_tx_complete; /* Build change_set and handle PSBT variables */ ictx->change_set = tal_free(ictx->change_set); - /* Call next_update or default to 'desired_psbt' */ - next_psbt = ictx->next_update(ictx, ictx); + /* Call next_update_fn or default to 'desired_psbt' */ + next_psbt = ictx->next_update_fn(ictx, ictx); - /* Returning NULL from next_update is the same as using `current_psbt` + /* Returning NULL from next_update_fn is the same as using `current_psbt` * with no changes -- both indicate no changes */ if (!next_psbt) next_psbt = ictx->current_psbt; @@ -355,7 +364,7 @@ char *process_interactivetx_updates(const tal_t *ctx, if (ictx->current_psbt != next_psbt) { /* psbt_get_changeset requires we keep the current_psbt until * we're done withh change_set */ - tal_steal(ictx->change_set, current_psbt); + tal_steal(ictx->change_set, ictx->current_psbt); ictx->current_psbt = next_psbt; } @@ -391,7 +400,7 @@ char *process_interactivetx_updates(const tal_t *ctx, t = fromwire_peektype(msg); switch (t) { case WIRE_TX_ADD_INPUT: { - const u8 *tx_bytes, *redeemscript; + const u8 *tx_bytes, *redeemscript = NULL; u32 sequence; size_t len; struct bitcoin_tx *tx; @@ -401,9 +410,9 @@ char *process_interactivetx_updates(const tal_t *ctx, &serial_id, cast_const2(u8 **, &tx_bytes), - &outpoint.n, &sequence, + &outpoint.n, &sequence/*, cast_const2(u8 **, - &redeemscript))) + &redeemscript)*/)) return tal_fmt(ctx, "Parsing tx_add_input %s", tal_hex(ctx, msg)); @@ -493,7 +502,7 @@ char *process_interactivetx_updates(const tal_t *ctx, */ if (ictx->current_psbt->num_inputs + 1 > MAX_FUNDING_INPUTS) return tal_fmt(ctx, "Too many inputs. Have %zu," - " Max allowed %zu", + " Max allowed %d", ictx->current_psbt->num_inputs + 1, MAX_FUNDING_INPUTS); @@ -620,7 +629,7 @@ char *process_interactivetx_updates(const tal_t *ctx, */ if (ictx->current_psbt->num_outputs + 1 > MAX_FUNDING_OUTPUTS) return tal_fmt(ctx, "Too many inputs. Have %zu," - " Max allowed %zu", + " Max allowed %d", ictx->current_psbt->num_outputs + 1, MAX_FUNDING_OUTPUTS); @@ -678,6 +687,8 @@ char *process_interactivetx_updates(const tal_t *ctx, if (received_tx_complete) *received_tx_complete = true; break; + case WIRE_TX_ABORT: + /* Todo */ case WIRE_INIT: case WIRE_ERROR: case WIRE_WARNING: @@ -685,7 +696,7 @@ char *process_interactivetx_updates(const tal_t *ctx, case WIRE_ACCEPT_CHANNEL: case WIRE_FUNDING_CREATED: case WIRE_FUNDING_SIGNED: - case WIRE_FUNDING_LOCKED: + case WIRE_CHANNEL_READY: case WIRE_SHUTDOWN: case WIRE_CLOSING_SIGNED: case WIRE_UPDATE_ADD_HTLC: @@ -699,13 +710,12 @@ char *process_interactivetx_updates(const tal_t *ctx, case WIRE_CHANNEL_REESTABLISH: case WIRE_ANNOUNCEMENT_SIGNATURES: case WIRE_GOSSIP_TIMESTAMP_FILTER: - case WIRE_OBS2_ONION_MESSAGE: case WIRE_ONION_MESSAGE: case WIRE_TX_SIGNATURES: case WIRE_OPEN_CHANNEL2: case WIRE_ACCEPT_CHANNEL2: - case WIRE_INIT_RBF: - case WIRE_ACK_RBF: + case WIRE_TX_INIT_RBF: + case WIRE_TX_ACK_RBF: case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_CHANNEL_UPDATE: case WIRE_NODE_ANNOUNCEMENT: @@ -715,11 +725,12 @@ char *process_interactivetx_updates(const tal_t *ctx, case WIRE_REPLY_SHORT_CHANNEL_IDS_END: case WIRE_PING: case WIRE_PONG: -#if EXPERIMENTAL_FEATURES + case WIRE_PEER_STORAGE: + case WIRE_YOUR_PEER_STORAGE: case WIRE_SPLICE: case WIRE_SPLICE_ACK: case WIRE_STFU: -#endif + case WIRE_SPLICE_LOCKED: return tal_fmt(ctx, "Unexpected wire message %s", tal_hex(ctx, msg)); } @@ -731,5 +742,7 @@ char *process_interactivetx_updates(const tal_t *ctx, /* Sort psbt! */ psbt_sort_by_serial_id(ictx->current_psbt); + tal_steal(ictx, ictx->current_psbt); + return NULL; } diff --git a/common/interactivetx.h b/common/interactivetx.h index 0d8a27588947..5e5119ab3b12 100644 --- a/common/interactivetx.h +++ b/common/interactivetx.h @@ -1,7 +1,6 @@ #ifndef LIGHTNING_COMMON_INTERACTIVETX_H #define LIGHTNING_COMMON_INTERACTIVETX_H -#include "config.h" #include #include #include @@ -26,9 +25,6 @@ enum tx_msgs { struct interactivetx_context { - /* Users can set this to their own context */ - void *ctx; - enum tx_role our_role; struct per_peer_state *pps; struct channel_id channel_id; @@ -45,16 +41,14 @@ struct interactivetx_context { * If no more changes are demanded, return NULL or current_psbt * unchanged to signal completion. */ - struct wally_psbt *(*next_update)(const tal_t *ctx, + struct wally_psbt *(*next_update_fn)(const tal_t *ctx, struct interactivetx_context *ictx); - /* Set this to the intial psbt. If NULL will be filled with an empty - * psbt. - */ + /* Set this to the intial psbt. Defaults to an empty PSBT. */ struct wally_psbt *current_psbt; /* Optional field for storing your side's desired psbt state, to be - * used inside 'next_update'. + * used inside 'next_update_fn'. */ struct wally_psbt *desired_psbt; @@ -74,8 +68,8 @@ struct interactivetx_context *new_interactivetx_context(const tal_t *ctx, struct channel_id channel_id); /* Blocks the thread until we run out of changes (and we send tx_complete), - * or an error occurs. If 'pause_when_complete' is set, this behavior changes - * and we return without sending tx_complete. + * or an error occurs. If 'pause_when_complete' on the `interactivetx_context` + * is set, this behavior changes and we return without sending tx_complete. * * If received_tx_complete is not NULL: * in -> true means we assume we've received tx_complete in a previous round. @@ -87,4 +81,11 @@ char *process_interactivetx_updates(const tal_t *ctx, struct interactivetx_context *ictx, bool *received_tx_complete); +/* If the given ictx would cause `process_interactivetx_updates to send tx + * changes when called. Returns true if an error occurs + * (call `process_interactivetx_updates` for a description of the error). + */ +bool interactivetx_has_changes(struct interactivetx_context *ictx, + struct wally_psbt *next_psbt); + #endif /* LIGHTNING_COMMON_INTERACTIVETX_H */ diff --git a/connectd/gossip_rcvd_filter.c b/connectd/gossip_rcvd_filter.c index 740b52957ffe..f977ca1a7811 100644 --- a/connectd/gossip_rcvd_filter.c +++ b/connectd/gossip_rcvd_filter.c @@ -91,9 +91,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: break; } return false; diff --git a/connectd/gossip_store.c b/connectd/gossip_store.c index 0ebb4f37772a..b288418aece0 100644 --- a/connectd/gossip_store.c +++ b/connectd/gossip_store.c @@ -94,9 +94,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: return false; case WIRE_CHANNEL_ANNOUNCEMENT: case WIRE_NODE_ANNOUNCEMENT: diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 72db922e9931..4eb2b9d9f4ba 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -387,9 +387,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: return false; /* These are time-sensitive, and so send without delay. */ diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 15272b1d5a76..de1b6a88d0a2 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1207,6 +1207,39 @@ def openchannel_abort(self, channel_id): } return self.call("openchannel_abort", payload) + def splice_init(self, chan_id, amount, initialpsbt=None, feerate_per_kw=None): + """ Initiate a splice """ + payload = { + "channel_id": chan_id, + "amount": amount, + "initialpsbt": initialpsbt, + "feerate_per_kw": feerate_per_kw, + } + return self.call("splice_init", payload) + + def splice_update(self, chan_id, psbt): + """ Update a splice """ + payload = { + "channel_id": chan_id, + "psbt": psbt + } + return self.call("splice_update", payload) + + def splice_finalize(self, chan_id): + """ Finalize a splice """ + payload = { + "channel_id": chan_id + } + return self.call("splice_finalize", payload) + + def splice_signed(self, chan_id, psbt): + """ Initiate a splice """ + payload = { + "channel_id": chan_id, + "psbt": psbt + } + return self.call("splice_signed", payload) + def paystatus(self, bolt11=None): """Detail status of attempts to pay {bolt11} or any.""" payload = { diff --git a/gossipd/gossipd.c b/gossipd/gossipd.c index ab995192190d..d319f5e77c3a 100644 --- a/gossipd/gossipd.c +++ b/gossipd/gossipd.c @@ -571,9 +571,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: break; } diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 9bfee1fd7d17..80431cb2ccb5 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -1,5 +1,7 @@ #include "config.h" #include +#include +#include #include #include #include @@ -23,6 +25,17 @@ #include #include #include +#include +#include + +struct splice_command { + /* Inside struct lightningd splice_commands. */ + struct list_node list; + /* Command structure. This is the parent of the splice command. */ + struct command *cmd; + /* Channel being spliced. */ + struct channel *channel; +}; static void update_feerates(struct lightningd *ld, struct channel *channel) { @@ -128,6 +141,471 @@ void notify_feerate_change(struct lightningd *ld) * peer. We *could* do so, however. */ } +static void handle_splice_funding_error(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct splice_command *cc; + struct splice_command *n; + struct amount_sat funding, req_funding; + bool opener_error; + + if (!fromwire_channeld_splice_funding_error(msg, &funding, + &req_funding, + &opener_error)) { + channel_internal_error(channel, + "bad fromwire_channeld_splice_feerate_error %s", + tal_hex(channel, msg)); + return; + } + + list_for_each_safe(&ld->splice_commands, cc, n, list) { + if (channel != cc->channel) + continue; + + struct json_stream *response = json_stream_success(cc->cmd); + json_add_string(response, "message", "Splice funding too low"); + json_add_string(response, "error", + tal_fmt(tmpctx, + "%s provided %s but committed to %s.", + opener_error ? "You" : "Peer", + fmt_amount_sat(tmpctx, funding), + fmt_amount_sat(tmpctx, req_funding))); + + was_pending(command_success(cc->cmd, response)); + + list_del(&cc->list); + tal_free(cc); + return; + } + + log_peer_unusual(ld->log, &channel->peer->id, + "Splice funding too low. %s provided but %s commited " + "to %s", + opener_error ? "peer" : "you", + fmt_amount_sat(tmpctx, funding), + fmt_amount_sat(tmpctx, req_funding)); +} + +static void handle_splice_feerate_error(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct splice_command *cc; + struct splice_command *n; + struct amount_sat fee; + bool too_high; + + if (!fromwire_channeld_splice_feerate_error(msg, &fee, &too_high)) { + channel_internal_error(channel, + "bad fromwire_channeld_splice_feerate_error %s", + tal_hex(channel, msg)); + return; + } + + list_for_each_safe(&ld->splice_commands, cc, n, list) { + if (channel != cc->channel) + continue; + + struct json_stream *response = json_stream_success(cc->cmd); + json_add_string(response, "message", "Splice feerate failed"); + + if (too_high) + json_add_string(response, "error", + tal_fmt(tmpctx, "Feerate too high. Do you " + "really want to spend %s on fees?", + fmt_amount_sat(tmpctx, fee))); + else + json_add_string(response, "error", + tal_fmt(tmpctx, "Feerate too low. Your " + "funding only provided %s in fees", + fmt_amount_sat(tmpctx, fee))); + + was_pending(command_success(cc->cmd, response)); + + list_del(&cc->list); + tal_free(cc); + return; + } + + log_peer_unusual(ld->log, &channel->peer->id, "Peer gave us a splice pkg" + " with too low of feerate (fee was %s), we rejected it.", + fmt_amount_sat(tmpctx, fee)); +} + +/* When channeld finishes processing the `splice_init` command, this is called */ +static void handle_splice_confirmed_init(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct splice_command *cc; + struct splice_command *n; + struct wally_psbt *psbt; + + if (!fromwire_channeld_splice_confirmed_init(tmpctx, msg, &psbt)) { + channel_internal_error(channel, + "bad splice_confirmed_init %s", + tal_hex(channel, msg)); + return; + } + + list_for_each_safe(&ld->splice_commands, cc, n, list) { + if (channel != cc->channel) + continue; + + struct json_stream *response = json_stream_success(cc->cmd); + json_add_string(response, "message", "Splice intiated"); + json_add_string(response, "psbt", psbt_to_b64(tmpctx, psbt)); + + was_pending(command_success(cc->cmd, response)); + + list_del(&cc->list); + tal_free(cc); + } +} + +/* Channeld sends us this in response to a user's `splice_update` request */ +static void handle_splice_confirmed_update(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct splice_command *cc; + struct splice_command *n; + struct wally_psbt *psbt; + bool commitments_secured; + + if (!fromwire_channeld_splice_confirmed_update(tmpctx, + msg, + &psbt, + &commitments_secured)) { + channel_internal_error(channel, + "bad splice_confirmed_update %s", + tal_hex(channel, msg)); + return; + } + + list_for_each_safe(&ld->splice_commands, cc, n, list) { + if (channel != cc->channel) + continue; + + struct json_stream *response = json_stream_success(cc->cmd); + json_add_string(response, "message", "Splice updated"); + json_add_string(response, "psbt", psbt_to_b64(tmpctx, psbt)); + json_add_bool(response, "commitments_secured", commitments_secured); + + was_pending(command_success(cc->cmd, response)); + + list_del(&cc->list); + tal_free(cc); + } +} + +/* Channeld uses this to request the funding transaction for help building the + * splice tx */ +static void handle_splice_lookup_tx(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct bitcoin_txid txid; + struct bitcoin_tx *tx; + u8 *outmsg; + + if (!fromwire_channeld_splice_lookup_tx(msg, &txid)) { + channel_internal_error(channel, + "bad splice_lookup_tx %s", + tal_hex(channel, msg)); + return; + } + + tx = wallet_transaction_get(tmpctx, ld->wallet, &txid); + + if (!tx) { + channel_internal_error(channel, + "channel control unable to find txid %s", + type_to_string(tmpctx, + struct bitcoin_txid, + &txid)); + return; + } + + outmsg = towire_channeld_splice_lookup_tx_result(NULL, tx); + subd_send_msg(channel->owner, take(outmsg)); +} + +/* Extra splice data we want to store for bitcoin send tx interface */ +struct send_splice_info +{ + struct splice_command *cc; + struct channel *channel; + const struct bitcoin_tx *final_tx; + u32 output_index; + const char *err_msg; +}; + +static void handle_tx_broadcast(struct send_splice_info *info) +{ + struct lightningd *ld = info->channel->peer->ld; + struct amount_sat unused; + struct json_stream *response; + struct bitcoin_txid txid; + u8 *tx_bytes; + int num_utxos; + + tx_bytes = linearize_tx(tmpctx, info->final_tx); + bitcoin_txid(info->final_tx, &txid); + + /* This might have spent UTXOs from our wallet */ + num_utxos = wallet_extract_owned_outputs(ld->wallet, + info->final_tx->wtx, false, + NULL, &unused); + if (num_utxos) + wallet_transaction_add(ld->wallet, info->final_tx->wtx, 0, 0); + + if (info->cc) { + response = json_stream_success(info->cc->cmd); + + json_add_string(response, "message", "Splice confirmed"); + json_add_hex(response, "tx", tx_bytes, tal_bytelen(tx_bytes)); + json_add_txid(response, "txid", &txid); + + was_pending(command_success(info->cc->cmd, response)); + + list_del(&info->cc->list); + } +} + +/* Succeeds if the utxo was found in the mempool or in the utxo set. If it's in + * a block and spent it will fail but we're okay with that here. */ +static void check_utxo_block(struct bitcoind *bitcoind UNUSED, + const struct bitcoin_tx_output *txout, + void *arg) +{ + struct send_splice_info *info = arg; + + if(!txout) { + if (info->cc) + was_pending(command_fail(info->cc->cmd, + SPLICE_BROADCAST_FAIL, + "Error broadcasting splice " + "tx: %s. Unsent tx discarded " + "%s.", + info->err_msg, + type_to_string(tmpctx, + struct wally_tx, + info->final_tx->wtx))); + + log_unusual(info->channel->log, + "Error broadcasting splice " + "tx: %s. Unsent tx discarded " + "%s.", + info->err_msg, + type_to_string(tmpctx, struct wally_tx, + info->final_tx->wtx)); + } + else + handle_tx_broadcast(info); + + tal_free(info); +} + +/* Callback for after the splice tx is sent to bitcoind */ +static void send_splice_tx_done(struct bitcoind *bitcoind UNUSED, + bool success, const char *msg, + struct send_splice_info *info) +{ + /* A NULL value of `info->cc` means we got here without user intiation. + * This means we are the ACCEPTER side of the splice */ + struct lightningd *ld = info->channel->peer->ld; + struct bitcoin_outpoint outpoint; + + bitcoin_txid(info->final_tx, &outpoint.txid); + outpoint.n = info->output_index; + + if (!success) { + info->err_msg = tal_strdup(info, msg); + bitcoind_getutxout(ld->topology->bitcoind, &outpoint, + check_utxo_block, info); + } else { + handle_tx_broadcast(info); + tal_free(info); + } +} + +/* Where the splice tx gets finally transmitted to the chain */ +static void send_splice_tx(struct channel *channel, + const struct bitcoin_tx *tx, + struct splice_command *cc, + u32 output_index) +{ + struct lightningd *ld = channel->peer->ld; + u8* tx_bytes = linearize_tx(tmpctx, tx); + + log_debug(channel->log, + "Broadcasting splice tx %s for channel %s.", + tal_hex(tmpctx, tx_bytes), + type_to_string(tmpctx, struct channel_id, &channel->cid)); + + struct send_splice_info *info = tal(NULL, struct send_splice_info); + + info->cc = tal_steal(info, cc); + info->channel = channel; + info->final_tx = tal_steal(info, tx); + info->output_index = output_index; + info->err_msg = NULL; + + bitcoind_sendrawtx(ld->topology->bitcoind, + cc ? cc->cmd->id : NULL, + tal_hex(tmpctx, tx_bytes), + false, + send_splice_tx_done, info); +} + +/* After user signs PSBT with splice_signed, our node goes through the signing + * process (adding it's own signatures and peers' sigs), sending the result to + * us here: */ +static void handle_splice_confirmed_signed(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct splice_command *cc; + struct splice_command *n; + struct bitcoin_tx *tx; + u32 output_index; + + if (!fromwire_channeld_splice_confirmed_signed(tmpctx, msg, &tx, &output_index)) { + + channel_internal_error(channel, + "bad splice_confirmed_init %s", + tal_hex(channel, msg)); + return; + } + + if (channel->state != CHANNELD_NORMAL) { + log_debug(channel->log, + "Would broadcast splice, but state %s" + " isn't CHANNELD_NORMAL", + channel_state_name(channel)); + return; + } + + /* First look for a matching user command for this splice */ + list_for_each_safe(&ld->splice_commands, cc, n, list) { + if (channel != cc->channel) + continue; + + channel_set_state(channel, + CHANNELD_NORMAL, + CHANNELD_AWAITING_SPLICE, + REASON_USER, + "Broadcasting splice"); + + send_splice_tx(channel, tx, cc, output_index); + + return; + } + + /* If no matching user commands, this wasn't a user intiated splice */ + channel_set_state(channel, + CHANNELD_NORMAL, + CHANNELD_AWAITING_SPLICE, + REASON_REMOTE, + "Broadcasting splice"); + + send_splice_tx(channel, tx, NULL, output_index); +} + +static void handle_add_inflight(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct bitcoin_outpoint outpoint; + u32 feerate; + struct amount_sat satoshis; + struct amount_sat our_funding_satoshis; + struct wally_psbt *psbt; + struct channel_inflight *inflight; + struct bitcoin_signature last_sig; + + if (!fromwire_channeld_add_inflight(tmpctx, + msg, + &outpoint.txid, + &outpoint.n, + &feerate, + &satoshis, + &our_funding_satoshis, + &psbt)) { + channel_internal_error(channel, + "bad channel_add_inflight %s", + tal_hex(channel, msg)); + return; + } + + memset(&last_sig, 0, sizeof(last_sig)); + + inflight = new_inflight(channel, + &outpoint, + feerate, + satoshis, + our_funding_satoshis, + psbt, + NULL, + last_sig, + channel->lease_expiry, + channel->lease_commit_sig, + channel->lease_chan_max_msat, + channel->lease_chan_max_ppt, + 0, + AMOUNT_MSAT(0), + AMOUNT_SAT(0)); + + + log_debug(channel->log, "lightningd adding inflight with txid %s", + type_to_string(tmpctx, struct bitcoin_txid, + &inflight->funding->outpoint.txid)); + + wallet_inflight_add(ld->wallet, inflight); + channel_watch_inflight(ld, channel, inflight); + + subd_send_msg(channel->owner, take(towire_channeld_got_inflight(NULL))); +} + +static void handle_update_inflight(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct channel_inflight *inflight; + struct wally_psbt *psbt; + struct bitcoin_txid txid; + + if (!fromwire_channeld_update_inflight(tmpctx, msg, &psbt)) { + channel_internal_error(channel, + "bad channel_add_inflight %s", + tal_hex(channel, msg)); + return; + } + + psbt_txid(tmpctx, psbt, &txid, NULL); + inflight = channel_inflight_find(channel, &txid); + + tal_wally_start(); + if (wally_psbt_combine(inflight->funding_psbt, psbt) != WALLY_OK) { + channel_internal_error(channel, + "Unable to combine PSBTs: %s, %s", + type_to_string(tmpctx, + struct wally_psbt, + inflight->funding_psbt), + type_to_string(tmpctx, + struct wally_psbt, + psbt)); + tal_wally_end(inflight->funding_psbt); + return; + } + tal_wally_end(inflight->funding_psbt); + + psbt_finalize(cast_const(struct wally_psbt *, inflight->funding_psbt)); + wallet_inflight_save(ld->wallet, inflight); +} + void channel_record_open(struct channel *channel, u32 blockheight, bool record_push) { struct chain_coin_mvt *mvt; @@ -186,7 +664,8 @@ void channel_record_open(struct channel *channel, u32 blockheight, bool record_p channel->opener == REMOTE)); } -static void lockin_complete(struct channel *channel) +static void lockin_complete(struct channel *channel, + enum channel_state expected_state) { if (!channel->scid && (!channel->alias[REMOTE] || !channel->alias[LOCAL])) { @@ -199,14 +678,18 @@ static void lockin_complete(struct channel *channel) assert(channel->remote_channel_ready); /* We might have already started shutting down */ - if (channel->state != CHANNELD_AWAITING_LOCKIN) { + if (channel->state != expected_state) { log_debug(channel->log, "Lockin complete, but state %s", channel_state_name(channel)); return; } + log_debug(channel->log, "Moving channel state from %s to %s", + channel_state_str(expected_state), + channel_state_str(CHANNELD_NORMAL)); + channel_set_state(channel, - CHANNELD_AWAITING_LOCKIN, + expected_state, CHANNELD_NORMAL, REASON_UNKNOWN, "Lockin complete"); @@ -242,6 +725,98 @@ bool channel_on_channel_ready(struct channel *channel, return true; } +static void handle_peer_splice_locked(struct channel *channel, const u8 *msg) +{ + struct amount_sat funding_sats; + struct amount_msat old_local_funding_msats, new_local_funding_msats; + struct amount_msat local_change; + struct channel_inflight *inflight; + struct bitcoin_txid locked_txid; + bool local_negative; + bool res; + + if (!fromwire_channeld_got_splice_locked(msg, &funding_sats, + &old_local_funding_msats, + &new_local_funding_msats, + &locked_txid)) { + channel_internal_error(channel, + "bad channel_got_funding_locked %s", + tal_hex(channel, msg)); + return; + } + + local_negative = amount_msat_greater(old_local_funding_msats, + new_local_funding_msats); + + if (local_negative) + res = amount_msat_sub(&local_change, old_local_funding_msats, + new_local_funding_msats); + else + res = amount_msat_sub(&local_change, new_local_funding_msats, + old_local_funding_msats); + if (!res) + channel_internal_error(channel, "Unable to calculate local " + "splice funding change"); + + if (local_negative) { + if (!amount_msat_sub(&channel->our_msat, + channel->our_msat, + local_change)) + channel_internal_error(channel, "Unable to update " + "our_msat"); + if (!amount_msat_sub(&channel->msat_to_us_min, + channel->msat_to_us_min, + local_change)) + channel_internal_error(channel, "Unable to update " + "msat_to_us_min"); + if (!amount_msat_sub(&channel->msat_to_us_max, + channel->msat_to_us_max, + local_change)) + channel_internal_error(channel, "Unable to update " + "msat_to_us_max"); + } + else { + if (!amount_msat_add(&channel->our_msat, + channel->our_msat, + local_change)) + channel_internal_error(channel, "Unable to update " + "our_msat"); + if (!amount_msat_add(&channel->msat_to_us_min, + channel->msat_to_us_min, + local_change)) + channel_internal_error(channel, "Unable to update " + "msat_to_us_min"); + if (!amount_msat_add(&channel->msat_to_us_max, + channel->msat_to_us_max, + local_change)) + channel_internal_error(channel, "Unable to update " + "msat_to_us_max"); + } + + inflight = channel_inflight_find(channel, &locked_txid); + + if(!inflight) + channel_internal_error(channel, "Unable to load inflight for" + " locked_txid %s", + type_to_string(tmpctx, + struct bitcoin_txid, + &locked_txid)); + + wallet_htlcsigs_confirm_inflight(channel->peer->ld->wallet, channel, + inflight->funding->outpoint.txid); + + update_channel_from_inflight(channel->peer->ld, channel, inflight); + + /* Remember that we got the lockin */ + wallet_channel_save(channel->peer->ld->wallet, channel); + + /* Empty out the inflights */ + log_debug(channel->log, "lightningd, splice_locked clearing inflights"); + wallet_channel_clear_inflights(channel->peer->ld->wallet, channel); + + lockin_complete(channel, CHANNELD_AWAITING_SPLICE); +} + /* We were informed by channeld that channel is ready (reached mindepth) */ static void peer_got_channel_ready(struct channel *channel, const u8 *msg) { @@ -266,7 +841,7 @@ static void peer_got_channel_ready(struct channel *channel, const u8 *msg) wallet_channel_save(channel->peer->ld->wallet, channel); if (channel->depth >= channel->minimum_depth) - lockin_complete(channel); + lockin_complete(channel, CHANNELD_AWAITING_LOCKIN); } static void peer_got_announcement(struct channel *channel, const u8 *msg) @@ -521,6 +1096,22 @@ static void handle_channel_upgrade(struct channel *channel, } #endif /* EXPERIMENTAL_FEATURES */ +static bool get_inflight_outpoint_index(struct channel *channel, + u32 *index, + const struct bitcoin_txid *txid) +{ + struct channel_inflight *inflight; + + list_for_each(&channel->inflights, inflight, list) { + if (bitcoin_txid_eq(txid, &inflight->funding->outpoint.txid)) { + *index = inflight->funding->outpoint.n; + return true; + } + } + + return false; +} + static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) { enum channeld_wire t = fromwire_peektype(msg); @@ -569,12 +1160,37 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_LOCAL_PRIVATE_CHANNEL: handle_local_private_channel(sd->channel, msg); break; -#if EXPERIMENTAL_FEATURES + case WIRE_CHANNELD_SPLICE_CONFIRMED_INIT: + handle_splice_confirmed_init(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_SPLICE_FEERATE_ERROR: + handle_splice_feerate_error(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_SPLICE_FUNDING_ERROR: + handle_splice_funding_error(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_SPLICE_CONFIRMED_UPDATE: + handle_splice_confirmed_update(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_SPLICE_LOOKUP_TX: + handle_splice_lookup_tx(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_SPLICE_CONFIRMED_SIGNED: + handle_splice_confirmed_signed(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_ADD_INFLIGHT: + handle_add_inflight(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_UPDATE_INFLIGHT: + handle_update_inflight(sd->ld, sd->channel, msg); + break; + case WIRE_CHANNELD_GOT_SPLICE_LOCKED: + handle_peer_splice_locked(sd->channel, msg); + break; case WIRE_CHANNELD_UPGRADED: +#if EXPERIMENTAL_FEATURES handle_channel_upgrade(sd->channel, msg); break; -#else - case WIRE_CHANNELD_UPGRADED: #endif /* And we never get these from channeld. */ case WIRE_CHANNELD_INIT: @@ -593,11 +1209,16 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_CHANNEL_UPDATE: case WIRE_CHANNELD_DEV_MEMLEAK: case WIRE_CHANNELD_DEV_QUIESCE: + case WIRE_CHANNELD_GOT_INFLIGHT: /* Replies go to requests. */ case WIRE_CHANNELD_OFFER_HTLC_REPLY: case WIRE_CHANNELD_DEV_REENABLE_COMMIT_REPLY: case WIRE_CHANNELD_DEV_MEMLEAK_REPLY: case WIRE_CHANNELD_SEND_ERROR: + case WIRE_CHANNELD_SPLICE_INIT: + case WIRE_CHANNELD_SPLICE_UPDATE: + case WIRE_CHANNELD_SPLICE_LOOKUP_TX_RESULT: + case WIRE_CHANNELD_SPLICE_SIGNED: case WIRE_CHANNELD_DEV_QUIESCE_REPLY: break; } @@ -613,6 +1234,7 @@ bool peer_start_channeld(struct channel *channel, { u8 *initmsg; int hsmfd; + u32 i; const struct existing_htlc **htlcs; struct short_channel_id scid; u64 num_revocations; @@ -622,6 +1244,9 @@ bool peer_start_channeld(struct channel *channel, struct secret last_remote_per_commit_secret; secp256k1_ecdsa_signature *remote_ann_node_sig, *remote_ann_bitcoin_sig; struct penalty_base *pbases; + struct channel_inflight *inflight; + struct inflight *inflights; + struct bitcoin_txid txid; hsmfd = hsm_get_client_fd(ld, &channel->peer->id, channel->dbid, @@ -629,7 +1254,8 @@ bool peer_start_channeld(struct channel *channel, | HSM_CAP_ECDH | HSM_CAP_COMMITMENT_POINT | HSM_CAP_SIGN_REMOTE_TX - | HSM_CAP_SIGN_ONCHAIN_TX); + | HSM_CAP_SIGN_ONCHAIN_TX + | HSM_CAP_SIGN_CLOSING_TX); channel_set_owner(channel, new_channel_subd(channel, ld, @@ -721,6 +1347,16 @@ bool peer_start_channeld(struct channel *channel, return false; } + i = 0; + inflights = tal_arr(tmpctx, struct inflight, 0); + list_for_each(&channel->inflights, inflight, list) { + tal_resize(&inflights, i + 1); + inflights[i].outpoint = inflight->funding->outpoint; + inflights[i].amnt = inflight->funding->total_funds; + inflights[i].local_funding = inflight->funding->our_funds; + i++; + } + initmsg = towire_channeld_init(tmpctx, chainparams, ld->our_features, @@ -790,7 +1426,8 @@ bool peer_start_channeld(struct channel *channel, NULL), pbases, reestablish_only, - channel->channel_update); + channel->channel_update, + inflights); /* We don't expect a response: we are triggered by funding_depth_cb. */ subd_send_msg(channel->owner, take(initmsg)); @@ -803,10 +1440,13 @@ bool peer_start_channeld(struct channel *channel, get_block_height(ld->topology)); } + memset(&txid, 0, sizeof(txid)); + /* Artificial confirmation event for zeroconf */ subd_send_msg(channel->owner, take(towire_channeld_funding_depth( - NULL, channel->scid, channel->alias[LOCAL], 0))); + NULL, channel->scid, channel->alias[LOCAL], 0, false, + &txid))); return true; } @@ -816,6 +1456,8 @@ bool channel_tell_depth(struct lightningd *ld, u32 depth) { const char *txidstr; + struct txlocator *loc; + u32 outnum; txidstr = type_to_string(tmpctx, struct bitcoin_txid, txid); channel->depth = depth; @@ -827,6 +1469,35 @@ bool channel_tell_depth(struct lightningd *ld, return false; } + if (channel->state == CHANNELD_AWAITING_SPLICE + && depth >= channel->minimum_depth) { + if (!get_inflight_outpoint_index(channel, &outnum, txid)) { + log_debug(channel->log, "Can't locate splice inflight" + " txid %s", txidstr); + false; + } + + loc = wallet_transaction_locate(tmpctx, ld->wallet, txid); + if (!loc) { + channel_fail_permanent(channel, + REASON_LOCAL, + "Can't locate splice transaction" + " in wallet txid %s", txidstr); + return false; + } + + if (!mk_short_channel_id(channel->scid, + loc->blkheight, loc->index, + outnum)) { + channel_fail_permanent(channel, + REASON_LOCAL, + "Invalid splice scid %u:%u:%u", + loc->blkheight, loc->index, + channel->funding.n); + return false; + } + } + if (streq(channel->owner->name, "dualopend")) { if (channel->state != DUALOPEND_AWAITING_LOCKIN) { log_debug(channel->log, @@ -842,8 +1513,7 @@ 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_AWAITING_SPLICE) { + && !channel_state_normalish(channel)) { /* If not awaiting lockin/announce, it doesn't * care any more */ log_debug(channel->log, @@ -852,14 +1522,19 @@ bool channel_tell_depth(struct lightningd *ld, return true; } + log_debug(channel->log, + "Sending towire_channeld_funding_depth with channel state %s", + channel_state_str(channel->state)); + subd_send_msg(channel->owner, take(towire_channeld_funding_depth( - NULL, channel->scid, channel->alias[LOCAL], depth))); + NULL, channel->scid, channel->alias[LOCAL], depth, + channel->state == CHANNELD_AWAITING_SPLICE, txid))); if (channel->remote_channel_ready && channel->state == CHANNELD_AWAITING_LOCKIN && depth >= channel->minimum_depth) { - lockin_complete(channel); + lockin_complete(channel, CHANNELD_AWAITING_LOCKIN); } else if (depth == 1 && channel->minimum_depth == 0) { /* If we have a zeroconf channel, i.e., no scid yet * but have exchange `channel_ready` messages, then we @@ -1113,6 +1788,200 @@ void channel_replace_update(struct channel *channel, u8 *update TAKES) channel->channel_update))); } +/* Returns an error if load fails */ +static struct command_result *splice_load_channel(struct command *cmd, + struct channel_id *cid, + struct channel **channel) +{ + *channel = channel_by_cid(cmd->ld, cid); + if (!*channel) + return command_fail(cmd, SPLICE_UNKNOWN_CHANNEL, + "Unknown channel %s", + type_to_string(tmpctx, struct channel_id, + cid)); + + if (!feature_negotiated(cmd->ld->our_features, + (*channel)->peer->their_features, + OPT_SPLICE)) + return command_fail(cmd, SPLICE_NOT_SUPPORTED, + "splicing not supported"); + + if (!(*channel)->owner) + return command_fail(cmd, SPLICE_WRONG_OWNER, + "Channel is disconnected"); + + if (!streq((*channel)->owner->name, "channeld")) + return command_fail(cmd, + SPLICE_WRONG_OWNER, + "Channel hasn't finished connecting or in " + "abnormal owner state %s", + (*channel)->owner->name); + + if ((*channel)->state != CHANNELD_NORMAL) + return command_fail(cmd, + SPLICE_INVALID_CHANNEL_STATE, + "Channel needs to be in normal state but " + "is in state %s", + channel_state_name(*channel)); + + return NULL; +} + +static struct command_result *json_splice_init(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct channel_id *cid; + struct channel *channel; + struct command_result *error; + struct splice_command *cc; + struct wally_psbt *initialpsbt; + struct amount_sat *amount; + u32 *feerate_per_kw; + bool *force_feerate; + u8 *msg; + + if (!param(cmd, buffer, params, + p_req("channel_id", param_channel_id, &cid), + p_req("amount", param_sat, &amount), + p_opt("initialpsbt", param_psbt, &initialpsbt), + p_opt("feerate_per_kw", param_feerate, &feerate_per_kw), + p_opt("force_feerate", param_bool, &force_feerate), + NULL)) + return command_param_failed(); + + error = splice_load_channel(cmd, cid, &channel); + if (error) + return error; + + if (!initialpsbt) + initialpsbt = create_psbt(cmd, 0, 0, 0); + if (!feerate_per_kw) { + feerate_per_kw = tal(tmpctx, u32); + *feerate_per_kw = opening_feerate(cmd->ld->topology); + } + if (!force_feerate) { + force_feerate = tal(tmpctx, bool); + *force_feerate = false; + } + + cc = tal(NULL, struct splice_command); + + list_add_tail(&cmd->ld->splice_commands, &cc->list); + + cc->cmd = tal_steal(cc, cmd); + cc->channel = channel; + + msg = towire_channeld_splice_init(NULL, initialpsbt, *amount, + *feerate_per_kw, *force_feerate); + + subd_send_msg(channel->owner, take(msg)); + return command_still_pending(cmd); +} + +static struct command_result *json_splice_update(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct channel_id *cid; + struct channel *channel; + struct splice_command *cc; + struct wally_psbt *psbt; + struct command_result *error; + + if (!param(cmd, buffer, params, + p_req("channel_id", param_channel_id, &cid), + p_req("psbt", param_psbt, &psbt), + NULL)) + return command_param_failed(); + + error = splice_load_channel(cmd, cid, &channel); + if (error) + return error; + + cc = tal(NULL, struct splice_command); + + list_add_tail(&cmd->ld->splice_commands, &cc->list); + + cc->cmd = tal_steal(cc, cmd); + cc->channel = channel; + + subd_send_msg(channel->owner, + take(towire_channeld_splice_update(NULL, psbt))); + return command_still_pending(cmd); +} + +static struct command_result *json_splice_signed(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct channel_id *cid; + u8 *msg; + struct channel *channel; + struct splice_command *cc; + struct wally_psbt *psbt; + struct command_result *error; + bool *sign_first; + + if (!param(cmd, buffer, params, + p_req("channel_id", param_channel_id, &cid), + p_req("psbt", param_psbt, &psbt), + p_opt_def("sign_first", param_bool, &sign_first, false), + NULL)) + return command_param_failed(); + + error = splice_load_channel(cmd, cid, &channel); + if (error) + return error; + + cc = tal(NULL, struct splice_command); + + list_add_tail(&cmd->ld->splice_commands, &cc->list); + + cc->cmd = tal_steal(cc, cmd); + cc->channel = channel; + + assert(channel); + assert(channel->owner); + + msg = towire_channeld_splice_signed(tmpctx, psbt, *sign_first); + subd_send_msg(channel->owner, take(msg)); + return command_still_pending(cmd); +} + +static const struct json_command splice_init_command = { + "splice_init", + "channels", + json_splice_init, + "Init a channel splice to {channel_id} for {amount} satoshis with {initialpsbt}. " + "Returns updated {psbt} with (partial) contributions from peer" +}; +AUTODATA(json_command, &splice_init_command); + +static const struct json_command splice_update_command = { + "splice_update", + "channels", + json_splice_update, + "Update {channel_id} currently active negotiated splice with {psbt}. " + "" + "Returns updated {psbt} with (partial) contributions from peer. " + "If {commitments_secured} is true, next call may be to splicechannel_finalize, " + "otherwise keep calling splice_update passing back in the returned PSBT until " + "{commitments_secured} is true." +}; +AUTODATA(json_command, &splice_update_command); + +static const struct json_command splice_signed_command = { + "splice_signed", + "channels", + json_splice_signed, + "Send our {signed_psbt}'s tx sigs for {channel_id}." +}; +AUTODATA(json_command, &splice_signed_command); + #if DEVELOPER static struct command_result *json_dev_feerate(struct command *cmd, const char *buffer, @@ -1199,7 +2068,7 @@ static struct command_result *json_dev_quiesce(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_normalish(channel)) + 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/lightningd.c b/lightningd/lightningd.c index 981cf1ea9fe6..500fa61b9974 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -210,6 +210,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx) list_head_init(&ld->close_commands); list_head_init(&ld->ping_commands); list_head_init(&ld->disconnect_commands); + list_head_init(&ld->splice_commands); list_head_init(&ld->waitblockheight_commands); /*~ Tal also explicitly supports arrays: it stores the number of @@ -859,6 +860,7 @@ static struct feature_set *default_features(const tal_t *ctx) OPTIONAL_FEATURE(OPT_ANCHOR_OUTPUTS), OPTIONAL_FEATURE(OPT_QUIESCE), OPTIONAL_FEATURE(OPT_ONION_MESSAGES), + OPTIONAL_FEATURE(OPT_SPLICE), #endif }; diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index e0d27b18965e..55216c936701 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -223,6 +223,9 @@ struct lightningd { /* Outstanding disconnect commands. */ struct list_head disconnect_commands; + /* Outstanding splice commands. */ + struct list_head splice_commands; + /* Maintained by invoices.c */ struct invoices *invoices; diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 107e748cc825..8a17c1d692c0 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1736,9 +1736,9 @@ static bool check_funding_tx(const struct bitcoin_tx *tx, return false; } -static void update_channel_from_inflight(struct lightningd *ld, - struct channel *channel, - const struct channel_inflight *inflight) +void update_channel_from_inflight(struct lightningd *ld, + struct channel *channel, + const struct channel_inflight *inflight) { struct wally_psbt *psbt_copy; @@ -1805,19 +1805,18 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, /* Reorg can change scid, so always update/save scid when possible (depth=0 * means the stale block with our funding tx was removed) */ - if (channel->state != CHANNELD_AWAITING_SPLICE - && (min_depth_no_scid || some_depth_has_scid)) { + if (min_depth_no_scid || some_depth_has_scid) { struct txlocator *loc; struct channel_inflight *inf; /* Update the channel's info to the correct tx, if needed to * It's possible an 'inflight' has reached depth */ - if (!list_empty(&channel->inflights)) { + if (channel->state != CHANNELD_AWAITING_SPLICE + && !list_empty(&channel->inflights)) { inf = channel_inflight_find(channel, txid); if (!inf) { - channel_fail_permanent(channel, - REASON_LOCAL, - "Txid %s for channel" + log_debug(channel->log, + "Ignoring event for txid %s for channel" " not found in inflights. (peer %s)", type_to_string(tmpctx, struct bitcoin_txid, @@ -1846,8 +1845,9 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, /* If we restart, we could already have peer->scid from database, * we don't need to update scid for stub channels(1x1x1) */ - if (!channel->scid) { - channel->scid = tal(channel, struct short_channel_id); + if (!channel->scid || channel->state == CHANNELD_AWAITING_SPLICE) { + if(!channel->scid) + channel->scid = tal(channel, struct short_channel_id); *channel->scid = scid; wallet_channel_save(ld->wallet, channel); @@ -1865,6 +1865,8 @@ static enum watch_result funding_depth_cb(struct lightningd *ld, &channel->peer->id, channel->peer->connectd_counter, warning))); + } else if (!short_channel_id_eq(channel->scid, &scid)) { + /* When we restart channeld, it will be initialized with updated scid * and also adds it (at least our halve_chan) to rtable. */ channel_fail_transient(channel, @@ -1898,10 +1900,22 @@ static enum watch_result funding_spent(struct channel *channel, const struct block *block) { struct bitcoin_txid txid; + struct channel_inflight *inflight; + bitcoin_txid(tx, &txid); wallet_channeltxs_add(channel->peer->ld->wallet, channel, WIRE_ONCHAIND_INIT, &txid, 0, block->height); + + /* If we're doing a splice, we expect the funding transaction to be + * spent, so don't freak out and just keep watching in that case */ + list_for_each(&channel->inflights, inflight, list) { + if (bitcoin_txid_eq(&txid, + &inflight->funding->outpoint.txid)) { + return KEEP_WATCHING; + } + } + return onchaind_funding_spent(channel, tx, block->height); } @@ -1927,7 +1941,7 @@ void channel_watch_funding(struct lightningd *ld, struct channel *channel) channel_watch_wrong_funding(ld, channel); } -static void channel_watch_inflight(struct lightningd *ld, +void channel_watch_inflight(struct lightningd *ld, struct channel *channel, struct channel_inflight *inflight) { diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index a967866bf4a6..84fb10c32dd2 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -110,7 +110,14 @@ void resend_closing_transactions(struct lightningd *ld); void drop_to_chain(struct lightningd *ld, struct channel *channel, bool cooperative); +void update_channel_from_inflight(struct lightningd *ld, + struct channel *channel, + const struct channel_inflight *inflight); + void channel_watch_funding(struct lightningd *ld, struct channel *channel); +void channel_watch_inflight(struct lightningd *ld, + struct channel *channel, + struct channel_inflight *inflight); /* If this channel has a "wrong funding" shutdown, watch that too. */ void channel_watch_wrong_funding(struct lightningd *ld, struct channel *channel); diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 8446c9f097bf..045de149c67d 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1981,6 +1981,8 @@ static bool peer_save_commitsig_received(struct channel *channel, u64 commitnum, channel->next_index[LOCAL]++; + /* DTODO: Add inflight_commit_sigs to the DB */ + /* Update channel->last_sig and channel->last_tx before saving to db */ channel_set_last_tx(channel, tx, commit_sig); @@ -1994,7 +1996,7 @@ static bool peer_save_commitsig_sent(struct channel *channel, u64 commitnum) if (commitnum != channel->next_index[REMOTE]) { channel_internal_error(channel, "channel_sent_commitsig: expected commitnum %"PRIu64 - " got %"PRIu64, + " got %"PRIu64" (while sending commitsig)", channel->next_index[REMOTE], commitnum); return false; } @@ -2224,6 +2226,8 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) struct failed_htlc **failed; struct changed_htlc *changed; struct bitcoin_tx *tx; + struct commitsig **inflight_commit_sigs; + struct channel_inflight *inflight; size_t i; struct lightningd *ld = channel->peer->ld; @@ -2237,7 +2241,8 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) &fulfilled, &failed, &changed, - &tx) + &tx, + &inflight_commit_sigs) || !fee_states_valid(fee_states, channel->opener) || !height_states_valid(blockheight_states, channel->opener)) { channel_internal_error(channel, @@ -2268,11 +2273,25 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) log_debug(channel->log, "got commitsig %"PRIu64 - ": feerate %u, blockheight: %u, %zu added, %zu fulfilled, %zu failed, %zu changed", + ": feerate %u, blockheight: %u, %zu added, %zu fulfilled, " + "%zu failed, %zu changed. %zu splice commitments.", commitnum, get_feerate(fee_states, channel->opener, LOCAL), get_blockheight(blockheight_states, channel->opener, LOCAL), tal_count(added), tal_count(fulfilled), - tal_count(failed), tal_count(changed)); + tal_count(failed), tal_count(changed), + tal_count(inflight_commit_sigs)); + + i = 0; + list_for_each(&channel->inflights, inflight, list) { + i++; + } + if (i != tal_count(inflight_commit_sigs)) { + channel_internal_error(channel, "Got commitsig with incorrect " + "number of splice commitments. " + "lightningd expects %zu but got %zu.", + i, tal_count(inflight_commit_sigs)); + return; + } /* New HTLCs */ for (i = 0; i < tal_count(added); i++) { @@ -2319,8 +2338,24 @@ void peer_got_commitsig(struct channel *channel, const u8 *msg) tal_free(channel->last_htlc_sigs); channel->last_htlc_sigs = tal_steal(channel, htlc_sigs); + /* Delete all HTLCs and add last_htlc_sigs back in */ wallet_htlc_sigs_save(ld->wallet, channel->dbid, channel->last_htlc_sigs); + /* Now append htlc sigs for inflights */ + i = 0; + list_for_each(&channel->inflights, inflight, list) { + struct commitsig *commit = inflight_commit_sigs[i]; + + inflight->last_tx = tal_steal(inflight, commit->tx); + inflight->last_tx->chainparams = chainparams; + inflight->last_sig = commit->commit_signature; + wallet_inflight_save(ld->wallet, inflight); + + wallet_htlc_sigs_add(ld->wallet, channel->dbid, + inflight->funding->outpoint.txid, + commit->htlc_signatures); + i++; + } /* Tell it we've committed, and to go ahead with revoke. */ msg = towire_channeld_got_commitsig_reply(msg); diff --git a/lightningd/routehint.c b/lightningd/routehint.c index f6c5fb960fc6..43fa7580ed98 100644 --- a/lightningd/routehint.c +++ b/lightningd/routehint.c @@ -104,14 +104,14 @@ routehint_candidates(const tal_t *ctx, continue; } - /* Check channel is in CHANNELD_NORMAL */ + /* Check channel is in CHANNELD_NORMAL or CHANNELD_AWAITING_SPLICE */ candidate.c = find_channel_by_scid(peer, &r->short_channel_id); /* Try seeing if we should be using a remote alias * instead. The `listpeers` result may have returned * the REMOTE alias, because it is the only scid we * have, and it is mandatory once the channel is in - * CHANNELD_NORMAL. */ + * CHANNELD_NORMAL or CHANNELD_AWAITING_SPLICE. */ if (!candidate.c) candidate.c = find_channel_by_alias(peer, &r->short_channel_id, REMOTE); @@ -126,7 +126,8 @@ routehint_candidates(const tal_t *ctx, continue; } - if (candidate.c->state != CHANNELD_NORMAL) { + if (candidate.c->state != CHANNELD_NORMAL + && candidate.c->state != CHANNELD_AWAITING_SPLICE) { log_debug(ld->log, "%s: abnormal channel", type_to_string(tmpctx, struct short_channel_id, diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 53850ce345c8..6e9cc18f1bfa 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -678,6 +678,12 @@ struct command_result *param_u64(struct command *cmd UNNEEDED, const char *name const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED, uint64_t **num UNNEEDED) { fprintf(stderr, "param_u64 called!\n"); abort(); } +/* Generated stub for channel_state_normalish */ +bool channel_state_normalish(const struct channel *channel UNNEEDED) +{ fprintf(stderr, "channel_state_normalish called!\n"); abort(); } +/* Generated stub for channel_state_awaitish */ +bool channel_state_awaitish(const struct channel *channel UNNEEDED) +{ fprintf(stderr, "channel_state_awaitish called!\n"); abort(); } /* Generated stub for peer_any_active_channel */ struct channel *peer_any_active_channel(struct peer *peer UNNEEDED, bool *others UNNEEDED) { fprintf(stderr, "peer_any_active_channel called!\n"); abort(); } diff --git a/openingd/dualopend.c b/openingd/dualopend.c index f06fced65de8..18e01db23b4d 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -993,11 +993,13 @@ static u8 *psbt_to_tx_sigs_msg(const tal_t *ctx, { const struct witness_stack **ws = psbt_to_witness_stacks(tmpctx, psbt, - state->our_role, -1); + state->our_role, + -1); return towire_tx_signatures(ctx, &state->channel_id, &state->tx_state->funding.txid, - ws); + ws, + NULL); } static void handle_tx_sigs(struct state *state, const u8 *msg) @@ -1010,10 +1012,12 @@ static void handle_tx_sigs(struct state *state, const u8 *msg) enum tx_role their_role = state->our_role == TX_INITIATOR ? TX_ACCEPTER : TX_INITIATOR; + struct tlv_txsigs_tlvs *txsig_tlvs = tlv_txsigs_tlvs_new(tmpctx); if (!fromwire_tx_signatures(tmpctx, msg, &cid, &txid, cast_const3( struct witness_stack ***, - &ws))) + &ws), + &txsig_tlvs)) open_err_fatal(state, "Bad tx_signatures %s", tal_hex(msg, msg)); @@ -1420,9 +1424,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: break; } @@ -1796,9 +1801,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: open_abort(state, "Unexpected wire message %s", tal_hex(tmpctx, msg)); return false; @@ -1880,7 +1886,7 @@ static u8 *accepter_commits(struct state *state, struct amount_msat our_msats; struct channel_id cid; const u8 *wscript; - u8 *msg; + u8 *msg, *commit_msg; char *error; /* Find the funding transaction txid */ @@ -1918,9 +1924,12 @@ static u8 *accepter_commits(struct state *state, } remote_sig.sighash_type = SIGHASH_ALL; + + struct tlv_commitment_signed_tlvs *cs_tlv + = tlv_commitment_signed_tlvs_new(tmpctx); if (!fromwire_commitment_signed(tmpctx, msg, &cid, &remote_sig.s, - &htlc_sigs)) + &htlc_sigs, &cs_tlv)) open_err_fatal(state, "Parsing commitment signed %s", tal_hex(tmpctx, msg)); @@ -2118,10 +2127,10 @@ static u8 *accepter_commits(struct state *state, master_badmsg(WIRE_DUALOPEND_SEND_TX_SIGS, msg); /* Send our commitment sigs over now */ - peer_write(state->pps, - take(towire_commitment_signed(NULL, - &state->channel_id, - &local_sig.s, NULL))); + commit_msg = towire_commitment_signed(NULL, &state->channel_id, + &local_sig.s, NULL, NULL); + + peer_write(state->pps, take(commit_msg)); tal_free(local_commit); return msg; } @@ -2751,7 +2760,7 @@ static u8 *opener_commits(struct state *state, assert(local_sig.sighash_type == SIGHASH_ALL); msg = towire_commitment_signed(tmpctx, &state->channel_id, &local_sig.s, - NULL); + NULL, NULL); peer_write(state->pps, msg); peer_billboard(false, "channel open: commitment sent, waiting for reply"); @@ -2764,9 +2773,12 @@ static u8 *opener_commits(struct state *state, } remote_sig.sighash_type = SIGHASH_ALL; + + struct tlv_commitment_signed_tlvs *cs_tlv + = tlv_commitment_signed_tlvs_new(tmpctx); if (!fromwire_commitment_signed(tmpctx, msg, &cid, &remote_sig.s, - &htlc_sigs)) + &htlc_sigs, &cs_tlv)) open_err_fatal(state, "Parsing commitment signed %s", tal_hex(tmpctx, msg)); @@ -4155,9 +4167,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: break; } diff --git a/tests/test_splicing.py b/tests/test_splicing.py new file mode 100644 index 000000000000..320a6325fbca --- /dev/null +++ b/tests/test_splicing.py @@ -0,0 +1,48 @@ +from fixtures import * # noqa: F401,F403 +from fixtures import TEST_NETWORK +from pyln.client import RpcError, Millisatoshi +from utils import ( + only_one, wait_for, sync_blockheight, first_channel_id, calc_lease_fee +) + +import pytest +import re +import unittest +import time + +@pytest.mark.openchannel('v2') +def test_splice(node_factory, bitcoind): + l1 = node_factory.get_node() + l2 = node_factory.get_node() + + chan_size = 4000000 + + l1.rpc.connect(l2.rpc.getinfo()['id'], 'localhost:%d' % l2.port) + l1.openchannel(l2, chan_size) + + l2.daemon.wait_for_log(r'to CHANNELD_NORMAL') + l1.daemon.wait_for_log(r'to CHANNELD_NORMAL') + + time.sleep(1) + + chan_id = l1.get_channel_id(l2) + + # add extra sats to pay fee + funds_result = l1.rpc.fundpsbt("105000sat", "slow", 166, excess_as_change=True) + + chan_size += 100000 + + result = l1.rpc.splice_init(chan_id, chan_size, funds_result['psbt']) + result = l1.rpc.splice_update(chan_id, result['psbt']) + result = l1.rpc.signpsbt(result['psbt']) + result = l1.rpc.splice_signed(chan_id, result['signed_psbt']) + + bitcoind.generate_block(6, wait_for_mempool=1) + + l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + + inv = l2.rpc.invoice(10**2, '3', 'no_3') + l1.rpc.pay(inv['bolt11']) + + result = True diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index e058adef1b80..701e1b32a438 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -147,7 +147,7 @@ void fatal(const char *fmt UNNEEDED, ...) bool fromwire_channeld_dev_memleak_reply(const void *p UNNEEDED, bool *leak UNNEEDED) { fprintf(stderr, "fromwire_channeld_dev_memleak_reply called!\n"); abort(); } /* Generated stub for fromwire_channeld_got_commitsig */ -bool fromwire_channeld_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct bitcoin_signature *signature UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, struct added_htlc **added UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED) +bool fromwire_channeld_got_commitsig(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *commitnum UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct bitcoin_signature *signature UNNEEDED, struct bitcoin_signature **htlc_signature UNNEEDED, struct added_htlc **added UNNEEDED, struct fulfilled_htlc **fulfilled UNNEEDED, struct failed_htlc ***failed UNNEEDED, struct changed_htlc **changed UNNEEDED, struct bitcoin_tx **tx UNNEEDED, struct commitsig ***inflight_commitsigs UNNEEDED) { fprintf(stderr, "fromwire_channeld_got_commitsig called!\n"); abort(); } /* Generated stub for fromwire_channeld_got_revoke */ bool fromwire_channeld_got_revoke(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, u64 *revokenum UNNEEDED, struct secret *per_commitment_secret UNNEEDED, struct pubkey *next_per_commit_point UNNEEDED, struct fee_states **fee_states UNNEEDED, struct height_states **blockheight_states UNNEEDED, struct changed_htlc **changed UNNEEDED, struct penalty_base **pbase UNNEEDED, struct bitcoin_tx **penalty_tx UNNEEDED) diff --git a/wire/extracted_peer_06_funding_outpoint_sigs.patch b/wire/extracted_peer_06_funding_outpoint_sigs.patch new file mode 100644 index 000000000000..10f2df60f11f --- /dev/null +++ b/wire/extracted_peer_06_funding_outpoint_sigs.patch @@ -0,0 +1,18 @@ +--- wire/peer_exp_wire.csv 2022-06-22 19:07:24.000000000 -0500 ++++ - 2022-06-30 16:00:51.000000000 -0500 +@@ -65,12 +57,15 @@ + msgdata,tx_signatures,txid,sha256, + msgdata,tx_signatures,num_witnesses,u16, + msgdata,tx_signatures,witness_stack,witness_stack,num_witnesses ++msgdata,tx_signatures,tlvs,txsigs_tlvs, + subtype,witness_stack + subtypedata,witness_stack,num_input_witness,u16, + subtypedata,witness_stack,witness_element,witness_element,num_input_witness + subtype,witness_element + subtypedata,witness_element,len,u16, + subtypedata,witness_element,witness,byte,len ++tlvtype,txsigs_tlvs,funding_outpoint_sig,0 ++tlvdata,txsigs_tlvs,funding_outpoint_sig,sig,byte,... + msgtype,tx_init_rbf,72 + msgdata,tx_init_rbf,channel_id,channel_id, + msgdata,tx_init_rbf,locktime,u32, diff --git a/wire/extracted_peer_exp_quiescence-protocol.patch b/wire/extracted_peer_exp_quiescence-protocol.patch deleted file mode 100644 index de073f5f8153..000000000000 --- a/wire/extracted_peer_exp_quiescence-protocol.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- wire/peer_exp_wire.csv 2021-05-17 09:30:02.302260471 +0930 -+++ - 2021-05-31 12:20:36.390910632 +0930 -@@ -120,6 +82,9 @@ - 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, diff --git a/wire/fromwire.c b/wire/fromwire.c index 69139ca3b918..0a78d4cea392 100644 --- a/wire/fromwire.c +++ b/wire/fromwire.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -258,3 +259,8 @@ void fromwire_siphash_seed(const u8 **cursor, size_t *max, { fromwire(cursor, max, seed, sizeof(*seed)); } + +void fromwire_inflight(const u8 **cursor, size_t *max, struct inflight *inflight) +{ + fromwire(cursor, max, inflight, sizeof(*inflight)); +} diff --git a/wire/peer_wire.c b/wire/peer_wire.c index 1d3772c8fd65..999b52f71e9e 100644 --- a/wire/peer_wire.c +++ b/wire/peer_wire.c @@ -49,9 +49,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: return false; } return true; @@ -105,9 +106,10 @@ 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 + case WIRE_SPLICE: + case WIRE_SPLICE_ACK: + case WIRE_SPLICE_LOCKED: break; } return false; @@ -363,14 +365,36 @@ 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 + case WIRE_SPLICE: + /* BOLT-splice #2: + * 1. type: 74 (`splice`) + * 2. data: + * * [`chain_hash`:`chain_hash`] + * * [`channel_id`:`channel_id`] + * * [`u32`:`funding_feerate_perkw`] + * * [`point`:`funding_pubkey`] + */ + case WIRE_SPLICE_ACK: + /* BOLT-splice #2: + * 1. type: 76 (`splice_ack`) + * 2. data: + * * [`chain_hash`:`chain_hash`] + * * [`channel_id`:`channel_id`] + * * [`point`:`funding_pubkey`] + */ + case WIRE_SPLICE_LOCKED: + /* BOLT-splice #2: + * 1. type: 78 (`splice_locked`) + * 2. data: + * * [`chain_hash`:`chain_hash`] + * * [`channel_id`:`channel_id`] + */ return fromwire_channel_id(&cursor, &max, channel_id); } return false; diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv index 7b1e33d8c348..241f459a9465 100644 --- a/wire/peer_wire.csv +++ b/wire/peer_wire.csv @@ -63,12 +63,15 @@ msgdata,tx_signatures,channel_id,channel_id, msgdata,tx_signatures,txid,sha256, msgdata,tx_signatures,num_witnesses,u16, msgdata,tx_signatures,witnesses,witness_stack,num_witnesses +msgdata,tx_signatures,tlvs,txsigs_tlvs, subtype,witness_stack subtypedata,witness_stack,num_witness_elements,u16, subtypedata,witness_stack,witness_elements,witness_element,num_witness_elements subtype,witness_element subtypedata,witness_element,len,u16, subtypedata,witness_element,witness_data,byte,len +tlvtype,txsigs_tlvs,funding_outpoint_sig,0 +tlvdata,txsigs_tlvs,funding_outpoint_sig,sig,byte,... msgtype,tx_init_rbf,72 msgdata,tx_init_rbf,channel_id,channel_id, msgdata,tx_init_rbf,locktime,u32, @@ -203,6 +206,23 @@ 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,splice,75 +msgdata,splice,channel_id,channel_id, +msgdata,splice,chain_hash,chain_hash, +msgdata,splice,funding_satoshis,u64, +msgdata,splice,funding_feerate_perkw,u32, +msgdata,splice,locktime,u32, +msgdata,splice,funding_pubkey,point, +msgtype,splice_ack,76 +msgdata,splice_ack,channel_id,channel_id, +msgdata,splice_ack,chain_hash,chain_hash, +msgdata,splice_ack,funding_satoshis,u64, +msgdata,splice_ack,funding_pubkey,point, +msgtype,splice_locked,78, +msgdata,splice_locked,channel_id,channel_id, msgtype,shutdown,38 msgdata,shutdown,channel_id,channel_id, msgdata,shutdown,len,u16, @@ -248,6 +268,9 @@ msgdata,commitment_signed,channel_id,channel_id, msgdata,commitment_signed,signature,signature, msgdata,commitment_signed,num_htlcs,u16, msgdata,commitment_signed,htlc_signature,signature,num_htlcs +msgdata,commitment_signed,splice_channel_id,commitment_signed_tlvs, +tlvtype,commitment_signed_tlvs,splice_info,0 +tlvdata,commitment_signed_tlvs,splice_info,splice_channel_id,channel_id, msgtype,revoke_and_ack,133 msgdata,revoke_and_ack,channel_id,channel_id, msgdata,revoke_and_ack,per_commitment_secret,byte,32 diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index c5a8179ff812..997f661cf56e 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -160,6 +160,7 @@ struct msg_commitment_signed { struct channel_id channel_id; secp256k1_ecdsa_signature signature; secp256k1_ecdsa_signature *htlc_signature; + struct tlv_commitment_signed_tlvs tlvs; }; struct msg_node_announcement { secp256k1_ecdsa_signature signature; @@ -525,7 +526,8 @@ static void *towire_struct_commitment_signed(const tal_t *ctx, return towire_commitment_signed(ctx, &s->channel_id, &s->signature, - s->htlc_signature); + s->htlc_signature, + &s->tlvs); } static struct msg_commitment_signed *fromwire_struct_commitment_signed(const tal_t *ctx, const void *p) @@ -535,7 +537,8 @@ static struct msg_commitment_signed *fromwire_struct_commitment_signed(const tal if (!fromwire_commitment_signed(s, p, &s->channel_id, &s->signature, - &s->htlc_signature)) + &s->htlc_signature, + NULL)) return tal_free(s); return s; } diff --git a/wire/towire.c b/wire/towire.c index 49eae1523b95..f495543df3a8 100644 --- a/wire/towire.c +++ b/wire/towire.c @@ -4,6 +4,7 @@ #include #include #include +#include #include void towire(u8 **pptr, const void *data, size_t len) @@ -145,3 +146,8 @@ void towire_siphash_seed(u8 **pptr, const struct siphash_seed *seed) { towire(pptr, seed, sizeof(*seed)); } + +void towire_inflight(u8 **pptr, const struct inflight *inflight) +{ + towire(pptr, inflight, sizeof(*inflight)); +} diff --git a/wire/wire.h b/wire/wire.h index 3b07a021bea9..1a0fb357bb05 100644 --- a/wire/wire.h +++ b/wire/wire.h @@ -11,6 +11,7 @@ struct ripemd160; struct sha256; struct siphash_seed; +struct inflight; /* Makes generate-wire.py work */ typedef char wirestring; @@ -44,6 +45,8 @@ void towire_utf8_array(u8 **pptr, const char *arr, size_t num); void towire_wirestring(u8 **pptr, const char *str); void towire_siphash_seed(u8 **cursor, const struct siphash_seed *seed); +void towire_inflight(u8 **cursor, const struct inflight *inflight); + const u8 *fromwire(const u8 **cursor, size_t *max, void *copy, size_t n); u8 fromwire_u8(const u8 **cursor, size_t *max); u16 fromwire_u16(const u8 **cursor, size_t *max); @@ -71,6 +74,8 @@ char *fromwire_wirestring(const tal_t *ctx, const u8 **cursor, size_t *max); void fromwire_siphash_seed(const u8 **cursor, size_t *max, struct siphash_seed *seed); +void fromwire_inflight(const u8 **cursor, size_t *max, struct inflight *inflight); + #if !EXPERIMENTAL_FEATURES /* Stubs, as this subtype is only defined when EXPERIMENTAL_FEATURES */ struct onionmsg_path;