From 8b0713aafe7b68565fb2ba52f0876172efb9554c Mon Sep 17 00:00:00 2001 From: Dustin Dettmer Date: Thu, 3 Nov 2022 13:00:53 -0700 Subject: [PATCH] splice: (todo del) fixes to go in other commits --- channeld/channeld.c | 378 +++++++++++-------- channeld/channeld_wire.csv | 2 + channeld/full_channel.c | 21 +- channeld/full_channel.h | 14 + common/amount.c | 10 + common/amount.h | 2 + common/interactivetx.c | 281 ++++++++------ common/interactivetx.h | 39 +- common/psbt_open.c | 2 + contrib/pyln-client/pyln/client/lightning.py | 6 +- lightningd/channel_control.c | 30 +- tests/test_splicing.py | 11 +- wire/extracted_peer_exp_wire.patch | 4 +- 13 files changed, 474 insertions(+), 326 deletions(-) diff --git a/channeld/channeld.c b/channeld/channeld.c index e71624946d36..e870bb2e909e 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -154,6 +154,10 @@ struct peer { bool stfu_sent[NUM_SIDES]; /* Updates master asked, which we've deferred while quiescing */ struct msg_queue *update_queue; + /* The amount the user told us to commit to for a splice */ + struct amount_sat splice_opener_funding; + /* The amount the peer told us they were committing to for a splice */ + struct amount_sat splice_accepter_funding; /* Callback for when when stfu is negotiated successfully */ void (*on_stfu_success)(struct peer*); /* The number of splices that have been signed & committed */ @@ -161,7 +165,7 @@ struct peer { /* The number of splices that are active (awaiting confirmation) */ int splice_count; /* Track how many of each tx collab msg we receive */ - u16 tx_msg_count[INTERACTIVETX_NUM_TX_MSGS]; + u16 tx_add_input_count, tx_add_output_count; /* Current negoitated psbt */ struct wally_psbt *current_psbt; /* If, in the last splice_update, we tx_complete was received */ @@ -1552,10 +1556,12 @@ static void send_commit(struct peer *peer) break; splice_txs = channel_splice_txs(tmpctx, &outpoint, funding_sats, - &splice_htlc_map, splice_direct_outputs, - &funding_wscript, peer->channel, - &peer->remote_per_commit, - peer->next_index[REMOTE], REMOTE); + &splice_htlc_map, splice_direct_outputs, + &funding_wscript, peer->channel, + &peer->remote_per_commit, + peer->next_index[REMOTE], REMOTE); + + status_debug("SPLICE calc_commitsigs tx: %s", tal_hex(tmpctx, splice_txs[0])); /* Expand the larger commit's cs_tlv->splice_commitsigs array * as needed */ @@ -1798,7 +1804,7 @@ static void send_revocation(struct peer *peer, failed, changed, committx, - cs_tlv); + NULL); /* DTODO: Save the splice commitment info */ master_wait_sync_reply(tmpctx, peer, take(msg_for_master), WIRE_CHANNELD_GOT_COMMITSIG_REPLY); @@ -1972,7 +1978,7 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) || !tal_count(cs_tlv->splice_commitsigs)) peer_failed_warn(peer->pps, &peer->channel_id, "Bad commitment_signed mesage" - " without an empty splice commit sig" + " without a (needed) splice commit sig" " section."); if(tal_count(cs_tlv->splice_commitsigs) != peer->splice_count) peer_failed_warn(peer->pps, &peer->channel_id, @@ -2012,12 +2018,11 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) type = fromwire_peektype(master_msg); if (type != WIRE_CHANNELD_GOT_INFLIGHT) { - peer_failed_err(peer->pps, &peer->channel_id, "Channeld got incorrect message from " "lightningd: %d " - "(should be WIRE_CHANNELD_GOT_INFLIGHT)", type); - + "(should be WIRE_CHANNELD_GOT_INFLIGHT)", + type); break; } @@ -2054,7 +2059,8 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) &splice_funding_wscript, peer->channel, &peer->next_local_per_commit, peer->next_index[LOCAL], LOCAL); - + status_debug("SPLICE check_tx_sig tx: %s", tal_hex(tmpctx, splice_txs[0])); + /* check_tx_sig failing on on l2. dump splice_txs[0] here */ if (!check_tx_sig(splice_txs[0], 0, NULL, splice_funding_wscript, &peer->channel->funding_pubkey[REMOTE], &splice_commit_sig)) { dump_htlcs(peer->channel, "receiving splice_commit_sig"); @@ -2628,7 +2634,8 @@ static bool do_i_sign_first(struct peer *peer, struct interactivetx_context *ict return (ictx->our_role == TX_INITIATOR); } -static struct wally_psbt *next_splice_step(struct interactivetx_context *ictx) +static struct wally_psbt *next_splice_step(const tal_t *ctx, + struct interactivetx_context *ictx) { /* DTODO: add plugin wrapper for accepter side of splice to add to the * negotiated splice. */ @@ -2693,19 +2700,18 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) const u8 *wit_script; const u8 *msg, *sigmsg; enum peer_wire type; - struct interactivetx_context ictx; + struct interactivetx_context *ictx; struct witness_stack **inws, **outws; struct channel_id cid; struct bitcoin_txid txid; int splice_funding_index = -1; struct bitcoin_blkid genesis_blockhash; struct channel_id channel_id; + struct amount_sat intiator_amount, accepter_amount, both_amount, + total_in, change_out, miner_fee; u32 funding_feerate_perkw; struct pubkey splice_remote_pubkey; - char *error; - u64 total_in; - u64 change_out; - struct amount_sat funding_sats, our_funding_sats; + char *error; struct bitcoin_outpoint outpoint; u32 theirFeerate = channel_feerate(peer->channel, REMOTE); struct bitcoin_tx *bitcoin_tx; @@ -2714,11 +2720,14 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) size_t der_len, funding_der_len; struct tlv_txsigs_tlvs *our_txsigs_tlvs, *their_txsigs_tlvs; int chan_output_index = 0; - u64 miner_fee; + + ictx = new_interactivetx_context(tmpctx, TX_ACCEPTER, + peer->pps, peer->channel_id); if (!fromwire_splice(inmsg, &channel_id, &genesis_blockhash, + &intiator_amount, &funding_feerate_perkw, &splice_remote_pubkey)) peer_failed_warn(peer->pps, &peer->channel_id, @@ -2741,9 +2750,12 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) peer_failed_warn(peer->pps, &peer->channel_id, "Splice doesnt support changing pubkeys"); + accepter_amount = amount_msat_to_sat_round(peer->channel->view->owed[LOCAL]); + msg = towire_splice_ack(tmpctx, &peer->channel_id, &chainparams->genesis_blockhash, + accepter_amount, &peer->channel->funding_pubkey[LOCAL]); peer_write(peer->pps, take(msg)); @@ -2755,34 +2767,22 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) * - MUST begin splice negotiation. */ - ictx.ctx = peer; - ictx.our_role = TX_ACCEPTER; - ictx.pps = peer->pps; - ictx.channel_id = peer->channel_id; - ictx.tx_msg_count[0] = 0; - ictx.tx_msg_count[1] = 0; - ictx.tx_msg_count[2] = 0; - ictx.tx_msg_count[3] = 0; - assert(INTERACTIVETX_NUM_TX_MSGS == 4); - ictx.next_update = next_splice_step; - ictx.current_psbt = NULL; - ictx.desired_psbt = NULL; - ictx.pause_when_complete = false; - - error = process_interactivetx_updates(tmpctx, &ictx, NULL); + ictx->next_update = next_splice_step; + ictx->desired_psbt = NULL; + ictx->pause_when_complete = false; + + error = process_interactivetx_updates(tmpctx, ictx, NULL); if (error) peer_failed_err(peer->pps, &peer->channel_id, "Interactive splicing error: %s", error); - psbt_sort_by_serial_id(ictx.current_psbt); - wit_script = bitcoin_redeem_2of2(tmpctx, &peer->channel->funding_pubkey[1], &peer->channel->funding_pubkey[0]); - for (int i = 0; i < ictx.current_psbt->num_inputs; i++) { + for (int i = 0; i < ictx->current_psbt->num_inputs; i++) { struct wally_tx_input *in = - &ictx.current_psbt->tx->inputs[i]; + &ictx->current_psbt->tx->inputs[i]; if (0 != memcmp(in->txhash, &peer->channel->funding.txid, @@ -2800,40 +2800,53 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) chan_output_index = 0; /* DTODO: Calculate chan_output_index for cases where it's not index 0 */ - struct wally_tx_output *newChanOutpoint = &ictx.current_psbt->tx->outputs[chan_output_index]; + struct wally_tx_output *newChanOutpoint = &ictx->current_psbt->tx->outputs[chan_output_index]; - total_in = 0; - change_out = 0; + total_in = AMOUNT_SAT(0); - for (int i = 0; i < ictx.current_psbt->tx->num_inputs; i++) { - u64 amount = psbt_input_get_amount(ictx.current_psbt, i).satoshis; + for (int i = 0; i < ictx->current_psbt->tx->num_inputs; i++) { + struct amount_sat amount = psbt_input_get_amount(ictx->current_psbt, i); - if (!amount) + if (!amount.satoshis) peer_failed_warn(peer->pps, &peer->channel_id, "Input %d of splice does not have an input amount", i); - total_in += amount; + if(!amount_sat_add(&total_in, total_in, amount)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to add input amounts"); } + change_out = AMOUNT_SAT(0); + /* i = 1 to skip the first output (which is our new channel output!) */ /* DTODO: Find the index of our channel output explicitly. */ - for (int i = 1; i < ictx.current_psbt->tx->num_outputs; i++) - change_out += psbt_output_get_amount(ictx.current_psbt, i).satoshis; + for (int i = 1; i < ictx->current_psbt->tx->num_outputs; i++) + if(!amount_sat_add(&change_out, change_out, + psbt_output_get_amount(ictx->current_psbt, i))) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to add output amounts"); - /* DTODO: calculate miner fee based on feerate */ - miner_fee = 1000; + /* Calculate total channel output amount */ + if(!amount_sat_add(&both_amount, intiator_amount, accepter_amount)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to calculate channel amount"); - /* DTODO adjust local/remote balances based on byte ownership * miner fees */ - newChanOutpoint->satoshi = total_in - change_out - miner_fee; + /* Calculate miner fee */ + if(!amount_sat_sub(&miner_fee, total_in, change_out)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to calculate miner fee"); + if(!amount_sat_sub(&miner_fee, miner_fee, both_amount)) + peer_failed_warn(peer->pps, &peer->channel_id, + "Unable to calculate miner fee"); - psbt_elements_normalize_fees(ictx.current_psbt); + newChanOutpoint->satoshi = both_amount.satoshis; - funding_sats.satoshis = newChanOutpoint->satoshi; - our_funding_sats.satoshis = funding_sats.satoshis; + psbt_elements_normalize_fees(ictx->current_psbt); - psbt_txid(tmpctx, ictx.current_psbt, &outpoint.txid, NULL); + /* DTODO adjust local/remote balances based on byte ownership * miner fees */ + psbt_txid(tmpctx, ictx->current_psbt, &outpoint.txid, NULL); outpoint.n = 0; /* DTODO find output index using redeem script & validate there @@ -2845,15 +2858,17 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) &outpoint.txid, outpoint.n, theirFeerate, - funding_sats, - our_funding_sats, - ictx.current_psbt)); + both_amount, + accepter_amount, + ictx->current_psbt)); /* DTODO: Need to wait for an ack back here from lightningd for saftey */ peer->splice_count++; - interactive_send_commitments(peer, &ictx); + interactive_send_commitments(peer, ictx); + + psbt_sort_by_serial_id(ictx->current_psbt); /* DTODO Validate splice tx takes none of our funds in either: * 1) channel balance @@ -2862,7 +2877,7 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) splice_sig.sighash_type = SIGHASH_ALL; - bitcoin_tx = bitcoin_tx_with_psbt(tmpctx, ictx.current_psbt); + bitcoin_tx = bitcoin_tx_with_psbt(tmpctx, ictx->current_psbt); msg = towire_hsmd_sign_splice_tx(tmpctx, bitcoin_tx, &peer->channel->funding_pubkey[REMOTE], @@ -2875,12 +2890,15 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) 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, + if (!psbt_input_set_signature(ictx->current_psbt, splice_funding_index, &peer->channel->funding_pubkey[LOCAL], &splice_sig)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Unable to set signature internally"); + + /* DTODO: Replace below with psbt_to_witness_stacks */ + outws = tal_arr(tmpctx, struct witness_stack *, 1); outws[0] = tal(tmpctx, struct witness_stack); @@ -2908,7 +2926,7 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) (const struct witness_stack**)outws, our_txsigs_tlvs); - if (do_i_sign_first(peer, &ictx)) { + if (do_i_sign_first(peer, ictx)) { /* DTODO: Add transaction to inflights even though its missing the other signature */ peer_write(peer->pps, sigmsg); @@ -2952,10 +2970,11 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) tal_hex(msg, msg)); } + /* DTODO: move var to top */ struct pubkey *their_pubkey = &peer->channel->funding_pubkey[REMOTE]; /* Set the commit_sig on the commitment tx psbt */ - if (!psbt_input_set_signature(ictx.current_psbt, + if (!psbt_input_set_signature(ictx->current_psbt, splice_funding_index, their_pubkey, &their_sig)) { @@ -2964,17 +2983,17 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) "Unable to set signature internally"); } - psbt_input_set_witscript(ictx.current_psbt, + psbt_input_set_witscript(ictx->current_psbt, splice_funding_index, wit_script); - final_sigs_cnt = psbt_finalize_multisig_signatures(ictx.current_psbt, - &ictx.current_psbt->inputs[splice_funding_index]); + final_sigs_cnt = psbt_finalize_multisig_signatures(ictx->current_psbt, + &ictx->current_psbt->inputs[splice_funding_index]); /* We put the PSBT + sigs all together */ - for (size_t j = 0, i = 0; i < ictx.current_psbt->num_inputs; i++) { + for (size_t j = 0, i = 0; i < ictx->current_psbt->num_inputs; i++) { struct wally_psbt_input *in = - &ictx.current_psbt->inputs[i]; + &ictx->current_psbt->inputs[i]; u64 in_serial; const struct witness_element **elem; @@ -2982,7 +3001,7 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) status_broken("PSBT input %zu missing serial_id %s", i, type_to_string(tmpctx, struct wally_psbt, - ictx.current_psbt)); + ictx->current_psbt)); return; } if (in_serial % 2 != TX_INITIATOR) @@ -2999,14 +3018,12 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) elem = cast_const2(const struct witness_element **, inws[j++]->witness_element); - psbt_finalize_input(ictx.current_psbt, in, elem); + psbt_finalize_input(ictx->current_psbt, in, elem); } - psbt_finalize(ictx.current_psbt); - /* DTODO: validate our peer's signatures are correct */ - if (!do_i_sign_first(peer, &ictx)) + if (!do_i_sign_first(peer, ictx)) peer_write(peer->pps, sigmsg); else { @@ -3014,7 +3031,7 @@ static void splice_accepter(struct peer *peer, const u8 *inmsg) } struct bitcoin_tx *final_tx = bitcoin_tx_with_psbt(tmpctx, - ictx.current_psbt); + ictx->current_psbt); /* DTODO: Assert final_sigs_cnt is correct value? */ (void)final_sigs_cnt; @@ -3067,18 +3084,24 @@ static void splice_intiator(struct peer *peer, const u8 *inmsg) { struct bitcoin_blkid genesis_blockhash; struct channel_id channel_id; + struct amount_sat accepter_amount; struct pubkey splice_remote_pubkey; + size_t input_index; const u8 *wit_script; u8 *outmsg; - struct interactivetx_context ictx; + struct interactivetx_context *ictx; struct bitcoin_tx *prev_tx; u32 sequence = 0; u8 *scriptPubkey; char *error; + ictx = new_interactivetx_context(tmpctx, TX_INITIATOR, + peer->pps, peer->channel_id); + if (!fromwire_splice_ack(inmsg, &channel_id, &genesis_blockhash, + &accepter_amount, &splice_remote_pubkey)) peer_failed_warn(peer->pps, &peer->channel_id, "Bad wire_splice_ack %s", tal_hex(tmpctx, inmsg)); @@ -3099,19 +3122,9 @@ static void splice_intiator(struct peer *peer, const u8 *inmsg) peer->splice_locked_ready[LOCAL] = false; peer->splice_locked_ready[REMOTE] = false; - ictx.ctx = peer; - ictx.our_role = TX_INITIATOR; - ictx.pps = peer->pps; - ictx.channel_id = peer->channel_id; - ictx.tx_msg_count[0] = 0; - ictx.tx_msg_count[1] = 0; - ictx.tx_msg_count[2] = 0; - ictx.tx_msg_count[3] = 0; - BUILD_ASSERT(INTERACTIVETX_NUM_TX_MSGS == 4); - ictx.next_update = next_splice_step; - ictx.current_psbt = NULL; - ictx.desired_psbt = create_psbt(tmpctx, 0, 0, 0); - ictx.pause_when_complete = true; + ictx->next_update = next_splice_step; + ictx->pause_when_complete = true; + ictx->desired_psbt = peer->current_psbt; /* We go first as the receiver of the ack. * @@ -3125,6 +3138,8 @@ static void splice_intiator(struct peer *peer, const u8 *inmsg) &peer->channel->funding_pubkey[0], &peer->channel->funding_pubkey[1]); + input_index = ictx->desired_psbt->tx->num_inputs; + /* First we spend the existing channel outpoint * * Bolt #2 @@ -3132,18 +3147,18 @@ static void splice_intiator(struct peer *peer, const u8 *inmsg) * - MUST `tx_add_input` an input which spends the current funding * transaction output. */ - psbt_append_input(ictx.desired_psbt, &peer->channel->funding, sequence, + psbt_append_input(ictx->desired_psbt, &peer->channel->funding, sequence, NULL, wit_script, NULL); /* Segwit requires us to store the value of the outpoint being spent, * so let's do that */ - scriptPubkey = scriptpubkey_p2wsh(ictx.desired_psbt, wit_script); - psbt_input_set_wit_utxo(ictx.desired_psbt, 0, + scriptPubkey = scriptpubkey_p2wsh(ictx->desired_psbt, wit_script); + psbt_input_set_wit_utxo(ictx->desired_psbt, input_index, scriptPubkey, peer->channel->funding_sats); /* We must loading the funding tx as our previous utxo */ prev_tx = bitcoin_tx_from_txid(peer, peer->channel->funding.txid); - psbt_input_set_utxo(ictx.desired_psbt, 0, prev_tx->wtx); + psbt_input_set_utxo(ictx->desired_psbt, input_index, prev_tx->wtx); /* Next we add the new channel outpoint, with a 0 amount for now. It * will be filled in later. @@ -3154,89 +3169,110 @@ static void splice_intiator(struct peer *peer, const u8 *inmsg) * - MUST `tx_add_output` a zero-value output which pays to the two * funding keys using the higher of the two `generation` fields. */ - psbt_append_output(ictx.desired_psbt, - scriptpubkey_p2wsh(ictx.desired_psbt, wit_script), + psbt_append_output(ictx->desired_psbt, + scriptpubkey_p2wsh(ictx->desired_psbt, wit_script), amount_sat(0)); - psbt_add_serials(ictx.desired_psbt, ictx.our_role); - psbt_sort_by_serial_id(ictx.desired_psbt); + psbt_add_serials(ictx->desired_psbt, ictx->our_role); error = process_interactivetx_updates(tmpctx, - &ictx, - &peer->received_tx_complete); + ictx, + &peer->received_tx_complete); if (error) peer_failed_warn(peer->pps, &peer->channel_id, "Interactive splicing_ack error: %s", error); - psbt_add_serials(ictx.current_psbt, ictx.our_role); - psbt_sort_by_serial_id(ictx.current_psbt); + psbt_add_serials(ictx->current_psbt, ictx->our_role); - memcpy(peer->tx_msg_count, - ictx.tx_msg_count, - sizeof(peer->tx_msg_count)); + peer->tx_add_input_count = ictx->tx_add_input_count; + peer->tx_add_output_count = ictx->tx_add_output_count; - tal_free(peer->current_psbt); - peer->current_psbt = tal_steal(peer, ictx.current_psbt); + if(peer->current_psbt != ictx->current_psbt) + tal_free(peer->current_psbt); + peer->current_psbt = tal_steal(peer, ictx->current_psbt); /* Return the current PSBT to the channel_control to give to user. */ - outmsg = towire_channeld_splice_confirmed_init(tmpctx, - ictx.current_psbt); + outmsg = towire_channeld_splice_confirmed_init(NULL, + ictx->current_psbt); wire_sync_write(MASTER_FD, take(outmsg)); } + /* During a splice the user may call splice_update mulitple times adding * new details to the active PSBT. Each user call enters here: */ static void splice_intiator_user_update(struct peer *peer, const u8 *inmsg) { u8 *outmsg; - struct interactivetx_context ictx; + struct interactivetx_context *ictx; char *error; - ictx.ctx = peer; - ictx.our_role = TX_INITIATOR; - ictx.pps = peer->pps; - ictx.channel_id = peer->channel_id; - ictx.next_update = next_splice_step; - ictx.pause_when_complete = true; + ictx = new_interactivetx_context(tmpctx, TX_INITIATOR, + peer->pps, peer->channel_id); + + ictx->next_update = next_splice_step; + ictx->pause_when_complete = true; /* Should already have a current_psbt from a previously initiated one */ assert(peer->current_psbt); - ictx.current_psbt = peer->current_psbt; - memcpy(ictx.tx_msg_count, - peer->tx_msg_count, - sizeof(peer->tx_msg_count)); + ictx->current_psbt = peer->current_psbt; + ictx->tx_add_input_count = peer->tx_add_input_count; + ictx->tx_add_output_count = peer->tx_add_output_count; - if (!fromwire_channeld_splice_update(tmpctx, inmsg, &ictx.desired_psbt)) + if (!fromwire_channeld_splice_update(ictx, inmsg, &ictx->desired_psbt)) peer_failed_warn(peer->pps, &peer->channel_id, "Invalid splice update message: %s", tal_hex(tmpctx, inmsg)); /* User may not have setup serial numbers on their modifeid PSBT, so we * ensure that for them here */ - psbt_add_serials(ictx.desired_psbt, ictx.our_role); - psbt_sort_by_serial_id(ictx.desired_psbt); + psbt_add_serials(ictx->desired_psbt, ictx->our_role); - error = process_interactivetx_updates(tmpctx, &ictx, &peer->received_tx_complete); - if (error) + error = process_interactivetx_updates(tmpctx, ictx, &peer->received_tx_complete); + if(error) peer_failed_warn(peer->pps, &peer->channel_id, "Splice update error: %s", error); - psbt_add_serials(ictx.current_psbt, ictx.our_role); - psbt_sort_by_serial_id(ictx.current_psbt); + psbt_add_serials(ictx->current_psbt, ictx->our_role); - memcpy(peer->tx_msg_count, ictx.tx_msg_count, sizeof(peer->tx_msg_count)); + peer->tx_add_input_count = ictx->tx_add_input_count; + peer->tx_add_output_count = ictx->tx_add_output_count; - peer->current_psbt = tal_steal(peer, ictx.current_psbt); + if(peer->current_psbt != ictx->current_psbt) + tal_free(peer->current_psbt); + peer->current_psbt = tal_steal(peer, ictx->current_psbt); /* Peer may have modified our PSBT so we return it to the user here */ - outmsg = towire_channeld_splice_confirmed_update(tmpctx, - ictx.current_psbt, + outmsg = towire_channeld_splice_confirmed_update(NULL, + ictx->current_psbt, peer->received_tx_complete); wire_sync_write(MASTER_FD, take(outmsg)); } +static int find_channel_output(struct peer *peer, struct wally_psbt *psbt) +{ + const u8 *wit_script; + u8 *scriptpubkey; + + wit_script = bitcoin_redeem_2of2(tmpctx, + &peer->channel->funding_pubkey[0], + &peer->channel->funding_pubkey[1]); + + scriptpubkey = scriptpubkey_p2wsh(psbt, wit_script); + + for (int i = 0; i < psbt->tx->num_outputs; i++) + if(memeq(psbt->tx->outputs[i].script, + psbt->tx->outputs[i].script_len, + scriptpubkey, + tal_bytelen(scriptpubkey))) + return i; + + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Unable to find channel output"); + return -1; +} + /* This occurs when the user has marked they are done making changes to the * PSBT. Now we continually send `tx_complete` and intake our peer's changes * inside `process_interactivetx_updates`. Once they are onboard indicated @@ -3245,47 +3281,45 @@ static void splice_intiator_user_update(struct peer *peer, const u8 *inmsg) static void splice_intiator_user_finalized(struct peer *peer, const u8 *inmsg) { u8 *outmsg; - struct interactivetx_context ictx; + struct interactivetx_context *ictx; char *error; int chan_output_index; struct wally_tx_output *newChanOutpoint; struct amount_sat total_in, change_out, miner_fee, outpoint_sats; - ictx.ctx = peer; - ictx.our_role = TX_INITIATOR; - ictx.pps = peer->pps; - ictx.channel_id = peer->channel_id; - ictx.next_update = next_splice_step; - ictx.pause_when_complete = false; - ictx.current_psbt = peer->current_psbt; - ictx.desired_psbt = ictx.current_psbt; - memcpy(ictx.tx_msg_count, peer->tx_msg_count, sizeof(peer->tx_msg_count)); + ictx = new_interactivetx_context(tmpctx, TX_INITIATOR, + peer->pps, peer->channel_id); + + ictx->next_update = next_splice_step; + ictx->pause_when_complete = false; + ictx->current_psbt = peer->current_psbt; + ictx->desired_psbt = ictx->current_psbt; + ictx->tx_add_input_count = peer->tx_add_input_count; + ictx->tx_add_output_count = peer->tx_add_output_count; if (!fromwire_channeld_splice_finalize(inmsg)) peer_failed_warn(peer->pps, &peer->channel_id, "Invalid splice finalized message: %s", tal_hex(tmpctx, inmsg)); - psbt_add_serials(ictx.current_psbt, ictx.our_role); - psbt_sort_by_serial_id(ictx.current_psbt); + psbt_add_serials(ictx->current_psbt, ictx->our_role); - error = process_interactivetx_updates(tmpctx, &ictx, &peer->received_tx_complete); + error = process_interactivetx_updates(tmpctx, ictx, &peer->received_tx_complete); if (error) peer_failed_warn(peer->pps, &peer->channel_id, "Splice finalize error: %s", error); - psbt_add_serials(ictx.current_psbt, ictx.our_role); - psbt_sort_by_serial_id(ictx.current_psbt); + psbt_add_serials(ictx->current_psbt, ictx->our_role); + psbt_sort_by_serial_id(ictx->current_psbt); - /* DTODO: calculate channel output index correctly */ - chan_output_index = 0; - newChanOutpoint = &ictx.current_psbt->tx->outputs[chan_output_index]; + chan_output_index = find_channel_output(peer, ictx->current_psbt); + newChanOutpoint = &ictx->current_psbt->tx->outputs[chan_output_index]; total_in = AMOUNT_SAT(0); change_out = AMOUNT_SAT(0); - for (int i = 0; i < ictx.current_psbt->tx->num_inputs; i++) { - struct amount_sat amount = psbt_input_get_amount(ictx.current_psbt, i); + for (int i = 0; i < ictx->current_psbt->tx->num_inputs; i++) { + struct amount_sat amount = psbt_input_get_amount(ictx->current_psbt, i); if (!amount.satoshis) peer_failed_warn(peer->pps, &peer->channel_id, "Input %d of splice does not have an input amount", @@ -3295,10 +3329,10 @@ static void splice_intiator_user_finalized(struct peer *peer, const u8 *inmsg) "Unable to amount_sat_add input amounts"); } - for (int i = 0; i < ictx.current_psbt->tx->num_outputs; i++) + for (int i = 0; i < ictx->current_psbt->tx->num_outputs; i++) if(i != chan_output_index) if(!amount_sat_add(&change_out, change_out, - psbt_output_get_amount(ictx.current_psbt, + psbt_output_get_amount(ictx->current_psbt, i))) peer_failed_warn(peer->pps, &peer->channel_id, "Unable to amount_sat_add output amounts"); @@ -3317,11 +3351,11 @@ static void splice_intiator_user_finalized(struct peer *peer, const u8 *inmsg) /* DTODO: audit if we need more checks at this point (check feerate, * copy dualopen checks, spec, etc) */ - psbt_elements_normalize_fees(ictx.current_psbt); + psbt_elements_normalize_fees(ictx->current_psbt); - psbt_finalize(ictx.current_psbt); + psbt_finalize(ictx->current_psbt); - peer->current_psbt = tal_steal(peer, ictx.current_psbt); + peer->current_psbt = tal_steal(peer, ictx->current_psbt); outmsg = towire_channeld_splice_confirmed_finalize(tmpctx, peer->current_psbt); wire_sync_write(MASTER_FD, take(outmsg)); @@ -3340,7 +3374,7 @@ static void splice_intiator_user_signed(struct peer *peer, const u8 *inmsg) struct wally_tx_output *newChanOutpoint; struct bitcoin_outpoint outpoint; struct amount_sat funding_sats, our_funding_sats; - struct interactivetx_context ictx; + struct interactivetx_context *ictx; struct bitcoin_tx *bitcoin_tx, *final_tx; struct bitcoin_signature splice_sig; struct bitcoin_signature their_sig; @@ -3358,6 +3392,9 @@ static void splice_intiator_user_signed(struct peer *peer, const u8 *inmsg) int chan_output_index; u32 theirFeerate; + ictx = new_interactivetx_context(tmpctx, TX_INITIATOR, + peer->pps, peer->channel_id); + if (!fromwire_channeld_splice_signed(tmpctx, inmsg, &signed_psbt)) peer_failed_warn(peer->pps, &peer->channel_id, "Invalid splice signed message: %s", @@ -3370,8 +3407,7 @@ static void splice_intiator_user_signed(struct peer *peer, const u8 *inmsg) &peer->channel->funding_pubkey[REMOTE], &peer->channel->funding_pubkey[LOCAL]); - chan_output_index = 0; - /* DTODO: Calculate chan_output_index correctly. */ + chan_output_index = find_channel_output(peer, signed_psbt); newChanOutpoint = &signed_psbt->tx->outputs[chan_output_index]; @@ -3396,12 +3432,10 @@ static void splice_intiator_user_signed(struct peer *peer, const u8 *inmsg) peer->splice_count++; - ictx.our_role = TX_INITIATOR; - /* DTODO: ictx here is only used for signing order (intiator first * currently). When tx_sig ordering is spec finalzed ictx needs to be * removed here and placed with a correct ordering indicator object */ - interactive_send_commitments(peer, &ictx); + interactive_send_commitments(peer, ictx); splice_sig.sighash_type = SIGHASH_ALL; bitcoin_tx = bitcoin_tx_with_psbt(tmpctx, signed_psbt); @@ -3454,7 +3488,7 @@ static void splice_intiator_user_signed(struct peer *peer, const u8 *inmsg) &outpoint.txid, ws, txsig_tlvs); /* DTODO: Swap out ictx for correct thing when tx_sig spec is settled */ - if(do_i_sign_first(peer, &ictx)) + if(do_i_sign_first(peer, ictx)) peer_write(peer->pps, take(sigout_msg)); msg = peer_read(tmpctx, peer->pps); @@ -3504,7 +3538,7 @@ static void splice_intiator_user_signed(struct peer *peer, const u8 *inmsg) /* DTODO: validate our peer's signatures are correct */ /* DTODO: Swap out ictx for correct thing when tx_sig spec is settled */ - if(!do_i_sign_first(peer, &ictx)) + if(!do_i_sign_first(peer, ictx)) peer_write(peer->pps, take(sigout_msg)); /* Sending of TX_SIGNATURE implies the end of stfu mode */ @@ -3535,10 +3569,16 @@ static void splice_intiator_user_signed(struct peer *peer, const u8 *inmsg) /* This occurs once our 'stfu' transition was successful. */ static void handle_splice_stfu_success(struct peer *peer) { + u32 funding_feerate_perkw; + + /* DTODO: calculate intiator_amount and funding_feerate_perkw */ + funding_feerate_perkw = 0; + u8 *msg = towire_splice(tmpctx, &peer->channel_id, &chainparams->genesis_blockhash, - 0, + peer->splice_opener_funding, + funding_feerate_perkw, &peer->channel->funding_pubkey[LOCAL]); peer_write(peer->pps, take(msg)); } @@ -3549,6 +3589,12 @@ static void handle_splice_stfu_success(struct peer *peer) * splice happens at that point in `splice_intiator()`. */ static void handle_splice_init(struct peer *peer, const u8 *inmsg) { + peer->current_psbt = tal_free(peer->current_psbt); + + if (!fromwire_channeld_splice_init(peer, inmsg, &peer->current_psbt, + &peer->splice_opener_funding)) + master_badmsg(WIRE_CHANNELD_SPLICE_INIT, inmsg); + if (peer->on_stfu_success) peer_failed_err(peer->pps, &peer->channel_id, "Can't start a splice request" @@ -5437,13 +5483,13 @@ int main(int argc, char *argv[]) peer->stfu = false; peer->stfu_sent[LOCAL] = peer->stfu_sent[REMOTE] = false; peer->update_queue = msg_queue_new(peer, false); + peer->splice_opener_funding = AMOUNT_SAT(0); + peer->splice_accepter_funding = AMOUNT_SAT(0); peer->on_stfu_success = NULL; peer->committed_splice_count = 0; peer->splice_count = 0; - peer->tx_msg_count[0] = 0; - peer->tx_msg_count[1] = 0; - peer->tx_msg_count[2] = 0; - peer->tx_msg_count[3] = 0; + peer->tx_add_input_count = 0; + peer->tx_add_output_count = 0; peer->current_psbt = NULL; peer->received_tx_complete = false; peer->splice_locked_ready[LOCAL] = false; diff --git a/channeld/channeld_wire.csv b/channeld/channeld_wire.csv index 8b163087280e..956d564052dc 100644 --- a/channeld/channeld_wire.csv +++ b/channeld/channeld_wire.csv @@ -191,6 +191,8 @@ msgtype,channeld_got_revoke_reply,1122 # master->channeld: hello, I'd like to start a channel splice open msgtype,channeld_splice_init,7204 +msgdata,channeld_splice_init,psbt,wally_psbt, +msgdata,channeld_splice_init,funding_amount,amount_sat, # channeld->master: hello, I started a channel splice open msgtype,channeld_splice_confirmed_init,7205 diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 0395aa180f77..f5d51e262a23 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -299,6 +299,23 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx, const struct pubkey *per_commitment_point, u64 commitment_number, enum side side) +{ + return channel_splice_txs(ctx, &channel->funding, channel->funding_sats, + htlcmap, direct_outputs, funding_wscript, + channel, per_commitment_point, + commitment_number, side); +} + +struct bitcoin_tx **channel_splice_txs(const tal_t *ctx, + const struct bitcoin_outpoint *funding, + struct amount_sat funding_sats, + const struct htlc ***htlcmap, + struct wally_tx_output *direct_outputs[NUM_SIDES], + const u8 **funding_wscript, + const struct channel *channel, + const struct pubkey *per_commitment_point, + u64 commitment_number, + enum side side) { struct bitcoin_tx **txs; const struct htlc **committed; @@ -322,8 +339,8 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx, txs = tal_arr(ctx, struct bitcoin_tx *, 1); txs[0] = commit_tx( - ctx, &channel->funding, - channel->funding_sats, + ctx, funding, + funding_sats, &channel->funding_pubkey[side], &channel->funding_pubkey[!side], channel->opener, diff --git a/channeld/full_channel.h b/channeld/full_channel.h index 6f674a75f2c0..cfef42d27a88 100644 --- a/channeld/full_channel.h +++ b/channeld/full_channel.h @@ -76,6 +76,20 @@ struct bitcoin_tx **channel_txs(const tal_t *ctx, u64 commitment_number, enum side side); +/* Version of `channel_txs` that lets you specify a custom funding outpoint + * and funding_sats. + */ +struct bitcoin_tx **channel_splice_txs(const tal_t *ctx, + const struct bitcoin_outpoint *funding, + struct amount_sat funding_sats, + const struct htlc ***htlcmap, + struct wally_tx_output *direct_outputs[NUM_SIDES], + const u8 **funding_wscript, + const struct channel *channel, + const struct pubkey *per_commitment_point, + u64 commitment_number, + enum side side); + /** * actual_feerate: what is the actual feerate for the local side. * @channel: The channel state diff --git a/common/amount.c b/common/amount.c index ca48d86e0af9..350687ddcb93 100644 --- a/common/amount.c +++ b/common/amount.c @@ -37,6 +37,16 @@ struct amount_sat amount_msat_to_sat_round_down(struct amount_msat msat) return sat; } +struct amount_sat amount_msat_to_sat_round(struct amount_msat msat) +{ + struct amount_sat sat; + + sat.satoshis = msat.millisatoshis / MSAT_PER_SAT; + if (msat.millisatoshis % MSAT_PER_SAT >= MSAT_PER_SAT / 2) + sat.satoshis++; + return sat; +} + /* Different formatting by amounts: btc, sat and msat */ const char *fmt_amount_msat_btc(const tal_t *ctx, struct amount_msat msat, diff --git a/common/amount.h b/common/amount.h index de3dd5a3a764..5e1edc501f6a 100644 --- a/common/amount.h +++ b/common/amount.h @@ -60,6 +60,8 @@ WARN_UNUSED_RESULT bool amount_msat_to_sat(struct amount_sat *sat, /* You can always truncate millisatoshis->satoshis. */ struct amount_sat amount_msat_to_sat_round_down(struct amount_msat msat); +struct amount_sat amount_msat_to_sat_round(struct amount_msat msat); + /* Simple operations: val = a + b, val = a - b. */ WARN_UNUSED_RESULT bool amount_msat_add(struct amount_msat *val, struct amount_msat a, diff --git a/common/interactivetx.c b/common/interactivetx.c index 6d8bc4f8aed0..f94124e37ae9 100644 --- a/common/interactivetx.c +++ b/common/interactivetx.c @@ -1,5 +1,4 @@ #include "config.h" -#include "interactivetx.h" #include #include #include @@ -9,37 +8,74 @@ #include #include #include -#include #include #include +#include #include #include #include #include -#include #include +#include #include #include #include #include #include #include -#include +#include -#define NUM_TX_MSGS (TX_RM_OUTPUT + 1) -enum tx_msgs { - TX_ADD_INPUT, - TX_ADD_OUTPUT, - TX_RM_INPUT, - TX_RM_OUTPUT, -}; +/* + * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: + * The receiving node: ... + * - MUST fail the negotiation if: ... + * - if has received 4096 `tx_add_input` messages during this negotiation + */ +#define MAX_TX_ADD_INPUT_MSG_RCVD 4096 +/* + * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: + * The receiving node: ... + * - MUST fail the negotiation if: ... + * - it has received 4096 `tx_add_output` messages during this negotiation + */ +#define MAX_TX_ADD_OUTPUT_MSG_RCVD 4096 /* * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: - * The maximum inputs and outputs are capped at 252. This effectively fixes - * the byte size of the input and output counts on the transaction to one (1). + * The receiving node: ... + * - MUST fail the negotiation if: ... + * - there are more than 252 inputs + * - there are more than 252 outputs */ -#define MAX_TX_MSG_RCVD (1 << 12) +#define MAX_FUNDING_INPUTS 252 +#define MAX_FUNDING_OUTPUTS 252 + +static struct wally_psbt *default_next_update(const tal_t *ctx, + struct interactivetx_context *ictx) +{ + return ictx->desired_psbt; +} + +struct interactivetx_context *new_interactivetx_context(const tal_t *ctx, + enum tx_role our_role, + struct per_peer_state *pps, + struct channel_id channel_id) +{ + struct interactivetx_context *ictx = tal(ctx, struct interactivetx_context); + + ictx->our_role = our_role; + ictx->pps = pps; + ictx->channel_id = channel_id; + ictx->tx_add_input_count = 0; + ictx->tx_add_output_count = 0; + ictx->next_update = default_next_update; + ictx->current_psbt = create_psbt(ictx, 0, 0, 0); + ictx->desired_psbt = NULL; + ictx->pause_when_complete = false; + ictx->change_set = NULL; + + return ictx; +} static bool is_segwit_output(const tal_t *ctx, struct wally_tx_output *output, @@ -62,14 +98,12 @@ static u8 *read_next_msg(const tal_t *ctx, u8 *msg = NULL; for (;;) { - char *err; + char *desc; bool warning; - struct channel_id actual; enum peer_wire t; /* Prevent runaway memory usage from many messages */ - - if(msg) + if (msg) tal_free(msg); /* This helper routine polls the peer. */ @@ -86,37 +120,21 @@ static u8 *read_next_msg(const tal_t *ctx, /* A helper which decodes an error. */ if (is_peer_error(msg, msg, &state->channel_id, - &err, &warning)) { + &desc, &warning)) { /* In this case, is_peer_error returns true, but sets - * err to NULL */ - if (!err) + * desc to NULL */ + if (!desc) continue; - *error = tal_fmt(ctx, "They sent %s", err); + *error = tal_fmt(ctx, "They sent a %s: %s", + warning ? "warning" : "error", + desc); tal_free(msg); /* Return NULL so caller knows to stop negotiating. */ return NULL; } - /*~ We do not support multiple "live" channels, though the - * protocol has a "channel_id" field in all non-gossip messages - * so it's possible. Our one-process-one-channel mechanism - * keeps things simple: if we wanted to change this, we would - * probably be best with another daemon to de-multiplex them; - * this could be connectd itself, in fact. */ - if (is_wrong_channel(msg, &state->channel_id, &actual)) { - status_debug("Rejecting %s for unknown channel_id %s", - peer_wire_name(fromwire_peektype(msg)), - type_to_string(NULL, struct channel_id, - &actual)); - peer_write(state->pps, - take(towire_errorfmt(NULL, &actual, - "Multiple channels" - " unsupported"))); - continue; - } - /* In theory, we're in the middle of an open/RBF/splice, but * it's possible we can get some different messages in * the meantime! */ @@ -164,11 +182,11 @@ static u8 *read_next_msg(const tal_t *ctx, case WIRE_PING: case WIRE_PONG: case WIRE_SHUTDOWN: +#if EXPERIMENTAL_FEATURES + case WIRE_STFU: case WIRE_SPLICE: case WIRE_SPLICE_ACK: case WIRE_SPLICE_LOCKED: -#if EXPERIMENTAL_FEATURES - case WIRE_STFU: #endif *error = tal_fmt(ctx, "Received invalid message from peer: %d", t); @@ -184,27 +202,25 @@ static char *send_next(const tal_t *ctx, struct channel_id *cid = &ictx->channel_id; struct psbt_changeset *set = ictx->change_set; u64 serial_id; - u8 *msg = NULL; - + u8 *msg; *finished = false; - if(!set) + if (!set) goto tx_complete; - if(tal_count(set->added_ins) != 0) { - + if (tal_count(set->added_ins) != 0) { const struct input_set *in = &set->added_ins[0]; struct bitcoin_outpoint outpoint; u8 *prevtx; if (!psbt_get_serial_id(&in->input.unknowns, &serial_id)) - abort(); + return "interactivetx ADD_INPUT PSBT has invalid serial_id."; - if(in->input.utxo) + if (in->input.utxo) prevtx = linearize_wtx(ctx, in->input.utxo); else - return "PSBT needs the previous transaction set."; + return "interactivetx ADD_INPUT PSBT needs the previous transaction set."; memcpy(outpoint.txid.shad.sha.u.u8, in->tx_input.txhash, @@ -212,26 +228,23 @@ static char *send_next(const tal_t *ctx, outpoint.n = in->tx_input.index; - msg = towire_tx_add_input(ctx, cid, serial_id, + msg = towire_tx_add_input(NULL, cid, serial_id, prevtx, in->tx_input.index, in->tx_input.sequence, NULL); tal_arr_remove(&set->added_ins, 0); - } else if (tal_count(set->rm_ins) != 0) { - if (!psbt_get_serial_id(&set->rm_ins[0].input.unknowns, &serial_id)) - abort(); + return "interactivetx RM_INPUT PSBT has invalid serial_id."; - msg = towire_tx_remove_input(ctx, cid, serial_id); + msg = towire_tx_remove_input(NULL, cid, serial_id); tal_arr_remove(&set->rm_ins, 0); } else if (tal_count(set->added_outs) != 0) { - struct amount_sat sats; struct amount_asset asset_amt; const struct output_set *out; @@ -240,13 +253,13 @@ static char *send_next(const tal_t *ctx, out = &set->added_outs[0]; if (!psbt_get_serial_id(&out->output.unknowns, &serial_id)) - abort(); + return "interactivetx ADD_OUTPUT PSBT has invalid serial_id."; asset_amt = wally_tx_output_get_amount(&out->tx_output); sats = amount_asset_to_sat(&asset_amt); script = wally_tx_output_get_script(ctx, &out->tx_output); - msg = towire_tx_add_output(ctx, + msg = towire_tx_add_output(NULL, cid, serial_id, sats.satoshis, /* Raw: wire interface */ @@ -255,38 +268,43 @@ static char *send_next(const tal_t *ctx, tal_arr_remove(&set->added_outs, 0); } else if (tal_count(set->rm_outs) != 0) { - if (!psbt_get_serial_id(&set->rm_outs[0].output.unknowns, &serial_id)) - abort(); + return "interactivetx RM_OUTPUT PSBT has invalid serial_id."; - msg = towire_tx_remove_output(ctx, cid, serial_id); + msg = towire_tx_remove_output(NULL, cid, serial_id); tal_arr_remove(&set->rm_outs, 0); } - else { /* no changes to psbt */ - + else /* no changes to psbt */ goto tx_complete; - } - - if(!msg) { - - return "Interactivetx::send_next failed to build a message"; - } - peer_write(ictx->pps, msg); + if (!msg) + return "Interactivetx send_next failed to build a message"; + peer_write(ictx->pps, take(msg)); return NULL; tx_complete: - *finished = true; - - if(!ictx->pause_when_complete) { - - msg = towire_tx_complete(ctx, cid); - peer_write(ictx->pps, msg); + if (!ictx->pause_when_complete) { + if (ictx->current_psbt->num_inputs > MAX_FUNDING_INPUTS) + return tal_fmt(ctx, "Humbly refusing to `tx_complete` " + "because we have too many inputs (%zu). " + "Limit is %d.", + ictx->current_psbt->num_inputs, + MAX_FUNDING_INPUTS); + + if (ictx->current_psbt->num_outputs > MAX_FUNDING_OUTPUTS) + return tal_fmt(ctx, "Humbly refusing to `tx_complete` " + "because we have too many outputs (%zu). " + "Limit is %d.", + ictx->current_psbt->num_outputs, + MAX_FUNDING_OUTPUTS); + + msg = towire_tx_complete(NULL, cid); + peer_write(ictx->pps, take(msg)); } - + *finished = true; return NULL; } @@ -294,62 +312,52 @@ char *process_interactivetx_updates(const tal_t *ctx, struct interactivetx_context *ictx, bool *received_tx_complete) { - assert(NUM_TX_MSGS == INTERACTIVETX_NUM_TX_MSGS); - - if(ictx->current_psbt == NULL) - ictx->current_psbt = create_psbt(ctx, 0, 0, 0); - bool we_complete = false, they_complete = false; u8 *msg; char *error = NULL; + struct wally_psbt *next_psbt; - if(received_tx_complete) + if (received_tx_complete) they_complete = *received_tx_complete; /* Build change_set and handle PSBT variables */ + ictx->change_set = tal_free(ictx->change_set); - ictx->change_set = NULL; + /* Call next_update or default to 'desired_psbt' */ + next_psbt = ictx->next_update(ictx, ictx); - struct wally_psbt *next_psbt; - - if(ictx->next_update) - next_psbt = ictx->next_update(ictx); - else - next_psbt = ictx->desired_psbt; - - if(!next_psbt) + /* Returning NULL from next_update is the same as using `current_psbt` + * with no changes -- both indicate no changes */ + if (!next_psbt) next_psbt = ictx->current_psbt; - ictx->change_set = psbt_get_changeset(ctx, - ictx->current_psbt, - next_psbt); - - if(ictx->current_psbt != next_psbt) { - - tal_free(ictx->current_psbt); - + ictx->change_set = psbt_get_changeset(ictx, + ictx->current_psbt, + next_psbt); + + /* If current_psbt and next_psbt are the same, dont double free it! + * Otherwise we advance `current_psbt` to `next_psbt` and begin + * processing the change set in `ictx->change_set` */ + if (ictx->current_psbt != next_psbt) { + /* psbt_get_changeset requires we keep the current_psbt until + * we're done withh change_set */ + tal_steal(ictx->change_set, ictx->current_psbt); ictx->current_psbt = next_psbt; } /* As initiator we always start with a single send to start it off */ - - if(ictx->our_role == TX_INITIATOR) { - - char *error = send_next(ctx, ictx, &we_complete); - - if(error) + if (ictx->our_role == TX_INITIATOR) { + error = send_next(ctx, ictx, &we_complete); + if (error) return error; - if(ictx->pause_when_complete && we_complete) { - - /* Sort psbt! */ + if (ictx->pause_when_complete && we_complete) { psbt_sort_by_serial_id(ictx->current_psbt); return NULL; } } /* Loop through tx update turns with peer */ - while (!(we_complete && they_complete)) { struct channel_id cid; enum peer_wire t; @@ -359,12 +367,11 @@ char *process_interactivetx_updates(const tal_t *ctx, * they have to re-affirm every time */ they_complete = false; - if(received_tx_complete) + if (received_tx_complete) *received_tx_complete = false; msg = read_next_msg(ctx, ictx, &error); - - if(error) + if (error) return error; t = fromwire_peektype(msg); @@ -394,9 +401,10 @@ char *process_interactivetx_updates(const tal_t *ctx, * - if has received 4096 `tx_add_input` * messages during this negotiation */ - if (++ictx->tx_msg_count[TX_ADD_INPUT] > MAX_TX_MSG_RCVD) + if (++ictx->tx_add_input_count >= MAX_TX_ADD_INPUT_MSG_RCVD) return tal_fmt(ctx, "Too many `tx_add_input`s" - " received %d", MAX_TX_MSG_RCVD); + " received %d", + MAX_TX_ADD_INPUT_MSG_RCVD); /* * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: * The receiving node: ... @@ -463,6 +471,18 @@ char *process_interactivetx_updates(const tal_t *ctx, struct bitcoin_outpoint, &outpoint)); + /* + * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: + * The receiving node: ... + * - MUST fail the negotiation if: ... + * - there are more than 252 inputs + */ + if (ictx->current_psbt->num_inputs + 1 > MAX_FUNDING_INPUTS) + return tal_fmt(ctx, "Too many inputs. Have %zu," + " Max allowed %d", + ictx->current_psbt->num_inputs + 1, + MAX_FUNDING_INPUTS); + /* * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: * The receiving node: @@ -480,9 +500,10 @@ char *process_interactivetx_updates(const tal_t *ctx, tal_wally_start(); wally_psbt_input_set_utxo(in, tx->wtx); - tal_wally_end(ctx); + tal_wally_end(ictx); - psbt_input_set_serial_id(ctx, in, serial_id); + psbt_input_set_serial_id(ictx->current_psbt, + in, serial_id); break; } @@ -543,11 +564,11 @@ char *process_interactivetx_updates(const tal_t *ctx, * - it has received 4096 `tx_add_output` * messages during this negotiation */ - if (++ictx->tx_msg_count[TX_ADD_OUTPUT] > MAX_TX_MSG_RCVD) + if (++ictx->tx_add_output_count >= MAX_TX_ADD_OUTPUT_MSG_RCVD) return tal_fmt(ctx, "Too many `tx_add_output`s" " received (%d)", - MAX_TX_MSG_RCVD); + MAX_TX_ADD_OUTPUT_MSG_RCVD); /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: * The receiving node: ... @@ -577,11 +598,25 @@ char *process_interactivetx_updates(const tal_t *ctx, if (!is_known_scripttype(scriptpubkey)) return tal_fmt(ctx, "Script is not standard"); + /* + * BOLT-f53ca2301232db780843e894f55d95d512f297f9 #2: + * The receiving node: ... + * - MUST fail the negotiation if: ... + * - there are more than 252 outputs + */ + if (ictx->current_psbt->num_outputs + 1 > MAX_FUNDING_OUTPUTS) + return tal_fmt(ctx, "Too many inputs. Have %zu," + " Max allowed %d", + ictx->current_psbt->num_outputs + 1, + MAX_FUNDING_OUTPUTS); + out = psbt_append_output(ictx->current_psbt, scriptpubkey, amt); - psbt_output_set_serial_id(ctx, out, serial_id); + psbt_output_set_serial_id(ictx->current_psbt, + out, + serial_id); break; } case WIRE_TX_REMOVE_OUTPUT: { @@ -626,7 +661,7 @@ char *process_interactivetx_updates(const tal_t *ctx, "Parsing tx_complete %s", tal_hex(ctx, msg)); they_complete = true; - if(received_tx_complete) + if (received_tx_complete) *received_tx_complete = true; break; case WIRE_INIT: @@ -668,8 +703,8 @@ char *process_interactivetx_updates(const tal_t *ctx, #if EXPERIMENTAL_FEATURES case WIRE_SPLICE: case WIRE_SPLICE_ACK: - case WIRE_SPLICE_LOCKED: case WIRE_STFU: + case WIRE_SPLICE_LOCKED: #endif return tal_fmt(ctx, "Unexpected wire message %s", tal_hex(ctx, msg)); @@ -682,5 +717,7 @@ char *process_interactivetx_updates(const tal_t *ctx, /* Sort psbt! */ psbt_sort_by_serial_id(ictx->current_psbt); + tal_steal(ictx, ictx->current_psbt); + return NULL; } diff --git a/common/interactivetx.h b/common/interactivetx.h index 6066d4bedf70..96addb81daa5 100644 --- a/common/interactivetx.h +++ b/common/interactivetx.h @@ -1,7 +1,6 @@ #ifndef LIGHTNING_COMMON_INTERACTIVETX_H #define LIGHTNING_COMMON_INTERACTIVETX_H -#include "config.h" #include #include #include @@ -16,19 +15,22 @@ * WIRE_TX_COMPLETE the transaction is considered complete. */ -#define INTERACTIVETX_NUM_TX_MSGS 4 +#define INTERACTIVETX_NUM_TX_MSGS (TX_RM_OUTPUT + 1) +enum tx_msgs { + TX_ADD_INPUT, + TX_ADD_OUTPUT, + TX_RM_INPUT, + TX_RM_OUTPUT, +}; struct interactivetx_context { - /* Users can set this to their own context */ - void *ctx; - enum tx_role our_role; struct per_peer_state *pps; struct channel_id channel_id; /* Track how many of each tx collab msg we receive */ - u16 tx_msg_count[INTERACTIVETX_NUM_TX_MSGS]; + u16 tx_add_input_count, tx_add_output_count; /* Returns a PSBT with at least one change to the transaction as * compared to ictx->current_psbt. @@ -36,24 +38,19 @@ struct interactivetx_context { * If set to NULL, the default implementation will simply return * ictx->desired_psbt. * - * The resulting psbt's memory is stolen. - * - * If no more changes are demanded, return NULL or return current_psbt + * If no more changes are demanded, return NULL or current_psbt * unchanged to signal completion. */ - struct wally_psbt STEALS *(*next_update)(struct interactivetx_context *ictx); + struct wally_psbt *(*next_update)(const tal_t *ctx, + struct interactivetx_context *ictx); - /* Set this to the intial psbt. If NULL will be filled with an empty - * psbt. - */ + /* Set this to the intial psbt. Defaults to an empty PSBT. */ struct wally_psbt *current_psbt; /* Optional field for storing your side's desired psbt state, to be * used inside 'next_update'. - * - * If returned from next_update (the default) its memory will be stolen */ - struct wally_psbt *desired_psbt STEALS; + struct wally_psbt *desired_psbt; /* If true, process_interactivetx_updates will return when local changes * are exhausted and 'tx_complete' will not be sent. @@ -64,9 +61,15 @@ struct interactivetx_context { struct psbt_changeset *change_set; }; +/* Builds a new default interactivetx context with default values */ +struct interactivetx_context *new_interactivetx_context(const tal_t *ctx, + enum tx_role our_role, + struct per_peer_state *pps, + struct channel_id channel_id); + /* Blocks the thread until we run out of changes (and we send tx_complete), - * or an error occurs. If 'pause_when_complete' is set, this behavior changes - * and we return without sending tx_complete. + * or an error occurs. If 'pause_when_complete' on the `interactivetx_context` + * is set, this behavior changes and we return without sending tx_complete. * * If received_tx_complete is not NULL: * in -> true means we assume we've received tx_complete in a previous round. diff --git a/common/psbt_open.c b/common/psbt_open.c index 646b4ea029a5..ffed3cb79206 100644 --- a/common/psbt_open.c +++ b/common/psbt_open.c @@ -84,6 +84,8 @@ static const u8 *linearize_input(const tal_t *ctx, psbt->inputs[0].redeem_script_len = 0; psbt->inputs[0].keypaths.num_items = 0; psbt->inputs[0].signatures.num_items = 0; + psbt->inputs[0].utxo = NULL; + psbt->inputs[0].witness_utxo = NULL; const u8 *bytes = psbt_get_bytes(ctx, psbt, &byte_len); diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index 52bf36e0fdf9..ee547df3fab3 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1125,10 +1125,12 @@ def openchannel_abort(self, channel_id): } return self.call("openchannel_abort", payload) - def splice_init(self, peer_id): + def splice_init(self, peer_id, amount, initialpsbt): """ Initiate a splice """ payload = { - "id": peer_id + "id": peer_id, + "amount": amount + "initialpsbt": initialpsbt, } return self.call("splice_init", payload) diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 7394db08973d..401233c2c088 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -28,9 +28,9 @@ #include struct splice_command { - /* Inside struct lightningd close_commands. */ + /* Inside struct lightningd splice_commands. */ struct list_node list; - /* Command structure. This is the parent of the close command. */ + /* Command structure. This is the parent of the splice command. */ struct command *cmd; /* Channel being spliced. */ struct channel *channel; @@ -1689,12 +1689,20 @@ static struct command_result *json_splice_init(struct command *cmd, struct channel *channel; struct splice_command *cc; struct command_result *error; + struct wally_psbt *initialpsbt; + struct amount_sat *amount; + u8 *msg; if(!param(cmd, buffer, params, - p_opt("id", param_node_id, &id), + p_req("id", param_node_id, &id), + p_req("amount", param_sat, &amount), + p_opt("initialpsbt", param_psbt, &initialpsbt), NULL)) return command_param_failed(); + if(!initialpsbt) + initialpsbt = create_psbt(cmd, 0, 0, 0); + channel = splice_load_channel(cmd, id, &error); if (error) return error; @@ -1706,7 +1714,9 @@ static struct command_result *json_splice_init(struct command *cmd, cc->cmd = tal_steal(cc, cmd); cc->channel = channel; - subd_send_msg(channel->owner, take(towire_channeld_splice_init(NULL))); + msg = towire_channeld_splice_init(NULL, initialpsbt, *amount); + + subd_send_msg(channel->owner, take(msg)); return command_still_pending(cmd); } @@ -1722,8 +1732,8 @@ static struct command_result *json_splice_update(struct command *cmd, struct command_result *error; if(!param(cmd, buffer, params, - p_opt("id", param_node_id, &id), - p_opt("psbt", param_psbt, &psbt), + p_req("id", param_node_id, &id), + p_req("psbt", param_psbt, &psbt), NULL)) return command_param_failed(); @@ -1754,7 +1764,7 @@ static struct command_result *json_splice_finalize(struct command *cmd, struct command_result *error; if(!param(cmd, buffer, params, - p_opt("id", param_node_id, &id), + p_req("id", param_node_id, &id), NULL)) return command_param_failed(); @@ -1787,8 +1797,8 @@ static struct command_result *json_splice_signed(struct command *cmd, struct command_result *error; if(!param(cmd, buffer, params, - p_opt("id", param_node_id, &id), - p_opt("psbt", param_psbt, &psbt), + p_req("id", param_node_id, &id), + p_req("psbt", param_psbt, &psbt), NULL)) return command_param_failed(); @@ -1815,7 +1825,7 @@ static const struct json_command splice_init_command = { "splice_init", "channels", json_splice_init, - "Init a channel splice to {id} with {initialpsbt} for {amount} satoshis. " + "Init a channel splice to {id} for {amount} satoshis with {initialpsbt}. " "Returns updated {psbt} with (partial) contributions from peer" }; AUTODATA(json_command, &splice_init_command); diff --git a/tests/test_splicing.py b/tests/test_splicing.py index 9844a52b08f6..6d1fc0e13c46 100644 --- a/tests/test_splicing.py +++ b/tests/test_splicing.py @@ -14,16 +14,17 @@ def test_splice(node_factory, bitcoind): l1 = node_factory.get_node() l2 = node_factory.get_node() + + chan_size = 4000000 l1.rpc.connect(l2.rpc.getinfo()['id'], 'localhost:%d' % l2.port) - l1.openchannel(l2, 4000000) - - result = l1.rpc.splice_init(l2.rpc.getinfo()['id']) + l1.openchannel(l2, chan_size) funds_result = l1.rpc.fundpsbt("100000sat", "slow", 166) - result = bitcoind.rpc.joinpsbts([result['psbt'], funds_result['psbt']]) - result = l1.rpc.splice_update(l2.rpc.getinfo()['id'], result) + chan_size += 100000 + + result = l1.rpc.splice_init(l2.rpc.getinfo()['id'], chan_size, funds_result['psbt']) result = l1.rpc.splice_finalize(l2.rpc.getinfo()['id']) result = l1.rpc.signpsbt(result['psbt']) result = l1.rpc.splice_signed(l2.rpc.getinfo()['id'], result['signed_psbt']) diff --git a/wire/extracted_peer_exp_wire.patch b/wire/extracted_peer_exp_wire.patch index 4404ca8d444a..96ba87cc98d2 100644 --- a/wire/extracted_peer_exp_wire.patch +++ b/wire/extracted_peer_exp_wire.patch @@ -1,17 +1,19 @@ --- wire/peer_exp_wire.csv 2021-10-18 11:43:51.851963867 -0500 +++ - 2021-10-18 11:43:56.623816578 -0500 -@@ -127,6 +85,17 @@ +@@ -127,6 +85,19 @@ msgtype,stfu,2 msgdata,stfu,channel_id,channel_id, msgdata,stfu,initiator,u8, +msgtype,splice,74 +msgdata,splice,channel_id,channel_id, +msgdata,splice,chain_hash,chain_hash, ++msgdata,splice,funding_satoshis,u64, +msgdata,splice,funding_feerate_perkw,u32, +msgdata,splice,funding_pubkey,point, +msgtype,splice_ack,76 +msgdata,splice_ack,channel_id,channel_id, +msgdata,splice_ack,chain_hash,chain_hash, ++msgdata,splice_ack,funding_satoshis,u64, +msgdata,splice_ack,funding_pubkey,point, +msgtype,splice_locked,78, +msgdata,splice_locked,channel_id,channel_id,