diff --git a/bitcoin/psbt.c b/bitcoin/psbt.c index 34153e94a397..42a89bfb8ffd 100644 --- a/bitcoin/psbt.c +++ b/bitcoin/psbt.c @@ -290,6 +290,27 @@ bool psbt_input_set_signature(struct wally_psbt *psbt, size_t in, return ok; } +bool psbt_input_have_signature(const struct wally_psbt *psbt, + size_t in, + const struct pubkey *pubkey, + bool *signature_found) +{ + u8 pk_der[PUBKEY_CMPR_LEN]; + size_t index_plus_one; + bool ok; + + assert(in < psbt->num_inputs); + + pubkey_to_der(pk_der, pubkey); + + ok = wally_psbt_input_find_signature(&psbt->inputs[in], pk_der, + sizeof(pk_der), + &index_plus_one) == WALLY_OK; + if (ok) + *signature_found = index_plus_one > 0; + return ok; +} + void psbt_input_set_wit_utxo(struct wally_psbt *psbt, size_t in, const u8 *scriptPubkey, struct amount_sat amt) { diff --git a/bitcoin/psbt.h b/bitcoin/psbt.h index 49682b09ebba..4c693c8a3636 100644 --- a/bitcoin/psbt.h +++ b/bitcoin/psbt.h @@ -178,6 +178,14 @@ WARN_UNUSED_RESULT bool psbt_input_set_signature(struct wally_psbt *psbt, size_t const struct pubkey *pubkey, const struct bitcoin_signature *sig); +/* Returns false on error. On success, *signature_found is set to true if the + * input has a signature present for `pubkey` and false if if one was not found. + * Only ignature presence is checked, is not validated. */ +WARN_UNUSED_RESULT bool psbt_input_have_signature(const struct wally_psbt *psbt, + size_t in, + const struct pubkey *pubkey, + bool *signature_found); + void psbt_input_set_witscript(struct wally_psbt *psbt, size_t in, const u8 *wscript); /* psbt_input_set_unknown - Set the given Key-Value in the psbt's input keymap diff --git a/channeld/channeld.c b/channeld/channeld.c index e91da4688766..a4ea9219c744 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -90,7 +90,8 @@ struct peer { struct pubkey remote_per_commit; /* Remotes's last per-commitment point: we keep this to check - * revoke_and_ack's `per_commitment_secret` is correct. */ + * revoke_and_ack's `per_commitment_secret` is correct and for + * splices. */ struct pubkey old_remote_per_commit; /* Their sig for current commit. */ @@ -786,14 +787,12 @@ static void check_mutual_splice_locked(struct peer *peer) /* We must regossip the scid since it has changed */ peer->gossip_scid_announced = false; - channel_announcement_negotiate(peer); + if (channel_announcement_negotiate(peer)) + send_channel_update(peer, true); billboard_update(peer); - send_channel_update(peer, true); peer->splice_state->inflights = tal_free(peer->splice_state->inflights); peer->splice_state->count = 0; - peer->splice_state->revoked_count = 0; - peer->splice_state->committed_count = 0; } /* Our peer told us they saw our splice confirm on chain with `splice_locked`. @@ -815,6 +814,13 @@ static void handle_peer_splice_locked(struct peer *peer, const u8 *msg) type_to_string(msg, struct channel_id, &peer->channel_id)); + /* If we've `mutual_splice_locked` but our peer hasn't, we can ignore + * this message harmlessly */ + if (!tal_count(peer->splice_state->inflights)) { + status_info("Peer sent redundant splice_locked, ignoring"); + return; + } + peer->splice_state->locked_ready[REMOTE] = true; check_mutual_splice_locked(peer); } @@ -906,13 +912,15 @@ static void handle_peer_announcement_signatures(struct peer *peer, const u8 *msg * `short_channel_id` matches the pre-splice short channel id. */ if (peer->splice_state->await_commitment_succcess && !short_channel_id_eq(&remote_scid, - &peer->short_channel_ids[LOCAL])) + &peer->short_channel_ids[LOCAL])) { status_info("Ignoring stale announcement_signatures: expected" " %s, got %s", type_to_string(tmpctx, struct short_channel_id, - &peer->short_channel_ids[REMOTE]), + &peer->short_channel_ids[LOCAL]), type_to_string(tmpctx, struct short_channel_id, - &peer->short_channel_ids[LOCAL])); + &remote_scid)); + return; + } peer->short_channel_ids[REMOTE] = remote_scid; @@ -1315,6 +1323,7 @@ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx, const u8 *funding_wscript, const struct htlc **htlc_map, u64 commit_index, + const struct pubkey *remote_per_commit, struct bitcoin_signature *commit_sig) { struct simple_htlc **htlcs; @@ -1326,7 +1335,7 @@ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx, htlcs = collect_htlcs(tmpctx, htlc_map); msg = towire_hsmd_sign_remote_commitment_tx(NULL, txs[0], &peer->channel->funding_pubkey[REMOTE], - &peer->remote_per_commit, + remote_per_commit, channel_has(peer->channel, OPT_STATIC_REMOTEKEY), commit_index, @@ -1350,7 +1359,7 @@ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx, dump_htlcs(peer->channel, "Sending commit_sig"); if (!derive_simple_key(&peer->channel->basepoints[LOCAL].htlc, - &peer->remote_per_commit, + remote_per_commit, &local_htlckey)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Deriving local_htlckey"); @@ -1370,7 +1379,7 @@ static struct bitcoin_signature *calc_commitsigs(const tal_t *ctx, wscript = bitcoin_tx_output_get_witscript(tmpctx, txs[0], txs[i+1]->wtx->inputs[0].index); msg = towire_hsmd_sign_remote_htlc_tx(NULL, txs[i + 1], wscript, - &peer->remote_per_commit, + remote_per_commit, channel_has_anchors(peer->channel)); msg = hsm_req(tmpctx, take(msg)); @@ -1511,6 +1520,7 @@ static u8 *send_commit_part(const tal_t *ctx, s64 splice_amnt, s64 remote_splice_amnt, u64 remote_index, + const struct pubkey *remote_per_commit, struct local_anchor_info **anchor) { u8 *msg; @@ -1539,12 +1549,12 @@ static u8 *send_commit_part(const tal_t *ctx, txs = channel_txs(tmpctx, funding, funding_sats, &htlc_map, direct_outputs, &funding_wscript, - peer->channel, &peer->remote_per_commit, + peer->channel, remote_per_commit, remote_index, REMOTE, splice_amnt, remote_splice_amnt, &local_anchor_outnum); htlc_sigs = calc_commitsigs(tmpctx, peer, txs, funding_wscript, htlc_map, - remote_index, &commit_sig); + remote_index, remote_per_commit, &commit_sig); if (direct_outputs[LOCAL] != NULL) { pbase = penalty_base_new(tmpctx, remote_index, @@ -1702,9 +1712,7 @@ static void send_commit(struct peer *peer) */ changed_htlcs = tal_arr(tmpctx, const struct htlc *, 0); - if (peer->splice_state->committed_count == peer->splice_state->count - && !channel_sending_commit(peer->channel, &changed_htlcs)) { - + if (!channel_sending_commit(peer->channel, &changed_htlcs)) { status_debug("Can't send commit: nothing to send," " feechange %s (%s)" " blockheight %s (%s)", @@ -1724,7 +1732,7 @@ static void send_commit(struct peer *peer) msgs[0] = send_commit_part(msgs, peer, &peer->channel->funding, peer->channel->funding_sats, changed_htlcs, true, 0, 0, peer->next_index[REMOTE], - &local_anchor); + &peer->remote_per_commit, &local_anchor); if (local_anchor) tal_arr_expand(&anchors_info, *local_anchor); @@ -1751,6 +1759,7 @@ static void send_commit(struct peer *peer) peer->splice_state->inflights[i]->splice_amnt, remote_splice_amnt, peer->next_index[REMOTE], + &peer->remote_per_commit, &local_anchor)); if (local_anchor) tal_arr_expand(&anchors_info, *local_anchor); @@ -1766,8 +1775,6 @@ static void send_commit(struct peer *peer) for(u32 i = 0; i < tal_count(msgs); i++) peer_write(peer->pps, take(msgs[i])); - peer->splice_state->committed_count = peer->splice_state->count; - maybe_send_shutdown(peer); /* Timer now considered expired, you can add a new one. */ @@ -1973,13 +1980,20 @@ struct commitsig_info { * consecutive commitment messages equal to the number of inflight splices. * * Returns the last commitsig received. When splicing this is the - * newest splice commit sig. */ + * newest splice commit sig. + * + * `commit_index` 0 refers to the funding commit. `commit_index` 1 and above + * refer to inflight splices. + */ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, - const u8 *msg, - u32 commit_index, - const struct htlc **changed_htlcs, - s64 splice_amnt, - s64 remote_splice_amnt) + const u8 *msg, + u32 commit_index, + const struct htlc **changed_htlcs, + s64 splice_amnt, + s64 remote_splice_amnt, + u64 local_index, + const struct pubkey *local_per_commit, + bool allow_empty_commit) { struct commitsig_info *result; struct channel_id channel_id; @@ -2040,7 +2054,7 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, if (!changed_htlcs) { changed_htlcs = tal_arr(msg, const struct htlc *, 0); if (!channel_rcvd_commit(peer->channel, &changed_htlcs) - && peer->splice_state->count == peer->splice_state->revoked_count) { + && !allow_empty_commit) { /* BOLT #2: * * A sending node: @@ -2082,8 +2096,8 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, txs = channel_txs(tmpctx, &outpoint, funding_sats, &htlc_map, NULL, &funding_wscript, peer->channel, - &peer->next_local_per_commit, - peer->next_index[LOCAL], LOCAL, splice_amnt, + local_per_commit, + local_index, LOCAL, splice_amnt, remote_splice_amnt, &remote_anchor_outnum); /* Set the commit_sig on the commitment tx psbt */ @@ -2094,7 +2108,7 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, "Unable to set signature internally"); if (!derive_simple_key(&peer->channel->basepoints[REMOTE].htlc, - &peer->next_local_per_commit, &remote_htlckey)) + local_per_commit, &remote_htlckey)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Deriving remote_htlckey"); status_debug("Derived key %s from basepoint %s, point %s", @@ -2102,7 +2116,7 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, type_to_string(tmpctx, struct pubkey, &peer->channel->basepoints[REMOTE].htlc), type_to_string(tmpctx, struct pubkey, - &peer->next_local_per_commit)); + local_per_commit)); /* BOLT #2: * * A receiving node: @@ -2120,7 +2134,7 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, " %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], + local_index, type_to_string(msg, struct bitcoin_signature, &commit_sig), type_to_string(msg, struct bitcoin_tx, txs[0]), @@ -2131,9 +2145,11 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, 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)), + cs_tlv && cs_tlv->splice_info + ? type_to_string(tmpctx, + struct channel_id, + cs_tlv->splice_info) + : "N/A", peer->splice_state->await_commitment_succcess ? "yes" : "no", tal_count(peer->splice_state->inflights)); @@ -2198,7 +2214,7 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, msg2 = towire_hsmd_validate_commitment_tx(NULL, txs[0], (const struct simple_htlc **) htlcs, - peer->next_index[LOCAL], + local_index, channel_feerate(peer->channel, LOCAL), &commit_sig, htlc_sigs); @@ -2243,17 +2259,18 @@ static struct commitsig_info *handle_peer_commit_sig(struct peer *peer, "WIRE_COMMITMENT_SIGNED but got %s", peer_wire_name(type)); - /* We purposely just store the last commit msg */ + /* We purposely just store the last commit msg in result */ result = handle_peer_commit_sig(peer, splice_msg, i + 1, changed_htlcs, sub_splice_amnt, - funding_diff - sub_splice_amnt); + funding_diff - sub_splice_amnt, + local_index, local_per_commit, + allow_empty_commit); old_secret = result->old_secret; tal_arr_expand(&commitsigs, result->commitsig); tal_steal(commitsigs, result); } assert(old_secret); - peer->splice_state->revoked_count = peer->splice_state->count; send_revocation(peer, &commit_sig, htlc_sigs, changed_htlcs, txs[0], old_secret, &next_point, commitsigs); @@ -2782,13 +2799,13 @@ static void add_amount_to_side(struct peer *peer, } static bool do_i_sign_first(struct peer *peer, struct wally_psbt *psbt, - enum tx_role our_role) + enum tx_role our_role, bool force_sign_first) { struct amount_msat in[NUM_TX_ROLES]; /* BOLT-0d8b701614b09c6ee4172b04da2203e73deec7e2 #2: * - MAY send `tx_signatures` first. */ - if (peer->splicing->force_sign_first) + if (force_sign_first) return true; in[TX_INITIATOR] = AMOUNT_MSAT(0); @@ -2824,17 +2841,19 @@ static struct wally_psbt *next_splice_step(const tal_t *ctx, return ictx->desired_psbt; } -static const u8 *peer_expect_msg(const tal_t *ctx, - struct peer *peer, - enum peer_wire expect_type, - enum peer_wire second_allowed_type) +static const u8 *peer_expect_msg_three(const tal_t *ctx, + struct peer *peer, + enum peer_wire expect_type, + enum peer_wire second_allowed_type, + enum peer_wire third_allowed_type) { u8 *msg; enum peer_wire type; msg = peer_read(ctx, peer->pps); type = fromwire_peektype(msg); - if (type != expect_type && type != second_allowed_type) + if (type != expect_type && type != second_allowed_type + && type != third_allowed_type) peer_failed_warn(peer->pps, &peer->channel_id, "Got incorrect message from peer: %s" " (should be %s) [%s]", @@ -2847,63 +2866,100 @@ static const u8 *peer_expect_msg(const tal_t *ctx, /* 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. */ + * required commitments as part of the splicing process. + * If the first message received is `tx_abort` or `tx_signatures, NULL is + * returned. */ static struct commitsig *interactive_send_commitments(struct peer *peer, struct wally_psbt *psbt, - enum tx_role our_role) + enum tx_role our_role, + size_t inflight_index, + bool send_commitments, + bool recv_commitments, + const u8 **msg_received) { struct commitsig_info *result; - const u8 *msg, *commit_msg; + const u8 *msg; + struct pubkey my_current_per_commitment_point; + struct inflight *inflight = peer->splice_state->inflights[inflight_index]; + s64 funding_diff = sats_diff(inflight->amnt, + peer->channel->funding_sats); + s64 remote_splice_amnt = funding_diff - inflight->splice_amnt; + struct local_anchor_info *local_anchor; + u64 next_index_local = peer->next_index[LOCAL]; + u64 next_index_remote = peer->next_index[REMOTE]; - commit_msg = NULL; + if(msg_received) + *msg_received = NULL; - if (do_i_sign_first(peer, psbt, our_role)) { + if (do_i_sign_first(peer, psbt, our_role, inflight->force_sign_first) + && send_commitments) { status_debug("Splice %s: we commit first", our_role == TX_INITIATOR ? "initiator" : "accepter"); - send_commit(peer); + peer_write(peer->pps, send_commit_part(tmpctx, + peer, + &inflight->outpoint, + inflight->amnt, + NULL, false, + inflight->splice_amnt, + remote_splice_amnt, + next_index_remote - 1, + &peer->old_remote_per_commit, + &local_anchor)); + } - /* If both sides commit simultaneously, that's fine. */ - msg = peer_expect_msg(tmpctx, peer, WIRE_REVOKE_AND_ACK, - WIRE_COMMITMENT_SIGNED); + result = NULL; - /* If commitments happened simultaneously, we'll get a - * commitment signed message, followed by revoke and ack. - */ - if (fromwire_peektype(msg) == WIRE_COMMITMENT_SIGNED) { - commit_msg = msg; - result = handle_peer_commit_sig(peer, commit_msg, 0, - NULL, 0, 0); + if (recv_commitments) { + msg = peer_expect_msg_three(tmpctx, peer, + WIRE_COMMITMENT_SIGNED, + WIRE_TX_SIGNATURES, + WIRE_TX_ABORT); - msg = peer_expect_msg(tmpctx, peer, - WIRE_REVOKE_AND_ACK, 0); - } - - handle_peer_revoke_and_ack(peer, msg); - } + if (msg_received) + *msg_received = msg; - if (!commit_msg) { - commit_msg = peer_expect_msg(tmpctx, peer, - WIRE_COMMITMENT_SIGNED, 0); - result = handle_peer_commit_sig(peer, commit_msg, 0, - NULL, 0, 0); + /* Funding counts as 0th commit so we do inflight_index + 1 */ + if (fromwire_peektype(msg) == WIRE_COMMITMENT_SIGNED) { + get_per_commitment_point(next_index_local - 1, + &my_current_per_commitment_point, NULL); + + result = handle_peer_commit_sig(peer, msg, + inflight_index + 1, + NULL, + inflight->splice_amnt, + remote_splice_amnt, + next_index_local - 1, + &my_current_per_commitment_point, + true); + } } - if (!do_i_sign_first(peer, psbt, our_role)) { + if (!do_i_sign_first(peer, psbt, our_role, inflight->force_sign_first) + && send_commitments) { status_debug("Splice %s: we commit second", our_role == TX_INITIATOR ? "initiator" : "accepter"); - send_commit(peer); - - msg = peer_expect_msg(tmpctx, peer, - WIRE_REVOKE_AND_ACK, 0); - - handle_peer_revoke_and_ack(peer, msg); + peer_write(peer->pps, send_commit_part(tmpctx, + peer, + &inflight->outpoint, + inflight->amnt, + NULL, false, + inflight->splice_amnt, + remote_splice_amnt, + next_index_remote - 1, + &peer->old_remote_per_commit, + &local_anchor)); } - return result->commitsig; + /* Sending and receiving splice commit should not increment commit + * related indices */ + assert(next_index_local == peer->next_index[LOCAL]); + assert(next_index_remote == peer->next_index[REMOTE]); + + return result ? result->commitsig : NULL; } static struct wally_psbt_output *find_channel_output(struct peer *peer, @@ -2917,7 +2973,7 @@ static struct wally_psbt_output *find_channel_output(struct peer *peer, &peer->channel->funding_pubkey[LOCAL], &peer->channel->funding_pubkey[REMOTE]); - scriptpubkey = scriptpubkey_p2wsh(psbt, wit_script); + scriptpubkey = scriptpubkey_p2wsh(tmpctx, wit_script); for (size_t i = 0; i < psbt->num_outputs; i++) { if (memeq(psbt->outputs[i].script, @@ -3323,12 +3379,69 @@ static void update_view_from_inflights(struct peer *peer) } } -/* Called to finish an ongoing splice OR on restart from chanenl_reestablish */ +static struct inflight *last_inflight(struct peer *peer) +{ + size_t count = tal_count(peer->splice_state->inflights); + + if (count) + return peer->splice_state->inflights[count - 1]; + + return NULL; +} + +static size_t last_inflight_index(struct peer *peer) +{ + assert(tal_count(peer->splice_state->inflights) > 0); + + return tal_count(peer->splice_state->inflights) - 1; +} + +static bool have_i_signed_inflight(const struct peer *peer, + const struct inflight *inflight) +{ + bool has_sig; + u32 index; + + index = find_channel_funding_input(inflight->psbt, + &peer->channel->funding); + + if (!psbt_input_have_signature(inflight->psbt, index, + &peer->channel->funding_pubkey[LOCAL], + &has_sig)) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable parse inflight psbt"); + + return has_sig; +} + +static bool check_tx_abort(struct peer *peer, const u8 *msg) +{ + if (!msg || fromwire_peektype(msg) != WIRE_TX_ABORT) + return false; + + if (have_i_signed_inflight(peer, last_inflight(peer))) { + peer_failed_err(peer->pps, &peer->channel_id, "tx_abort" + " is not allowed after I have sent my" + " signature. msg: %s", + tal_hex(tmpctx, msg)); + } + + /* DTODO: Remove last_inflight */ + + return true; +} + +/* Called to finish an ongoing splice OR on restart from chanenl_reestablish. */ static void resume_splice_negotiation(struct peer *peer, - struct inflight *inflight, - bool skip_commitments, - enum tx_role our_role) + bool send_commitments, + bool recv_commitments, + bool send_signature, + bool recv_signature) { + struct inflight *inflight = last_inflight(peer); + enum tx_role our_role = inflight->i_am_initiator + ? TX_INITIATOR + : TX_ACCEPTER; const u8 *wit_script; struct channel_id cid; enum peer_wire type; @@ -3346,8 +3459,17 @@ static void resume_splice_negotiation(struct peer *peer, struct bitcoin_signature their_sig; struct pubkey *their_pubkey; struct bitcoin_tx *final_tx; + struct bitcoin_txid final_txid; u8 **wit_stack; struct tlv_txsigs_tlvs *txsig_tlvs, *their_txsigs_tlvs; + const u8 *msg_received; + + status_info("Splice negotation, will %ssend commit, %srecv commit," + " %ssend signature, %srecv signature", + send_commitments ? "" : "not ", + recv_commitments ? "" : "not ", + send_signature ? "" : "not ", + recv_signature ? "" : "not "); wit_script = bitcoin_redeem_2of2(tmpctx, &peer->channel->funding_pubkey[LOCAL], @@ -3358,10 +3480,20 @@ static void resume_splice_negotiation(struct peer *peer, splice_funding_index = find_channel_funding_input(current_psbt, &peer->channel->funding); - if (!skip_commitments) { - their_commit = interactive_send_commitments(peer, current_psbt, - our_role); + msg_received = NULL; + their_commit = interactive_send_commitments(peer, current_psbt, + our_role, + last_inflight_index(peer), + send_commitments, + recv_commitments, + &msg_received); + + if (check_tx_abort(peer, msg_received)) + return; + if (their_commit) { + if (inflight->last_tx != their_commit->tx) + inflight->last_tx = tal_free(inflight->last_tx); inflight->last_tx = tal_steal(inflight, their_commit->tx); inflight->last_sig = their_commit->commit_signature; @@ -3371,6 +3503,12 @@ static void resume_splice_negotiation(struct peer *peer, wire_sync_write(MASTER_FD, take(msg)); } + if (!inflight->last_tx) + peer_failed_err(peer->pps, &peer->channel_id, + "Splice needs commitment signature to continue" + " but your last msg was %s", + msg_received ? tal_hex(tmpctx, msg_received) : "NULL"); + /* DTODO Validate splice tx takes none of our funds in either: * 1) channel balance * 2) other side sneakily adding other outputs we own @@ -3407,155 +3545,198 @@ static void resume_splice_negotiation(struct peer *peer, "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, current_psbt)); - - + 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, + current_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); + /* DTODO: is this finalize call required? */ + psbt_finalize(current_psbt); + outws = psbt_to_witnesses(tmpctx, current_psbt, our_role, splice_funding_index); sigmsg = towire_tx_signatures(tmpctx, &peer->channel_id, &inflight->outpoint.txid, outws, txsig_tlvs); - if (do_i_sign_first(peer, current_psbt, our_role)) { + psbt_txid(tmpctx, current_psbt, &final_txid, NULL); + + if (do_i_sign_first(peer, current_psbt, our_role, + inflight->force_sign_first) + && send_signature) { msg = towire_channeld_update_inflight(NULL, current_psbt, NULL, NULL); wire_sync_write(MASTER_FD, take(msg)); + + msg = towire_channeld_splice_sending_sigs(tmpctx, &final_txid); + wire_sync_write(MASTER_FD, take(msg)); + peer_write(peer->pps, sigmsg); - status_debug("Splice: we signed first"); } - msg = peer_read(tmpctx, peer->pps); + their_pubkey = &peer->channel->funding_pubkey[REMOTE]; - type = fromwire_peektype(msg); + if (recv_signature) { + if (fromwire_peektype(msg_received) == WIRE_TX_SIGNATURES) + msg = msg_received; + else + msg = peer_read(tmpctx, peer->pps); - if (handle_peer_error_or_warning(peer->pps, msg)) - return; + type = fromwire_peektype(msg); - 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, &inflight->outpoint.txid, - cast_const3(struct witness ***, &inws), - &their_txsigs_tlvs)) - peer_failed_warn(peer->pps, &peer->channel_id, - "Splicing bad tx_signatures %s", - tal_hex(msg, msg)); + if (check_tx_abort(peer, msg)) + return; - /* BOLT-0d8b701614b09c6ee4172b04da2203e73deec7e2 #2: - * - Upon receipt of `tx_signatures` for the splice transaction: - * - MUST consider splice negotiation complete. - * - MUST consider the connection no longer quiescent. - */ - end_stfu_mode(peer); + if (handle_peer_error_or_warning(peer->pps, msg)) + return; - /* BOLT-a8b9f495cac28124c69cc5ee429f9ef2bacb9921 #2: - * Both nodes: - * - MUST sign the transaction using SIGHASH_ALL */ - their_sig.sighash_type = SIGHASH_ALL; + 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)); - if (!signature_from_der(their_txsigs_tlvs->funding_outpoint_sig, - tal_count(their_txsigs_tlvs->funding_outpoint_sig), - &their_sig)) { + their_txsigs_tlvs = tlv_txsigs_tlvs_new(tmpctx); + if (!fromwire_tx_signatures(tmpctx, msg, &cid, + &inflight->outpoint.txid, + cast_const3(struct witness ***, + &inws), + &their_txsigs_tlvs)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing bad tx_signatures %s", + tal_hex(msg, msg)); - peer_failed_warn(peer->pps, &peer->channel_id, - "Splicing bad tx_signatures %s", - tal_hex(msg, msg)); - } + /* BOLT-0d8b701614b09c6ee4172b04da2203e73deec7e2 #2: + * - Upon receipt of `tx_signatures` for the splice transaction: + * - MUST consider splice negotiation complete. + * - MUST consider the connection no longer quiescent. + */ + end_stfu_mode(peer); - their_pubkey = &peer->channel->funding_pubkey[REMOTE]; + /* BOLT-a8b9f495cac28124c69cc5ee429f9ef2bacb9921 #2: + * Both nodes: + * - MUST sign the transaction using SIGHASH_ALL */ + their_sig.sighash_type = SIGHASH_ALL; - /* Set the commit_sig on the commitment tx psbt */ - if (!psbt_input_set_signature(current_psbt, - splice_funding_index, - their_pubkey, - &their_sig)) { + if (!signature_from_der(their_txsigs_tlvs->funding_outpoint_sig, + tal_count(their_txsigs_tlvs->funding_outpoint_sig), + &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, current_psbt)); - } + peer_failed_warn(peer->pps, &peer->channel_id, + "Splicing bad tx_signatures %s", + tal_hex(msg, msg)); + } - psbt_input_set_witscript(current_psbt, - splice_funding_index, - wit_script); + /* Set the commit_sig on the commitment tx psbt */ + if (!psbt_input_set_signature(current_psbt, + splice_funding_index, + their_pubkey, + &their_sig)) { - if (tal_count(inws) > current_psbt->num_inputs) - peer_failed_warn(peer->pps, &peer->channel_id, - "%zu too many witness elements received", - tal_count(inws) - current_psbt->num_inputs); - - /* We put the PSBT + sigs all together */ - for (size_t j = 0, i = 0; i < current_psbt->num_inputs; i++) { - struct wally_psbt_input *in = - ¤t_psbt->inputs[i]; - u64 in_serial; - - 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, - current_psbt)); - return; + 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, + current_psbt)); } - if (in_serial % 2 == our_role) - continue; - if (i == splice_funding_index) - continue; + psbt_input_set_witscript(current_psbt, + splice_funding_index, + wit_script); - if (j == tal_count(inws)) - peer_failed_warn(peer->pps, - &peer->channel_id, - "Mismatch witness stack count %s", - tal_hex(msg, msg)); + if (tal_count(inws) > current_psbt->num_inputs) + peer_failed_warn(peer->pps, &peer->channel_id, + "%zu too many witness elements" + " received", + tal_count(inws) - current_psbt->num_inputs); + + /* We put the PSBT + sigs all together */ + for (size_t j = 0, i = 0; i < current_psbt->num_inputs; i++) { + struct wally_psbt_input *in = + ¤t_psbt->inputs[i]; + u64 in_serial; + + 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, + current_psbt)); + return; + } + if (in_serial % 2 == our_role) + continue; - psbt_finalize_input(current_psbt, in, inws[j++]); - } + if (i == splice_funding_index) + continue; - final_tx = bitcoin_tx_with_psbt(tmpctx, current_psbt); + if (j == tal_count(inws)) + peer_failed_warn(peer->pps, + &peer->channel_id, + "Mismatch witness stack count." + " Most likely you are missing" + " signatures. Your" + " TX_SIGNATURES message: %s.", + tal_hex(msg, msg)); - wit_stack = bitcoin_witness_2of2(current_psbt, &splice_sig, &their_sig, - &peer->channel->funding_pubkey[LOCAL], - their_pubkey); + psbt_finalize_input(current_psbt, in, inws[j++]); + } - bitcoin_tx_input_set_witness(final_tx, splice_funding_index, wit_stack); + final_tx = bitcoin_tx_with_psbt(tmpctx, current_psbt); - /* We let core validate our peer's signatures are correct. */ + wit_stack = bitcoin_witness_2of2(final_tx, &splice_sig, + &their_sig, + &peer->channel->funding_pubkey[LOCAL], + their_pubkey); - msg = towire_channeld_update_inflight(NULL, current_psbt, NULL, NULL); - wire_sync_write(MASTER_FD, take(msg)); + bitcoin_tx_input_set_witness(final_tx, splice_funding_index, + wit_stack); + + /* We let core validate our peer's signatures are correct. */ + + msg = towire_channeld_update_inflight(NULL, current_psbt, NULL, + NULL); + wire_sync_write(MASTER_FD, take(msg)); + } + + if (!do_i_sign_first(peer, current_psbt, our_role, + inflight->force_sign_first) + && send_signature) { + msg = towire_channeld_splice_sending_sigs(tmpctx, &final_txid); + wire_sync_write(MASTER_FD, take(msg)); - if (!do_i_sign_first(peer, current_psbt, our_role)) { peer_write(peer->pps, sigmsg); status_debug("Splice: we signed second"); } peer->splicing = tal_free(peer->splicing); - msg = towire_channeld_splice_confirmed_signed(tmpctx, final_tx, - chan_output_index); - wire_sync_write(MASTER_FD, take(msg)); + if (recv_signature) { + msg = towire_channeld_splice_confirmed_signed(tmpctx, final_tx, + chan_output_index); + wire_sync_write(MASTER_FD, take(msg)); - send_channel_update(peer, true); + send_channel_update(peer, true); + } } static struct inflight *inflights_new(struct peer *peer) @@ -3725,7 +3906,8 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) both_amount, peer->splicing->accepter_relative, ictx->current_psbt, - false); + false, + peer->splicing->force_sign_first); master_wait_sync_reply(tmpctx, peer, take(msg), WIRE_CHANNELD_GOT_INFLIGHT); @@ -3740,6 +3922,7 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) new_inflight->splice_amnt = peer->splicing->accepter_relative; new_inflight->last_tx = NULL; new_inflight->i_am_initiator = false; + new_inflight->force_sign_first = peer->splicing->force_sign_first; current_push_val = relative_splice_balance_fundee(peer, our_role,ictx->current_psbt, outpoint.n, splice_funding_index); @@ -3749,7 +3932,7 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) peer->splice_state->count++; - resume_splice_negotiation(peer, new_inflight, false, TX_ACCEPTER); + resume_splice_negotiation(peer, true, true, true, true); } static struct bitcoin_tx *bitcoin_tx_from_txid(struct peer *peer, @@ -3961,7 +4144,8 @@ static void splice_initiator_user_finalized(struct peer *peer) amount_sat(new_chan_output->amount), peer->splicing->opener_relative, ictx->current_psbt, - true); + true, + peer->splicing->force_sign_first); master_wait_sync_reply(tmpctx, peer, take(outmsg), WIRE_CHANNELD_GOT_INFLIGHT); @@ -3975,6 +4159,7 @@ static void splice_initiator_user_finalized(struct peer *peer) new_inflight->splice_amnt = peer->splicing->opener_relative; new_inflight->last_tx = NULL; new_inflight->i_am_initiator = true; + new_inflight->force_sign_first = peer->splicing->force_sign_first; current_push_val = relative_splice_balance_fundee(peer, our_role, ictx->current_psbt, chan_output_index, splice_funding_index); @@ -3985,7 +4170,9 @@ static void splice_initiator_user_finalized(struct peer *peer) peer->splice_state->count++; their_commit = interactive_send_commitments(peer, ictx->current_psbt, - our_role); + our_role, + last_inflight_index(peer), + true, true, NULL); new_inflight->last_tx = tal_steal(new_inflight, their_commit->tx); new_inflight->last_sig = their_commit->commit_signature; @@ -4077,16 +4264,6 @@ static void splice_initiator_user_update(struct peer *peer, const u8 *inmsg) wire_sync_write(MASTER_FD, take(outmsg)); } -static struct inflight *last_inflight(struct peer *peer) -{ - size_t count = tal_count(peer->splice_state->inflights); - - if (count) - return peer->splice_state->inflights[count - 1]; - - return NULL; -} - /* 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`. @@ -4099,7 +4276,7 @@ static void splice_initiator_user_signed(struct peer *peer, const u8 *inmsg) struct wally_psbt *signed_psbt; struct bitcoin_txid current_psbt_txid, signed_psbt_txid; struct inflight *inflight; - const u8 *msg; + const u8 *msg, *outmsg; if (!peer->splicing) { msg = towire_channeld_splice_state_error(NULL, "Can't accept a" @@ -4156,7 +4333,15 @@ static void splice_initiator_user_signed(struct peer *peer, const u8 *inmsg) inflight = last_inflight(peer); inflight->psbt = tal_steal(inflight, signed_psbt); - resume_splice_negotiation(peer, inflight, true, TX_INITIATOR); + /* Save the user provided signatures to DB incase we have to + * restart and reestablish later. */ + outmsg = towire_channeld_update_inflight(NULL, inflight->psbt, + inflight->last_tx, + &inflight->last_sig); + + wire_sync_write(MASTER_FD, take(outmsg)); + + resume_splice_negotiation(peer, false, false, true, true); } /* This occurs once our 'stfu' transition was successful. */ @@ -4192,7 +4377,7 @@ static void handle_splice_init(struct peer *peer, const u8 *inmsg) peer->splicing = splicing_new(peer); - if (!fromwire_channeld_splice_init(peer, inmsg, + if (!fromwire_channeld_splice_init(peer->splicing, inmsg, &peer->splicing->current_psbt, &peer->splicing->opener_relative, &peer->splicing->feerate_per_kw, @@ -4285,7 +4470,9 @@ static void peer_in(struct peer *peer, const u8 *msg) handle_peer_add_htlc(peer, msg); return; case WIRE_COMMITMENT_SIGNED: - handle_peer_commit_sig(peer, msg, 0, NULL, 0, 0); + handle_peer_commit_sig(peer, msg, 0, NULL, 0, 0, + peer->next_index[LOCAL], + &peer->next_local_per_commit, false); return; case WIRE_UPDATE_FEE: handle_peer_feechange(peer, msg); @@ -4515,6 +4702,7 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) msgs[0] = send_commit_part(msgs, peer, &peer->channel->funding, peer->channel->funding_sats, NULL, false, 0, 0, peer->next_index[REMOTE] - 1, + &peer->remote_per_commit, &local_anchor); /* Loop over current inflights @@ -4540,6 +4728,7 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) peer->splice_state->inflights[i]->splice_amnt, remote_splice_amnt, peer->next_index[REMOTE] - 1, + &peer->remote_per_commit, &local_anchor)); } @@ -4805,22 +4994,12 @@ static void peer_reconnect(struct peer *peer, get_per_commitment_point(peer->next_index[LOCAL] - 1, &my_current_per_commitment_point, NULL); - inflight = last_inflight(peer); + send_tlvs = NULL; if (peer->experimental_upgrade) { /* Subtle: we free tmpctx below as we loop, so tal off peer */ send_tlvs = tlv_channel_reestablish_tlvs_new(peer); - /* If inflight with no sigs on it, send next_funding */ - if (inflight && !inflight->last_tx) { - status_debug("Reestablish with an inflight but missing" - " last_tx, will send next_funding %s", - type_to_string(tmpctx, - struct bitcoin_txid, - &inflight->outpoint.txid)); - send_tlvs->next_funding = &inflight->outpoint.txid; - } - /* BOLT-upgrade_protocol #2: * A node sending `channel_reestablish`, if it supports upgrading channels: * - MUST set `next_to_send` the commitment number of the next @@ -4854,8 +5033,23 @@ static void peer_reconnect(struct peer *peer, take(channel_upgradable_type(NULL, peer->channel))); } - } else - send_tlvs = NULL; + } + + inflight = last_inflight(peer); + + if (inflight && (!inflight->last_tx || !inflight->remote_tx_sigs)) { + status_info("Reconnecting to peer with pending inflight commit:" + " %s, remote sigs: %s.", + inflight->last_tx ? "received" : "missing", + inflight->remote_tx_sigs ? "received" : "missing"); + + if (!send_tlvs) { + /* Subtle: we free tmpctx below as we loop, so tal off + * peer */ + send_tlvs = tlv_channel_reestablish_tlvs_new(peer); + } + send_tlvs->next_funding = &inflight->outpoint.txid; + } /* BOLT #2: * @@ -4959,6 +5153,84 @@ static void peer_reconnect(struct peer *peer, tal_count(peer->splice_state->inflights), peer->splice_state->count); + /* If we didn't send (i.e. don't support!) ignore theirs */ + if (!send_tlvs && !inflight) + recv_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); + + local_next_funding = (send_tlvs ? send_tlvs->next_funding : NULL); + remote_next_funding = (recv_tlvs ? recv_tlvs->next_funding : NULL); + + status_info("Splice resume check with local_next_funding: %s," + " remote_next_funding: %s, inflights: %zu", + local_next_funding ? "sent" : "omitted", + remote_next_funding ? "received" : "empty", + tal_count(peer->splice_state->inflights)); + + /* DTODO: Update splice BOLT spec PR and reference here. */ + if (inflight && (remote_next_funding || local_next_funding)) { + if (!remote_next_funding) { + status_info("Resuming splice negotation."); + resume_splice_negotiation(peer, + false, + true, + false, + true); + } else if (bitcoin_txid_eq(remote_next_funding, + &inflight->outpoint.txid)) { + status_info("Resuming splice negotation"); + resume_splice_negotiation(peer, + !inflight->remote_tx_sigs, + local_next_funding, + true, + local_next_funding); + } else if (bitcoin_txid_eq(remote_next_funding, + &peer->channel->funding.txid)) { + peer_failed_err(peer->pps, + &peer->channel_id, + "Invalid reestablish with next_funding" + " txid %s that matches our current" + " active funding txid %s. Should be %s" + " or NULL", + type_to_string(tmpctx, + struct bitcoin_txid, + remote_next_funding), + type_to_string(tmpctx, + struct bitcoin_txid, + &peer->channel->funding.txid), + type_to_string(tmpctx, + struct bitcoin_txid, + &inflight->outpoint.txid)); + } else { /* remote_next_funding set but unrecognized */ + peer_failed_err(peer->pps, + &peer->channel_id, + "Invalid reestablish with unrecognized" + " next_funding txid %s, should be %s", + type_to_string(tmpctx, + struct bitcoin_txid, + remote_next_funding), + type_to_string(tmpctx, + struct bitcoin_txid, + &inflight->outpoint.txid)); + } + } else if (remote_next_funding) { /* No current inflight */ + if (bitcoin_txid_eq(remote_next_funding, + &peer->channel->funding.txid)) { + status_info("We have no pending splice but peer" + " expects one; resending splice_lock"); + peer_write(peer->pps, + take(towire_splice_locked(NULL, &peer->channel_id))); + } + else { + char *errmsg = tal_fmt(tmpctx, + "next_funding_txid not recognized." + " Sending tx_abort."); + peer_write(peer->pps, + take(towire_tx_abort(NULL, + &peer->channel_id, + (u8*)errmsg))); + } + } + /* BOLT #2: * * - if `next_commitment_number` is 1 in both the @@ -5126,10 +5398,6 @@ static void peer_reconnect(struct peer *peer, /* (If we had sent `closing_signed`, we'd be in closingd). */ maybe_send_shutdown(peer); - /* If we didn't send (i.e. don't support!) ignore theirs */ - if (!send_tlvs) - recv_tlvs = tlv_channel_reestablish_tlvs_new(tmpctx); - if (recv_tlvs->desired_channel_type) status_debug("They sent desired_channel_type [%s]", fmt_featurebits(tmpctx, @@ -5221,58 +5489,6 @@ static void peer_reconnect(struct peer *peer, "Channel is already closed"); } - local_next_funding = (send_tlvs ? send_tlvs->next_funding : NULL); - remote_next_funding = (recv_tlvs ? recv_tlvs->next_funding : NULL); - - if (local_next_funding || remote_next_funding) { - bool next_matches_current = false, next_matches_inflight = false; - - if (remote_next_funding) { - next_matches_current = bitcoin_txid_eq(remote_next_funding, - &peer->channel->funding.txid); - if (inflight) - next_matches_inflight = bitcoin_txid_eq(remote_next_funding, - &inflight->outpoint.txid); - } - if (remote_next_funding && !next_matches_current - && !next_matches_inflight) { - peer_failed_err(peer->pps, - &peer->channel_id, - "Unrecognized next_funding txid %s", - type_to_string(tmpctx, - struct bitcoin_txid, - remote_next_funding)); - } else if (inflight && !next_matches_inflight) { - /* DTODO: tx_abort */ - peer_failed_warn(peer->pps, &peer->channel_id, - "next_funding txid %s doesnt match" - " our inflight txid %s", - type_to_string(tmpctx, - struct bitcoin_txid, - &inflight->outpoint.txid), - type_to_string(tmpctx, - struct bitcoin_txid, - &peer->channel->funding.txid)); - } else if (!inflight && !next_matches_current) { - /* DTODO: tx_abort */ - peer_failed_warn(peer->pps, &peer->channel_id, - "next_funding txid %s doesnt match" - " our confirmed funding txid %s", - type_to_string(tmpctx, - struct bitcoin_txid, - remote_next_funding), - type_to_string(tmpctx, - struct bitcoin_txid, - &peer->channel->funding.txid)); - } - else { - status_info("Resuming splice negotation"); - resume_splice_negotiation(peer, inflight, false, - inflight->i_am_initiator - ? TX_INITIATOR - : TX_ACCEPTER); - } - } tal_free(send_tlvs); /* Corner case: we didn't send shutdown before because update_add_htlc @@ -5349,6 +5565,10 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) struct short_channel_id, &peer->splice_state->short_channel_id)); } else { + status_debug("handle_funding_depth: Setting short_channel_ids[LOCAL] to %s", + type_to_string(tmpctx, + struct short_channel_id, + (scid ? scid : alias_local))); /* 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 @@ -5395,7 +5615,8 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) peer->announce_depth_reached = (depth >= ANNOUNCE_MIN_DEPTH); /* Send temporary or final announcements */ - channel_announcement_negotiate(peer); + if (!splicing) + channel_announcement_negotiate(peer); } billboard_update(peer); @@ -5775,6 +5996,7 @@ static void req_in(struct peer *peer, const u8 *msg) return; case WIRE_CHANNELD_SPLICE_CONFIRMED_INIT: case WIRE_CHANNELD_SPLICE_CONFIRMED_SIGNED: + case WIRE_CHANNELD_SPLICE_SENDING_SIGS: case WIRE_CHANNELD_SPLICE_CONFIRMED_UPDATE: case WIRE_CHANNELD_SPLICE_LOOKUP_TX: case WIRE_CHANNELD_SPLICE_LOOKUP_TX_RESULT: @@ -5923,8 +6145,6 @@ static void init_channel(struct peer *peer) peer->final_index = tal_dup(peer, u32, &final_index); peer->final_ext_key = tal_dup(peer, struct ext_key, &final_ext_key); - peer->splice_state->committed_count = tal_count(peer->splice_state->inflights); - peer->splice_state->revoked_count = tal_count(peer->splice_state->inflights); peer->splice_state->count = tal_count(peer->splice_state->inflights); status_debug("option_static_remotekey = %u," diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index 1992f7fa12d4..53590a2e6ee6 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -243,6 +243,10 @@ msgtype,channeld_splice_confirmed_signed,7213 msgdata,channeld_splice_confirmed_signed,tx,bitcoin_tx, msgdata,channeld_splice_confirmed_signed,output_index,u32, +# channeld->master: Splice signatures are about to be sent +msgtype,channeld_splice_sending_sigs,7214 +msgdata,channeld_splice_sending_sigs,tx,bitcoin_txid, + # channeld->master: A feerate error has occured msgtype,channeld_splice_feerate_error,7215 msgdata,channeld_splice_feerate_error,fee,amount_msat, @@ -257,6 +261,7 @@ msgdata,channeld_add_inflight,satoshis,amount_sat, msgdata,channeld_add_inflight,splice_amount,s64, msgdata,channeld_add_inflight,psbt,wally_psbt, msgdata,channeld_add_inflight,i_am_initiator,bool, +msgdata,channeld_add_inflight,force_sign_first,bool, # master->channeld: Inflight saved successfully msgtype,channeld_got_inflight,7217 diff --git a/channeld/inflight.c b/channeld/inflight.c index 3c7796960f72..a1e908ead6ab 100644 --- a/channeld/inflight.c +++ b/channeld/inflight.c @@ -10,6 +10,7 @@ struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t * fromwire_bitcoin_outpoint(cursor, max, &inflight->outpoint); inflight->amnt = fromwire_amount_sat(cursor, max); + inflight->remote_tx_sigs = fromwire_bool(cursor, max); inflight->psbt = fromwire_wally_psbt(inflight, cursor, max); inflight->splice_amnt = fromwire_s64(cursor, max); int has_tx = fromwire_u8(cursor, max); @@ -22,6 +23,7 @@ struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t * memset(&inflight->last_sig, 0, sizeof(inflight->last_sig)); } inflight->i_am_initiator = fromwire_bool(cursor, max); + inflight->force_sign_first = fromwire_bool(cursor, max); return inflight; } @@ -30,6 +32,7 @@ void towire_inflight(u8 **pptr, const struct inflight *inflight) { towire_bitcoin_outpoint(pptr, &inflight->outpoint); towire_amount_sat(pptr, inflight->amnt); + towire_bool(pptr, inflight->remote_tx_sigs); towire_wally_psbt(pptr, inflight->psbt); towire_s64(pptr, inflight->splice_amnt); towire_u8(pptr, inflight->last_tx ? 1 : 0); @@ -38,15 +41,18 @@ void towire_inflight(u8 **pptr, const struct inflight *inflight) towire_bitcoin_signature(pptr, &inflight->last_sig); } towire_bool(pptr, inflight->i_am_initiator); + towire_bool(pptr, inflight->force_sign_first); } void copy_inflight(struct inflight *dest, struct inflight *src) { dest->outpoint = src->outpoint; dest->amnt = src->amnt; + dest->remote_tx_sigs = src->remote_tx_sigs; dest->psbt = src->psbt ? clone_psbt(dest, src->psbt): NULL; dest->splice_amnt = src->splice_amnt; dest->last_tx = src->last_tx ? clone_bitcoin_tx(dest, src->last_tx) : NULL; dest->last_sig = src->last_sig; dest->i_am_initiator = src->i_am_initiator; + dest->force_sign_first = src->force_sign_first; } diff --git a/channeld/inflight.h b/channeld/inflight.h index c95acf9af215..47deb316681d 100644 --- a/channeld/inflight.h +++ b/channeld/inflight.h @@ -8,12 +8,15 @@ struct inflight { struct bitcoin_outpoint outpoint; struct amount_sat amnt; + bool remote_tx_sigs; struct wally_psbt *psbt; s64 splice_amnt; struct bitcoin_tx *last_tx; /* last_sig is assumed valid if last_tx is set */ struct bitcoin_signature last_sig; bool i_am_initiator; + bool force_sign_first; + bool is_locked; }; struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t *max); diff --git a/channeld/splice.c b/channeld/splice.c index 656017574d31..473159614f09 100644 --- a/channeld/splice.c +++ b/channeld/splice.c @@ -6,8 +6,6 @@ struct splice_state *splice_state_new(const tal_t *ctx) { struct splice_state *splice_state = tal(ctx, struct splice_state); - splice_state->committed_count = 0; - splice_state->revoked_count = 0; splice_state->count = 0; splice_state->locked_ready[LOCAL] = false; splice_state->locked_ready[REMOTE] = false; diff --git a/channeld/splice.h b/channeld/splice.h index 4f1785a011a1..267fddbac679 100644 --- a/channeld/splice.h +++ b/channeld/splice.h @@ -21,10 +21,6 @@ struct splice_state { bool await_commitment_succcess; /* The txid of which splice inflight was confirmed */ struct bitcoin_txid locked_txid; - /* The number of splices that have been signed & committed */ - u32 committed_count; - /* the number of splices that have been revoke_and_ack'ed */ - u32 revoked_count; /* The number of splices that are active (awaiting confirmation) */ u32 count; }; diff --git a/common/psbt_internal.c b/common/psbt_internal.c index aca36b6ad96a..df1cb536328d 100644 --- a/common/psbt_internal.c +++ b/common/psbt_internal.c @@ -124,6 +124,8 @@ psbt_to_witnesses(const tal_t *ctx, tal_arr(ctx, const struct witness *, 0); for (size_t i = 0; i < psbt->num_inputs; i++) { + struct wally_tx_witness_stack *wtx_s = + psbt->inputs[i].final_witness; if (!psbt_get_serial_id(&psbt->inputs[i].unknowns, &serial_id)) /* FIXME: throw an error ? */ @@ -136,9 +138,7 @@ psbt_to_witnesses(const tal_t *ctx, * - if is the *initiator*: * - MUST send even `serial_id`s */ - if (serial_id % 2 == side_to_stack) { - struct wally_tx_witness_stack *wtx_s = - psbt->inputs[i].final_witness; + if (wtx_s && serial_id % 2 == side_to_stack) { /* BOLT-e299850cb5ebd8bd9c55763bbc498fcdf94a9567 #2: * diff --git a/lightningd/channel.c b/lightningd/channel.c index 6a226985474d..a20b3f5387c9 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -150,7 +150,8 @@ new_inflight(struct channel *channel, const struct amount_msat lease_fee, const struct amount_sat lease_amt, s64 splice_amnt, - bool i_am_initiator) + bool i_am_initiator, + bool force_sign_first) { struct channel_inflight *inflight = tal(channel, struct channel_inflight); @@ -183,6 +184,7 @@ new_inflight(struct channel *channel, inflight->lease_amt = lease_amt; inflight->i_am_initiator = i_am_initiator; + inflight->force_sign_first = force_sign_first; inflight->splice_locked_memonly = false; list_add_tail(&channel->inflights, &inflight->list); diff --git a/lightningd/channel.h b/lightningd/channel.h index ea58bf09046d..1df9bd032793 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -76,6 +76,9 @@ struct channel_inflight { /* Did I initate this splice attempt? */ bool i_am_initiator; + /* On reestablish recovery; should I sign first? */ + bool force_sign_first; + /* Note: This field is not stored in the database. * * After splice_locked, we need a way to stop the chain watchers from @@ -397,7 +400,8 @@ struct channel_inflight *new_inflight(struct channel *channel, const struct amount_msat lease_fee, const struct amount_sat lease_amt, s64 splice_amnt, - bool i_am_initiator); + bool i_am_initiator, + bool force_sign_first); /* Add a last_tx and sig to an inflight */ void inflight_set_last_tx(struct channel_inflight *inflight, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index f39f211457e9..7018e63457aa 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -499,9 +499,7 @@ static void send_splice_tx(struct channel *channel, 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: */ +/* After channeld have all the signatures it sends the result to us here */ static void handle_splice_confirmed_signed(struct lightningd *ld, struct channel *channel, const u8 *msg) @@ -512,7 +510,8 @@ static void handle_splice_confirmed_signed(struct lightningd *ld, struct channel_inflight *inflight; u32 output_index; - if (!fromwire_channeld_splice_confirmed_signed(tmpctx, msg, &tx, &output_index)) { + if (!fromwire_channeld_splice_confirmed_signed(tmpctx, msg, &tx, + &output_index)) { channel_internal_error(channel, "bad splice_confirmed_signed %s", @@ -532,23 +531,130 @@ static void handle_splice_confirmed_signed(struct lightningd *ld, inflight->remote_tx_sigs = true; wallet_inflight_save(ld->wallet, inflight); - if (channel->state != CHANNELD_NORMAL) { + if (channel->state != CHANNELD_AWAITING_SPLICE) { log_debug(channel->log, "Would broadcast splice, but state %s" - " isn't CHANNELD_NORMAL", + " isn't CHANNELD_AWAITING_SPLICE", channel_state_name(channel)); return; } + cc = splice_command_for_chan(ld, channel); + + send_splice_tx(channel, tx, cc, output_index); +} + +static enum watch_result splice_depth_cb(struct lightningd *ld, + const struct bitcoin_txid *txid, + const struct bitcoin_tx *tx, + unsigned int depth, + void *param) +{ + /* find_txwatch triggers a type warning on inflight, so we do this. */ + struct channel_inflight *inflight = param; + struct txlocator *loc; + struct short_channel_id scid; + + /* What scid is this giving us? */ + loc = wallet_transaction_locate(tmpctx, ld->wallet, txid); + if (!mk_short_channel_id(&scid, + loc->blkheight, loc->index, + inflight->funding->outpoint.n)) { + channel_fail_permanent(inflight->channel, + REASON_LOCAL, + "Invalid funding scid %u:%u:%u", + loc->blkheight, loc->index, + inflight->funding->outpoint.n); + return false; + } + + /* Usually, we're here because we're awaiting a splice, but + * we could also mutual shutdown, or that weird splice_locked_memonly + * hack... */ + if (inflight->channel->state != CHANNELD_AWAITING_SPLICE) { + log_info(inflight->channel->log, "Splice inflight event but not" + " in AWAITING_SPLICE, ending watch of txid %s", + type_to_string(tmpctx, struct bitcoin_txid, txid)); + return DELETE_WATCH; + } + + /* Reorged out? OK, we're not committed yet. */ + if (depth == 0) { + return KEEP_WATCHING; + } + + if (inflight->channel->owner) { + log_info(inflight->channel->log, "splice_depth_cb: sending funding depth scid: %s", + type_to_string(tmpctx, struct short_channel_id, &scid)); + subd_send_msg(inflight->channel->owner, + take(towire_channeld_funding_depth( + NULL, &scid, + inflight->channel->alias[LOCAL], + depth, true, txid))); + } + + /* channeld will tell us when splice is locked in: we'll clean + * this watch up then. */ + return KEEP_WATCHING; +} + +void watch_splice_inflight(struct lightningd *ld, + struct channel_inflight *inflight) +{ + log_info(inflight->channel->log, "Watching splice inflight %s", + type_to_string(tmpctx, struct bitcoin_txid, + &inflight->funding->outpoint.txid)); + watch_txid(inflight, ld->topology, + &inflight->funding->outpoint.txid, + splice_depth_cb, inflight); +} + +static struct txwatch *splice_inflight_txwatch(struct channel *channel, + struct channel_inflight *inflight) +{ + return find_txwatch(channel->peer->ld->topology, + &inflight->funding->outpoint.txid, + splice_depth_cb, channel); +} + +static void handle_splice_sending_sigs(struct lightningd *ld, + struct channel *channel, + const u8 *msg) +{ + struct splice_command *cc; + struct bitcoin_txid txid; + struct channel_inflight *inflight; + + if (!fromwire_channeld_splice_sending_sigs(msg, &txid)) { + + channel_internal_error(channel, + "bad splice_confirmed_signed %s", + tal_hex(channel, msg)); + return; + } + + inflight = channel_inflight_find(channel, &txid); + if (!inflight) + channel_internal_error(channel, "Unable to load inflight for" + " splice_confirmed_signed txid %s", + type_to_string(tmpctx, + struct bitcoin_txid, + &txid)); + + /* Signing a splice after it has confirmed is safe and can happen during + * reestablish if one node is late seeing blocks */ + if (channel->state == CHANNELD_AWAITING_SPLICE) + return; + cc = splice_command_for_chan(ld, channel); /* If matching user command found, this was a user intiated splice */ channel_set_state(channel, CHANNELD_NORMAL, CHANNELD_AWAITING_SPLICE, cc ? REASON_USER : REASON_REMOTE, - "Broadcasting splice"); + "Splice signatures sent"); - send_splice_tx(channel, tx, cc, output_index); + watch_splice_inflight(ld, inflight); } bool depthcb_update_scid(struct channel *channel, @@ -600,46 +706,6 @@ bool depthcb_update_scid(struct channel *channel, return true; } -static enum watch_result splice_depth_cb(struct lightningd *ld, - const struct bitcoin_txid *txid, - const struct bitcoin_tx *tx, - unsigned int depth, - struct channel_inflight *inflight) -{ - /* Usually, we're here because we're awaiting a splice, but - * we could also mutual shutdown, or that weird splice_locked_memonly - * hack... */ - if (inflight->channel->state != CHANNELD_AWAITING_SPLICE) - return DELETE_WATCH; - - /* Reorged out? OK, we're not committed yet. */ - if (depth == 0) - return KEEP_WATCHING; - - if (!depthcb_update_scid(inflight->channel, txid, &inflight->funding->outpoint)) - return DELETE_WATCH; - - if (inflight->channel->owner) { - subd_send_msg(inflight->channel->owner, - take(towire_channeld_funding_depth( - NULL, inflight->channel->scid, - inflight->channel->alias[LOCAL], - depth, true, txid))); - } - - /* channeld will tell us when splice is locked in: we'll clean - * this watch up then. */ - return KEEP_WATCHING; -} - -void watch_splice_inflight(struct lightningd *ld, - struct channel_inflight *inflight) -{ - watch_txid(inflight, ld->topology, - &inflight->funding->outpoint.txid, - splice_depth_cb, inflight); -} - static void handle_add_inflight(struct lightningd *ld, struct channel *channel, const u8 *msg) @@ -650,7 +716,7 @@ static void handle_add_inflight(struct lightningd *ld, s64 splice_amnt; struct wally_psbt *psbt; struct channel_inflight *inflight; - bool i_am_initiator; + bool i_am_initiator, force_sign_first; if (!fromwire_channeld_add_inflight(tmpctx, msg, @@ -660,7 +726,8 @@ static void handle_add_inflight(struct lightningd *ld, &satoshis, &splice_amnt, &psbt, - &i_am_initiator)) { + &i_am_initiator, + &force_sign_first)) { channel_internal_error(channel, "bad channel_add_inflight %s", tal_hex(channel, msg)); @@ -681,14 +748,14 @@ static void handle_add_inflight(struct lightningd *ld, AMOUNT_MSAT(0), AMOUNT_SAT(0), splice_amnt, - i_am_initiator); + i_am_initiator, + force_sign_first); 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); - watch_splice_inflight(ld, inflight); subd_send_msg(channel->owner, take(towire_channeld_got_inflight(NULL))); } @@ -885,6 +952,7 @@ static void handle_peer_splice_locked(struct channel *channel, const u8 *msg) s64 splice_amnt; struct channel_inflight *inflight; struct bitcoin_txid locked_txid; + struct txwatch *txw; if (!fromwire_channeld_got_splice_locked(msg, &funding_sats, &splice_amnt, @@ -922,6 +990,9 @@ static void handle_peer_splice_locked(struct channel *channel, const u8 *msg) wallet_channel_clear_inflights(channel->peer->ld->wallet, channel); + depthcb_update_scid(channel, &locked_txid, + &inflight->funding->outpoint); + /* That freed watchers in inflights: now watch funding tx */ channel_watch_funding(channel->peer->ld, channel); @@ -934,6 +1005,14 @@ static void handle_peer_splice_locked(struct channel *channel, const u8 *msg) list_add_tail(&channel->inflights, &inflight->list); lockin_complete(channel, CHANNELD_AWAITING_SPLICE); + + /* Turn off tx watcher for the splice */ + txw = splice_inflight_txwatch(channel, inflight); + if (!txw) + log_unusual(channel->log, "Can't unwatch txid %s", + type_to_string(tmpctx, struct bitcoin_txid, + &locked_txid)); + tal_free(txw); } /* We were informed by channeld that channel is ready (reached mindepth) */ @@ -1318,6 +1397,9 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds) case WIRE_CHANNELD_SPLICE_CONFIRMED_SIGNED: handle_splice_confirmed_signed(sd->ld, sd->channel, msg); break; + case WIRE_CHANNELD_SPLICE_SENDING_SIGS: + handle_splice_sending_sigs(sd->ld, sd->channel, msg); + break; case WIRE_CHANNELD_ADD_INFLIGHT: handle_add_inflight(sd->ld, sd->channel, msg); break; @@ -1524,6 +1606,7 @@ bool peer_start_channeld(struct channel *channel, infcopy->outpoint = inflight->funding->outpoint; infcopy->amnt = inflight->funding->total_funds; + infcopy->remote_tx_sigs = inflight->remote_tx_sigs; infcopy->splice_amnt = inflight->funding->splice_amnt; if (inflight->last_tx) infcopy->last_tx = tal_dup(infcopy, struct bitcoin_tx, inflight->last_tx); @@ -1531,9 +1614,12 @@ bool peer_start_channeld(struct channel *channel, infcopy->last_tx = NULL; infcopy->last_sig = inflight->last_sig; infcopy->i_am_initiator = inflight->i_am_initiator; + infcopy->force_sign_first = inflight->force_sign_first; + tal_wally_start(); wally_psbt_clone_alloc(inflight->funding_psbt, 0, &infcopy->psbt); tal_wally_end_onto(infcopy, infcopy->psbt, struct wally_psbt); + tal_arr_expand(&inflights, infcopy); } @@ -1643,7 +1729,7 @@ void channeld_tell_depth(struct channel *channel, subd_send_msg(channel->owner, take(towire_channeld_funding_depth( NULL, channel->scid, channel->alias[LOCAL], depth, - channel->state == CHANNELD_AWAITING_SPLICE, txid))); + false, txid))); } /* Check if we are the fundee of this channel, the channel diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 5702cb2dd1e3..5de6d1138336 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1292,6 +1292,7 @@ wallet_update_channel(struct lightningd *ld, channel->push, lease_amt, 0, + false, false); wallet_inflight_add(ld->wallet, inflight); @@ -1510,6 +1511,7 @@ wallet_commit_channel(struct lightningd *ld, channel->push, lease_amt, 0, + false, false); wallet_inflight_add(ld->wallet, inflight); diff --git a/tests/test_splicing.py b/tests/test_splicing.py index 424b49c00f4b..78e480571ac8 100644 --- a/tests/test_splicing.py +++ b/tests/test_splicing.py @@ -211,13 +211,14 @@ def test_invalid_splice(node_factory, bitcoind): result = l1.rpc.signpsbt(result['psbt']) result = l1.rpc.splice_signed(chan_id, result['signed_psbt']) - l2.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE') - l1.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE') - mempool = bitcoind.rpc.getrawmempool(True) assert len(list(mempool.keys())) == 1 assert result['txid'] in list(mempool.keys()) + # Wait until nodes are reconnected + l1.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH') + l2.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH') + bitcoind.generate_block(6, wait_for_mempool=1) l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') diff --git a/tests/test_splicing_disconnect.py b/tests/test_splicing_disconnect.py new file mode 100644 index 000000000000..093afe296fec --- /dev/null +++ b/tests/test_splicing_disconnect.py @@ -0,0 +1,119 @@ +from fixtures import * # noqa: F401,F403 +import pytest +import unittest +import time +from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND +from utils import ( + TEST_NETWORK, first_scid +) + + +@pytest.mark.openchannel('v1') +@pytest.mark.openchannel('v2') +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +def test_splice_disconnect_sig(node_factory, bitcoind): + # Dual open and splicing both use tx_sig messages. If we have dual enabled, ignore the first one. + disconnect = ['-WIRE_TX_SIGNATURES'] + if EXPERIMENTAL_DUAL_FUND: + disconnect = ['=WIRE_TX_SIGNATURES'] + disconnect + + l1 = node_factory.get_node(disconnect=disconnect, + options={'experimental-splicing': None, 'dev-no-reconnect': None}, + may_reconnect=True) + l2 = node_factory.get_node(options={'experimental-splicing': None}, may_reconnect=True) + l1.openchannel(l2, 1000000) + + chan_id = l1.get_channel_id(l2) + + # add extra sats to pay fee + funds_result = l1.rpc.fundpsbt("109000sat", "slow", 166, excess_as_change=True) + + result = l1.rpc.splice_init(chan_id, 100000, 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']) + + l1.daemon.wait_for_log(r'dev_disconnect: \-WIRE_TX_SIGNATURES') + + print("Killing l1 without sending WIRE_TX_SIGNATURES") + l1.daemon.kill() + + # Restart l1, without disconnect stuff. + del l1.daemon.opts['dev-no-reconnect'] + del l1.daemon.opts['dev-disconnect'] + + # Should reconnect, and reestablish the splice. + l1.start() + + # Wait until nodes are reconnected + l1.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH') + l2.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH') + + bitcoind.generate_block(6, wait_for_mempool=1) + + l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + l1.daemon.wait_for_log(r'private channel announcement from channeld for ' + first_scid(l1, l2)) + + inv = l2.rpc.invoice(10**2, '3', 'no_3') + l1.rpc.pay(inv['bolt11']) + + # Check that the splice doesn't generate a unilateral close transaction + time.sleep(5) + assert l1.db_query("SELECT count(*) as c FROM channeltxs;")[0]['c'] == 0 + + +@pytest.mark.openchannel('v1') +@pytest.mark.openchannel('v2') +@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need') +def test_splice_disconnect_commit(node_factory, bitcoind, executor): + l1 = node_factory.get_node(options={'experimental-splicing': None}, may_reconnect=True) + l2 = node_factory.get_node(disconnect=['+WIRE_COMMITMENT_SIGNED'], + options={'experimental-splicing': None, 'dev-no-reconnect': None}, + may_reconnect=True) + l1.openchannel(l2, 1000000) + + chan_id = l1.get_channel_id(l2) + + # add extra sats to pay fee + funds_result = l1.rpc.fundpsbt("109000sat", "slow", 166, excess_as_change=True) + + result = l1.rpc.splice_init(chan_id, 100000, funds_result['psbt']) + print("l1 splice_update") + result = l1.rpc.splice_update(chan_id, result['psbt']) + print("l1 signpsbt") + result = l1.rpc.signpsbt(result['psbt']) + print("l1 splice_signed") + + executor.submit(l1.rpc.splice_signed, chan_id, result['signed_psbt']) + + print("l2 waiting for dev_disconnect msg") + + l2.daemon.wait_for_log(r'dev_disconnect: \+WIRE_COMMITMENT_SIGNED') + + print("Killing l2 without sending WIRE_COMMITMENT_SIGNED") + l2.daemon.kill() + + # Restart l1, without disconnect stuff. + del l2.daemon.opts['dev-no-reconnect'] + del l2.daemon.opts['dev-disconnect'] + + # Should reconnect, and reestablish the splice. + l2.start() + + # Wait until nodes are reconnected + l1.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH') + l2.daemon.wait_for_log(r'peer_in WIRE_CHANNEL_REESTABLISH') + + bitcoind.generate_block(6, wait_for_mempool=1) + + l1.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + l2.daemon.wait_for_log(r'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + l1.daemon.wait_for_log(r'private channel announcement from channeld for ' + first_scid(l1, l2)) + + inv = l2.rpc.invoice(10**2, '3', 'no_3') + l1.rpc.pay(inv['bolt11']) + + # Check that the splice doesn't generate a unilateral close transaction + time.sleep(5) + assert l1.db_query("SELECT count(*) as c FROM channeltxs;")[0]['c'] == 0 diff --git a/wallet/db.c b/wallet/db.c index 376b4bee7cef..33e322aafd36 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -1010,6 +1010,7 @@ static struct migration dbmigrations[] = { {SQL("ALTER TABLE forwards ADD updated_index BIGINT DEFAULT 0"), NULL}, {SQL("CREATE INDEX forwards_updated_idx ON forwards (updated_index)"), NULL}, {NULL, migrate_initialize_forwards_wait_indexes}, + {SQL("ALTER TABLE channel_funding_inflights ADD force_sign_first INTEGER DEFAULT 0"), NULL}, }; /** diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index ca7ca447626c..ddabea496a5d 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -201,7 +201,8 @@ struct channel_inflight *new_inflight(struct channel *channel UNNEEDED, const struct amount_msat lease_fee UNNEEDED, const struct amount_sat lease_amt UNNEEDED, s64 splice_amnt UNNEEDED, - bool i_am_initiator UNNEEDED) + bool i_am_initiator UNNEEDED, + bool force_sign_first UNNEEDED) { fprintf(stderr, "new_inflight called!\n"); abort(); } /* Generated stub for new_logger */ struct logger *new_logger(const tal_t *ctx UNNEEDED, struct log_book *record UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 26fda1b90cc6..42cec47f1ef0 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1923,6 +1923,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) AMOUNT_MSAT(10), AMOUNT_SAT(1111), 0, + false, false); inflight_set_last_tx(inflight, last_tx, sig); @@ -1949,6 +1950,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) AMOUNT_MSAT(0), AMOUNT_SAT(0), 0, + false, false); inflight_set_last_tx(inflight, last_tx, sig); wallet_inflight_add(w, inflight); diff --git a/wallet/wallet.c b/wallet/wallet.c index ddad3b5c4356..e2e7986594a6 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1217,8 +1217,9 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight) ", lease_satoshi" ", splice_amnt" ", i_am_initiator" + ", force_sign_first" ") VALUES (" - "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); db_bind_u64(stmt, inflight->channel->dbid); db_bind_txid(stmt, &inflight->funding->outpoint.txid); @@ -1256,6 +1257,7 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight) db_bind_s64(stmt, inflight->funding->splice_amnt); db_bind_int(stmt, inflight->i_am_initiator); + db_bind_int(stmt, inflight->force_sign_first); db_exec_prepared_v2(stmt); assert(!stmt->error); @@ -1324,7 +1326,7 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, struct bitcoin_tx *last_tx; struct channel_inflight *inflight; s64 splice_amnt; - bool i_am_initiator; + bool i_am_initiator, force_sign_first; secp256k1_ecdsa_signature *lease_commit_sig; u32 lease_blockheight_start; @@ -1362,6 +1364,7 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, splice_amnt = db_col_s64(stmt, "splice_amnt"); i_am_initiator = db_col_int(stmt, "i_am_initiator"); + force_sign_first = db_col_int(stmt, "force_sign_first"); inflight = new_inflight(chan, &funding, db_col_int(stmt, "funding_feerate"), @@ -1376,7 +1379,8 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, lease_fee, lease_amt, splice_amnt, - i_am_initiator); + i_am_initiator, + force_sign_first); /* last_tx is null for not yet committed * channels + static channel backup recoveries */ @@ -1427,6 +1431,7 @@ static bool wallet_channel_load_inflights(struct wallet *w, ", lease_satoshi" ", splice_amnt" ", i_am_initiator" + ", force_sign_first" " FROM channel_funding_inflights" " WHERE channel_id = ?" " ORDER BY funding_feerate"));