diff --git a/channeld/channeld.c b/channeld/channeld.c index 37452adfe966..d6aa2aee149a 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1851,7 +1851,7 @@ static void splice_abort(struct peer *peer, const char *fmt, ...) reason = tal_vfmt(NULL, fmt, ap); va_end(ap); - if (have_i_signed_inflight(peer, inflight)) + if (inflight && inflight->i_sent_sigs) peer_failed_err(peer->pps, &peer->channel_id, "I needed to abort a splice where I have already" " sent my signatures"); @@ -3320,7 +3320,10 @@ static struct amount_sat check_balances(struct peer *peer, if (!amount_msat_add_sat_s64(&funding_amount, funding_amount, peer->splicing->opener_relative)) splice_abort(peer, "Splice initiator did not provide enough" - " funding"); + " funding, funding_amount: %s, opener_relative:" + " %"PRIu64, + fmt_amount_msat(tmpctx, funding_amount), + peer->splicing->opener_relative); if (!amount_msat_add_sat_s64(&out[TX_INITIATOR], out[TX_INITIATOR], peer->splicing->opener_relative)) peer_failed_warn(peer->pps, &peer->channel_id, @@ -3346,11 +3349,16 @@ static struct amount_sat check_balances(struct peer *peer, " amount. Initiator contributing %s but they" " committed to %s. Pending offered HTLC" " balance of %s is not available for this" - " operation.", + " operation. We are%s the opener. We began the" + " operation being owed/owing %s and expect" + " that amount to change %"PRIu64"000", fmt_amount_msat(tmpctx, in[TX_INITIATOR]), fmt_amount_msat(tmpctx, out[TX_INITIATOR]), fmt_amount_msat(tmpctx, - pending_htlcs[TX_INITIATOR])); + pending_htlcs[TX_INITIATOR]), + opener ? "" : " not", + fmt_amount_msat(tmpctx, peer->channel->view->owed[opener ? LOCAL : REMOTE]), + peer->splicing->opener_relative); } if (!amount_msat_sub(&initiator_fee, in[TX_INITIATOR], out[TX_INITIATOR])) @@ -3549,6 +3557,7 @@ static void resume_splice_negotiation(struct peer *peer, const u8 *msg_received; struct witness **inws; struct bitcoin_signature *their_sig; + size_t remote_inputs_needing_sigs; if (peer->splicing) { inws = peer->splicing->inws; @@ -3596,7 +3605,8 @@ static void resume_splice_negotiation(struct peer *peer, msg = towire_channeld_update_inflight(NULL, current_psbt, their_commit->tx, &their_commit->commit_signature, - inflight->locked_scid); + inflight->locked_scid, + inflight->i_sent_sigs); wire_sync_write(MASTER_FD, take(msg)); } @@ -3665,9 +3675,11 @@ static void resume_splice_negotiation(struct peer *peer, if (do_i_sign_first(peer, current_psbt, our_role, inflight->force_sign_first) && send_signature) { + inflight->i_sent_sigs = true; msg = towire_channeld_update_inflight(NULL, current_psbt, NULL, NULL, - inflight->locked_scid); + inflight->locked_scid, + inflight->i_sent_sigs); wire_sync_write(MASTER_FD, take(msg)); msg = towire_channeld_splice_sending_sigs(tmpctx, &final_txid); @@ -3792,6 +3804,28 @@ static void resume_splice_negotiation(struct peer *peer, " received", tal_count(inws) - current_psbt->num_inputs); + remote_inputs_needing_sigs = 0; + for (size_t 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, + fmt_wally_psbt(tmpctx, + current_psbt)); + return; + } + if (in_serial % 2 == our_role) + continue; + + if (i == splice_funding_index) + continue; + + remote_inputs_needing_sigs++; + } + /* 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 = @@ -3811,12 +3845,18 @@ static void resume_splice_negotiation(struct peer *peer, if (i == splice_funding_index) continue; - if (j == tal_count(inws)) + if (j == tal_count(inws)) { peer_failed_warn(peer->pps, &peer->channel_id, "Mismatch witness stack count." " Most likely you are missing" - " signatures."); + " signatures. We have %zu" + " remote inputs needing sigs" + " and you sent %zu witness" + " bundles.", + remote_inputs_needing_sigs, + tal_count(inws)); + } psbt_finalize_input(current_psbt, in, inws[j++]); @@ -3837,7 +3877,8 @@ static void resume_splice_negotiation(struct peer *peer, /* We let core validate our peer's signatures are correct. */ msg = towire_channeld_update_inflight(NULL, current_psbt, NULL, NULL, - inflight->locked_scid); + inflight->locked_scid, + send_signature || inflight->i_sent_sigs); wire_sync_write(MASTER_FD, take(msg)); } @@ -3847,6 +3888,7 @@ static void resume_splice_negotiation(struct peer *peer, msg = towire_channeld_splice_sending_sigs(tmpctx, &final_txid); wire_sync_write(MASTER_FD, take(msg)); + inflight->i_sent_sigs = true; peer_write(peer->pps, sigmsg); status_debug("Splice: we signed second"); } @@ -4102,7 +4144,8 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) peer->splicing->accepter_relative, ictx->current_psbt, false, - peer->splicing->force_sign_first); + peer->splicing->force_sign_first, + false); master_wait_sync_reply(tmpctx, peer, take(msg), WIRE_CHANNELD_GOT_INFLIGHT); @@ -4120,6 +4163,7 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) new_inflight->i_am_initiator = false; new_inflight->force_sign_first = peer->splicing->force_sign_first; new_inflight->locked_scid = NULL; + new_inflight->i_sent_sigs = false; current_push_val = relative_splice_balance_fundee(peer, our_role,ictx->current_psbt, outpoint.n, splice_funding_index); @@ -4279,6 +4323,8 @@ static void splice_initiator_user_finalized(struct peer *peer) u8 *outmsg; struct interactivetx_context *ictx; struct bitcoin_tx *prev_tx; + struct bitcoin_tx *bitcoin_tx; + struct bitcoin_signature splice_sig; bool sign_first; char *error; u32 chan_output_index, splice_funding_index; @@ -4290,6 +4336,7 @@ static void splice_initiator_user_finalized(struct peer *peer) struct amount_msat current_push_val; const enum tx_role our_role = TX_INITIATOR; u8 *abort_msg; + const u8* msg; /* We must loading the funding tx as our previous utxo */ prev_tx = bitcoin_tx_from_txid(peer, peer->channel->funding.txid); @@ -4338,6 +4385,44 @@ static void splice_initiator_user_finalized(struct peer *peer) psbt_elements_normalize_fees(ictx->current_psbt); + /* We have to sign the shared output early (here) for cases where we are + * splicing between multiple channels simultaneously. This is so the + * we can build a complete `tx_signatures` message when there are two + * or more shared outputs between mulitple peers */ + + splice_sig.sighash_type = SIGHASH_ALL; + + bitcoin_tx = bitcoin_tx_with_psbt(tmpctx, ictx->current_psbt); + + status_info("Splice pre-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 pre-set signature internally " + "funding_index: %d " + "my pubkey: %s " + "my signature: %s " + "psbt: %s", + splice_funding_index, + fmt_pubkey(tmpctx, + &peer->channel->funding_pubkey[LOCAL]), + fmt_bitcoin_signature(tmpctx, &splice_sig), + fmt_wally_psbt(tmpctx, ictx->current_psbt)); + status_debug("Splice adding inflight: %s", fmt_wally_psbt(tmpctx, ictx->current_psbt)); @@ -4352,7 +4437,8 @@ static void splice_initiator_user_finalized(struct peer *peer) peer->splicing->opener_relative, ictx->current_psbt, true, - peer->splicing->force_sign_first); + peer->splicing->force_sign_first, + false); master_wait_sync_reply(tmpctx, peer, take(outmsg), WIRE_CHANNELD_GOT_INFLIGHT); @@ -4369,6 +4455,7 @@ static void splice_initiator_user_finalized(struct peer *peer) new_inflight->i_am_initiator = true; new_inflight->force_sign_first = peer->splicing->force_sign_first; new_inflight->locked_scid = NULL; + new_inflight->i_sent_sigs = false; audit_psbt(ictx->current_psbt, ictx->current_psbt); @@ -4400,7 +4487,8 @@ static void splice_initiator_user_finalized(struct peer *peer) outmsg = towire_channeld_update_inflight(NULL, new_inflight->psbt, their_commit->tx, &their_commit->commit_signature, - new_inflight->locked_scid); + new_inflight->locked_scid, + new_inflight->i_sent_sigs); wire_sync_write(MASTER_FD, take(outmsg)); sign_first = do_i_sign_first(peer, new_inflight->psbt, our_role, @@ -4471,6 +4559,9 @@ static void splice_initiator_user_update(struct peer *peer, const u8 *inmsg) /* If there no are no changes, we consider the splice user finalized */ if (!interactivetx_has_changes(ictx, ictx->desired_psbt)) { + peer->splicing->current_psbt = tal_free(peer->splicing->current_psbt); + peer->splicing->current_psbt = clone_psbt(peer->splicing, + ictx->desired_psbt); splice_initiator_user_finalized(peer); tal_steal(last_inflight(peer), last_inflight(peer)->psbt); return; @@ -4594,7 +4685,8 @@ static void splice_initiator_user_signed(struct peer *peer, const u8 *inmsg) outmsg = towire_channeld_update_inflight(NULL, inflight->psbt, inflight->last_tx, &inflight->last_sig, - inflight->locked_scid); + inflight->locked_scid, + inflight->i_sent_sigs); wire_sync_write(MASTER_FD, take(outmsg)); @@ -6050,7 +6142,8 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg) inflight->psbt, NULL, NULL, - inflight->locked_scid); + inflight->locked_scid, + inflight->i_sent_sigs); wire_sync_write(MASTER_FD, take(msg)); inflight_match = inflight; } diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index c2833504153a..07db19025eb0 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -263,6 +263,7 @@ 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, +msgdata,channeld_add_inflight,i_sent_sigs,bool, # master->channeld: Inflight saved successfully msgtype,channeld_got_inflight,7217 @@ -273,6 +274,7 @@ msgdata,channeld_update_inflight,psbt,wally_psbt, msgdata,channeld_update_inflight,last_tx,?bitcoin_tx, msgdata,channeld_update_inflight,last_sig,?bitcoin_signature, msgdata,channeld_update_inflight,locked_scid,?short_channel_id, +msgdata,channeld_update_inflight,i_sent_sigs,bool, # channeld->master: A funding error has occured msgtype,channeld_splice_funding_error,7220 diff --git a/channeld/inflight.c b/channeld/inflight.c index 88e7ac60d409..db84e58196a8 100644 --- a/channeld/inflight.c +++ b/channeld/inflight.c @@ -34,6 +34,7 @@ struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t * else { inflight->locked_scid = NULL; } + inflight->i_sent_sigs = fromwire_bool(cursor, max); return inflight; } @@ -56,4 +57,5 @@ void towire_inflight(u8 **pptr, const struct inflight *inflight) towire_u8(pptr, inflight->locked_scid ? 1 : 0); if (inflight->locked_scid) towire_short_channel_id(pptr, *inflight->locked_scid); + towire_bool(pptr, inflight->i_sent_sigs); } diff --git a/channeld/inflight.h b/channeld/inflight.h index 73d9d1ad1f38..7143e0ad9ae6 100644 --- a/channeld/inflight.h +++ b/channeld/inflight.h @@ -20,6 +20,7 @@ struct inflight { bool i_am_initiator; bool force_sign_first; struct short_channel_id *locked_scid; + bool i_sent_sigs; }; struct inflight *fromwire_inflight(const tal_t *ctx, const u8 **cursor, size_t *max); diff --git a/common/interactivetx.c b/common/interactivetx.c index 0a72a7df658d..3ff709fb3bbb 100644 --- a/common/interactivetx.c +++ b/common/interactivetx.c @@ -23,6 +23,10 @@ #include #include +#ifndef SUPERVERBOSE +#define SUPERVERBOSE(...) +#endif + /* * BOLT #2: * The receiving node: ... @@ -197,6 +201,18 @@ static u8 *read_next_msg(const tal_t *ctx, } } +#define SHA_FMT \ + "%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x" \ + "%02x%02x%02x%02x%02x%02x%02x%02x" + +#define SHA_VALS(e) \ + e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], \ + e[8], e[9], e[10], e[11], e[12], e[13], e[14], e[15], \ + e[16], e[17], e[18], e[19], e[20], e[21], e[22], e[23], \ + e[24], e[25], e[25], e[26], e[28], e[29], e[30], e[31] + static char *send_next(const tal_t *ctx, struct interactivetx_context *ictx, bool *finished) @@ -268,6 +284,10 @@ static char *send_next(const tal_t *ctx, return "interactivetx RM_INPUT PSBT has invalid" " serial_id."; + SUPERVERBOSE("Removing input "SHA_FMT" with serial_id %s", + SHA_VALS(set->rm_ins[0].input.txhash), + tal_hexstr(ctx, &serial_id, sizeof(serial_id))); + msg = towire_tx_remove_input(NULL, cid, serial_id); tal_arr_remove(&set->rm_ins, 0); @@ -404,6 +424,36 @@ char *process_interactivetx_updates(const tal_t *ctx, if (!next_psbt) next_psbt = ictx->current_psbt; + SUPERVERBOSE("itx get_changes %zu inputs -> %zu inputs", + ictx->current_psbt->num_outputs, + next_psbt->num_inputs); + + SUPERVERBOSE("current_psbt inputs:"); + for(size_t i = 0; i < ictx->current_psbt->num_inputs; i++) { + u64 serial_id; + if (!psbt_get_serial_id(&ictx->current_psbt->inputs[i].unknowns, + &serial_id)) + return "interactivetx ADD_INPUT PSBT has invalid" + " serial_id."; + SUPERVERBOSE("txhash: "SHA_FMT", index: %"PRIu32", serial_id: %s", + SHA_VALS(ictx->current_psbt->inputs[i].txhash), + ictx->current_psbt->inputs[i].index, + tal_hexstr(ctx, &serial_id, sizeof(serial_id))); + } + + SUPERVERBOSE("next_psbt inputs:"); + for(size_t i = 0; i < next_psbt->num_inputs; i++) { + u64 serial_id; + if (!psbt_get_serial_id(&next_psbt->inputs[i].unknowns, + &serial_id)) + return "interactivetx ADD_INPUT PSBT has invalid" + " serial_id."; + SUPERVERBOSE("txhash: "SHA_FMT", index: %"PRIu32", serial_id: %s", + SHA_VALS(next_psbt->inputs[i].txhash), + next_psbt->inputs[i].index, + tal_hexstr(ctx, &serial_id, sizeof(serial_id))); + } + ictx->change_set = get_changes(ctx, ictx, next_psbt); /* If current_psbt and next_psbt are the same, dont double free it! diff --git a/common/psbt_open.c b/common/psbt_open.c index c2bf8558a190..d58932250341 100644 --- a/common/psbt_open.c +++ b/common/psbt_open.c @@ -82,6 +82,7 @@ static const u8 *linearize_input(const tal_t *ctx, wally_psbt_input_set_witness_script(&psbt->inputs[0], NULL, 0); wally_psbt_input_set_redeem_script(&psbt->inputs[0], NULL, 0); wally_psbt_input_set_taproot_signature(&psbt->inputs[0], NULL, 0); + wally_psbt_input_set_sighash(&psbt->inputs[0], 0); psbt->inputs[0].taproot_leaf_hashes.num_items = 0; psbt->inputs[0].taproot_leaf_paths.num_items = 0; psbt->inputs[0].keypaths.num_items = 0; diff --git a/lightningd/channel.c b/lightningd/channel.c index 94ff06c7b842..cf8286e50839 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -172,7 +172,8 @@ new_inflight(struct channel *channel, const struct amount_sat lease_amt, s64 splice_amnt, bool i_am_initiator, - bool force_sign_first) + bool force_sign_first, + bool i_sent_sigs) { struct channel_inflight *inflight = tal(channel, struct channel_inflight); @@ -208,6 +209,7 @@ new_inflight(struct channel *channel, inflight->i_am_initiator = i_am_initiator; inflight->force_sign_first = force_sign_first; inflight->locked_scid = NULL; + inflight->i_sent_sigs = i_sent_sigs; inflight->splice_locked_memonly = false; list_add_tail(&channel->inflights, &inflight->list); diff --git a/lightningd/channel.h b/lightningd/channel.h index f133dd2b4e36..1688aff5723d 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -86,6 +86,9 @@ struct channel_inflight { * peer through reconnect flows. */ struct short_channel_id *locked_scid; + /* Have I sent my peer my sigs? */ + bool i_sent_sigs; + /* Note: This field is not stored in the database. * * After splice_locked, we need a way to stop the chain watchers from @@ -456,7 +459,8 @@ struct channel_inflight *new_inflight(struct channel *channel, const struct amount_sat lease_amt, s64 splice_amnt, bool i_am_initiator, - bool force_sign_first); + bool force_sign_first, + bool i_sent_sigs); struct channel_state_change *new_channel_state_change(const tal_t *ctx, struct timeabs timestamp, diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index a2447136a200..fd968ba688c1 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -842,7 +842,7 @@ static void handle_add_inflight(struct lightningd *ld, s64 splice_amnt; struct wally_psbt *psbt; struct channel_inflight *inflight; - bool i_am_initiator, force_sign_first; + bool i_am_initiator, force_sign_first, i_sent_sigs; if (!fromwire_channeld_add_inflight(tmpctx, msg, @@ -854,7 +854,8 @@ static void handle_add_inflight(struct lightningd *ld, &splice_amnt, &psbt, &i_am_initiator, - &force_sign_first)) { + &force_sign_first, + &i_sent_sigs)) { channel_internal_error(channel, "bad channel_add_inflight %s", tal_hex(channel, msg)); @@ -877,7 +878,8 @@ static void handle_add_inflight(struct lightningd *ld, AMOUNT_SAT(0), splice_amnt, i_am_initiator, - force_sign_first); + force_sign_first, + i_sent_sigs); log_debug(channel->log, "lightningd adding inflight with txid %s", fmt_bitcoin_txid(tmpctx, @@ -898,9 +900,11 @@ static void handle_update_inflight(struct lightningd *ld, struct bitcoin_tx *last_tx; struct bitcoin_signature *last_sig; struct short_channel_id *locked_scid; + bool i_sent_sigs; if (!fromwire_channeld_update_inflight(tmpctx, msg, &psbt, &last_tx, - &last_sig, &locked_scid)) { + &last_sig, &locked_scid, + &i_sent_sigs)) { channel_internal_error(channel, "bad channel_add_inflight %s", tal_hex(channel, msg)); @@ -929,6 +933,7 @@ static void handle_update_inflight(struct lightningd *ld, inflight->last_sig = *last_sig; inflight->locked_scid = tal_steal(inflight, locked_scid); + inflight->i_sent_sigs = i_sent_sigs; tal_wally_start(); if (wally_psbt_combine(inflight->funding_psbt, psbt) != WALLY_OK) { @@ -1823,6 +1828,7 @@ bool peer_start_channeld(struct channel *channel, infcopy->i_am_initiator = inflight->i_am_initiator; infcopy->force_sign_first = inflight->force_sign_first; infcopy->locked_scid = tal_dup_or_null(infcopy, struct short_channel_id, inflight->locked_scid); + infcopy->i_sent_sigs = inflight->i_sent_sigs; tal_wally_start(); wally_psbt_clone_alloc(inflight->funding_psbt, 0, &infcopy->psbt); diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 7acb2237da5b..0c7aa239049d 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1300,6 +1300,7 @@ wallet_update_channel(struct lightningd *ld, lease_amt, 0, false, + false, false); wallet_inflight_add(ld->wallet, inflight); @@ -1538,6 +1539,7 @@ wallet_commit_channel(struct lightningd *ld, lease_amt, 0, false, + false, false); wallet_inflight_add(ld->wallet, inflight); return inflight; diff --git a/tests/test_splicing.py b/tests/test_splicing.py index 0f1c9359a566..682712455389 100644 --- a/tests/test_splicing.py +++ b/tests/test_splicing.py @@ -47,6 +47,82 @@ def test_splice(node_factory, bitcoind): 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_two_chan_splice_in(node_factory, bitcoind): + l1, l2, l3 = node_factory.line_graph(3, fundamount=1000000, wait_for_announce=True, opts={'experimental-splicing': None}) + + # l2 will splice funds into the channels with l1 and l3 at the same time + + chan_id1 = l2.get_channel_id(l1) + chan_id2 = l2.get_channel_id(l3) + + # add extra sats to pay fee + funds_result = l2.rpc.fundpsbt("209000sat", "slow", 166, excess_as_change=True) + + # Intiate splices to both channels + result = l2.rpc.splice_init(chan_id1, 100000, funds_result['psbt']) + result = l2.rpc.splice_init(chan_id2, 100000, result['psbt']) # start with psbt from first channel + + done1 = False + done2 = False + sigs1 = False + sigs2 = False + + while not done1 or not done2: + if not done1: + result = l2.rpc.splice_update(chan_id1, result['psbt']) + done1 = result['commitments_secured'] + sigs1 = result['signatures_secured'] + print("chan 1 " + result['psbt']) + if not done2: + result = l2.rpc.splice_update(chan_id2, result['psbt']) + done2 = result['commitments_secured'] + sigs2 = result['signatures_secured'] + print("chan 2 " + result['psbt']) + + print("Sigs1 " + str(sigs1) + ", Sigs2 " + str(sigs2)) + assert(sigs1 or sigs2) + + # Sign and finish splice for both channels + result = l2.rpc.signpsbt(result['psbt']) + result['psbt'] = result['signed_psbt'] + + if sigs2: + # If chan2 gave us sigs, start with chan1 + result = l2.rpc.splice_signed(chan_id1, result['psbt']) + result = l2.rpc.splice_signed(chan_id2, result['psbt']) + else: + # If chan1 gave us sigs, start with chan2 + result = l2.rpc.splice_signed(chan_id2, result['psbt']) + result = l2.rpc.splice_signed(chan_id1, result['psbt']) + + l3.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE') + l2.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE') + l1.daemon.wait_for_log(r'CHANNELD_NORMAL to CHANNELD_AWAITING_SPLICE') + + wait_for(lambda: len(list(bitcoind.rpc.getrawmempool(True).keys())) == 1) + mempool = bitcoind.rpc.getrawmempool(True) + assert result['txid'] in list(mempool.keys()) + + bitcoind.generate_block(6, wait_for_mempool=1) + + l3.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'CHANNELD_AWAITING_SPLICE to CHANNELD_NORMAL') + + inv = l2.rpc.invoice(10**2, '1', 'no_1') + l1.rpc.pay(inv['bolt11']) + + inv = l3.rpc.invoice(10**2, '2', 'no_2') + l2.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') diff --git a/wallet/db.c b/wallet/db.c index 569182d5e592..cebf3bd1e101 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -1042,6 +1042,7 @@ static struct migration dbmigrations[] = { {NULL, NULL}, /* Old, incorrect channel_htlcs_wait_indexes migration */ {SQL("ALTER TABLE channel_funding_inflights ADD locked_scid BIGINT DEFAULT 0;"), NULL}, {NULL, migrate_initialize_channel_htlcs_wait_indexes_and_fixup_forwards}, + {SQL("ALTER TABLE channel_funding_inflights ADD i_sent_sigs INTEGER DEFAULT 0"), NULL}, }; /** diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index 7c18dede5127..a85529321017 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -272,7 +272,8 @@ struct channel_inflight *new_inflight(struct channel *channel UNNEEDED, const struct amount_sat lease_amt UNNEEDED, s64 splice_amnt UNNEEDED, bool i_am_initiator UNNEEDED, - bool force_sign_first UNNEEDED) + bool force_sign_first UNNEEDED, + bool i_sent_sigs 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 5787f640c25f..3084da4dd427 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -2080,6 +2080,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) AMOUNT_SAT(1111), 0, false, + false, false); inflight->splice_locked_memonly = true; inflight->locked_scid = tal(inflight, struct short_channel_id); @@ -2110,6 +2111,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) AMOUNT_SAT(0), 0, false, + false, false); inflight->splice_locked_memonly = false; inflight->locked_scid = NULL; diff --git a/wallet/wallet.c b/wallet/wallet.c index 75f3b6fae18a..090ba7fbc3c4 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1415,8 +1415,9 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight) ", force_sign_first" ", remote_funding" ", locked_scid" + ", i_sent_sigs" ") VALUES (" - "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);")); db_bind_u64(stmt, inflight->channel->dbid); db_bind_txid(stmt, &inflight->funding->outpoint.txid); @@ -1463,6 +1464,7 @@ void wallet_inflight_add(struct wallet *w, struct channel_inflight *inflight) db_bind_short_channel_id(stmt, *inflight->locked_scid); else db_bind_null(stmt); + db_bind_int(stmt, inflight->i_sent_sigs); db_exec_prepared_v2(stmt); assert(!stmt->error); @@ -1567,7 +1569,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, force_sign_first; + bool i_am_initiator, force_sign_first, i_sent_sigs; secp256k1_ecdsa_signature *lease_commit_sig; u32 lease_blockheight_start; @@ -1611,6 +1613,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"); + i_sent_sigs = db_col_int(stmt, "i_sent_sigs"); inflight = new_inflight(chan, remote_funding, &funding, db_col_int(stmt, "funding_feerate"), @@ -1626,7 +1629,8 @@ wallet_stmt2inflight(struct wallet *w, struct db_stmt *stmt, lease_amt, splice_amnt, i_am_initiator, - force_sign_first); + force_sign_first, + i_sent_sigs); inflight->locked_scid = db_col_optional_scid(inflight, stmt, "locked_scid"); @@ -1682,6 +1686,7 @@ static bool wallet_channel_load_inflights(struct wallet *w, ", force_sign_first" ", remote_funding" ", locked_scid" + ", i_sent_sigs" " FROM channel_funding_inflights" " WHERE channel_id = ?" " ORDER BY funding_feerate"));