diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index bfbf9ad8b..734d63a3b 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -557,6 +557,11 @@ struct onchain_signing_info { struct bitcoin_signature remote_htlc_sig; struct preimage preimage; } htlc_success; + /* WIRE_ONCHAIND_SPEND_FULFILL */ + struct { + struct pubkey remote_per_commitment_point; + struct preimage preimage; + } fulfill; } u; }; @@ -618,6 +623,22 @@ static u8 *sign_htlc_success(const tal_t *ctx, info->channel->dbid); } +static u8 *sign_fulfill(const tal_t *ctx, + const struct bitcoin_tx *tx, + const struct onchain_signing_info *info) +{ + const bool anchor_outputs = channel_has(info->channel, OPT_ANCHOR_OUTPUTS); + + assert(info->msgtype == WIRE_ONCHAIND_SPEND_FULFILL); + return towire_hsmd_sign_any_remote_htlc_to_us(ctx, + &info->u.fulfill.remote_per_commitment_point, + tx, info->wscript, + anchor_outputs, + 0, + &info->channel->peer->id, + info->channel->dbid); +} + /* Matches bitcoin_witness_sig_and_element! */ static const struct onchain_witness_element ** onchain_witness_sig_and_element(const tal_t *ctx, u8 **witness) @@ -913,6 +934,51 @@ static void handle_onchaind_spend_penalty(struct channel *channel, __func__); } +static void handle_onchaind_spend_fulfill(struct channel *channel, + const u8 *msg) +{ + struct lightningd *ld = channel->peer->ld; + struct onchain_signing_info *info; + struct bitcoin_outpoint out; + struct amount_sat out_sats; + struct preimage preimage; + u32 initial_feerate; + u64 htlc_id; + const bool anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS); + + info = new_signing_info(msg, channel, WIRE_ONCHAIND_SPEND_FULFILL); + info->minblock = 0; + + if (!fromwire_onchaind_spend_fulfill(info, msg, + &out, &out_sats, + &htlc_id, + &info->u.fulfill.remote_per_commitment_point, + &preimage, + &info->wscript)) { + channel_internal_error(channel, "Invalid onchaind_spend_fulfill %s", + tal_hex(tmpctx, msg)); + return; + } + info->stack_elem = tal_dup(info, struct preimage, &preimage); + + /* FIXME: Be more sophisticated! */ + initial_feerate = htlc_resolution_feerate(ld->topology); + if (!initial_feerate) + initial_feerate = tx_feerate(channel->last_tx); + + info->deadline_block = htlc_incoming_deadline(channel, htlc_id); + /* BOLT #3: + * + * Note that if `option_anchors` applies, the nSequence field of + * the spending input must be `1`. + */ + create_onchain_tx(channel, &out, out_sats, + anchor_outputs ? 1 : 0, + 0, + initial_feerate, sign_fulfill, info, + __func__); +} + static void handle_onchaind_spend_htlc_success(struct channel *channel, const u8 *msg) { @@ -1048,6 +1114,10 @@ static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds U handle_onchaind_spend_htlc_success(sd->channel, msg); break; + case WIRE_ONCHAIND_SPEND_FULFILL: + handle_onchaind_spend_fulfill(sd->channel, msg); + break; + /* We send these, not receive them */ case WIRE_ONCHAIND_INIT: case WIRE_ONCHAIND_SPENT: diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 081d57c86..ba27e3a5e 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -1742,7 +1742,7 @@ static void handle_preimage(struct tracked_output **outs, ripemd160(&ripemd, &sha, sizeof(sha)); for (i = 0; i < tal_count(outs); i++) { - struct bitcoin_tx *tx; + const u8 *msg; if (outs[i]->output_type != THEIR_HTLC) continue; @@ -1779,7 +1779,6 @@ static void handle_preimage(struct tracked_output **outs, */ if (outs[i]->remote_htlc_sig) { struct amount_sat fee; - const u8 *msg; const u8 *htlc_wscript; /* FIXME: lightningd could derive this itself? */ @@ -1802,8 +1801,6 @@ static void handle_preimage(struct tracked_output **outs, propose_immediate_resolution(outs[i], take(msg), OUR_HTLC_SUCCESS_TX); } else { - enum tx_type tx_type = THEIR_HTLC_FULFILL_TO_US; - /* BOLT #5: * * ## HTLC Output Handling: Remote Commitment, Remote @@ -1817,13 +1814,16 @@ static void handle_preimage(struct tracked_output **outs, * - MUST *resolve* the output by spending it to a * convenient address. */ - tx = tx_to_us(outs[i], remote_htlc_to_us, outs[i], - option_anchor_outputs ? 1 : 0, - 0, preimage, sizeof(*preimage), - outs[i]->wscript, &tx_type, - htlc_feerate); - propose_resolution(outs[i], tx, 0, tx_type); + msg = towire_onchaind_spend_fulfill(NULL, + &outs[i]->outpoint, + outs[i]->sat, + outs[i]->htlc.id, + remote_per_commitment_point, + preimage, + outs[i]->wscript); + propose_immediate_resolution(outs[i], take(msg), + THEIR_HTLC_FULFILL_TO_US); } } } @@ -1960,6 +1960,7 @@ static void wait_for_resolved(struct tracked_output **outs) case WIRE_ONCHAIND_SPEND_TO_US: case WIRE_ONCHAIND_SPEND_PENALTY: case WIRE_ONCHAIND_SPEND_HTLC_SUCCESS: + case WIRE_ONCHAIND_SPEND_FULFILL: break; } master_badmsg(-1, msg); diff --git a/onchaind/onchaind_wire.csv b/onchaind/onchaind_wire.csv index 98f568380..386584e32 100644 --- a/onchaind/onchaind_wire.csv +++ b/onchaind/onchaind_wire.csv @@ -173,6 +173,16 @@ msgdata,onchaind_spend_htlc_success,wscript,u8,wscript_len msgdata,onchaind_spend_htlc_success,htlc_wscript_len,u32, msgdata,onchaind_spend_htlc_success,htlc_wscript,u8,htlc_wscript_len +# We tell lightningd to create, sign and broadcast this HTLC redepmtion: +msgtype,onchaind_spend_fulfill,5043 +msgdata,onchaind_spend_fulfill,outpoint,bitcoin_outpoint, +msgdata,onchaind_spend_fulfill,outpoint_amount,amount_sat, +msgdata,onchaind_spend_fulfill,htlc_id,u64, +msgdata,onchaind_spend_fulfill,remote_per_commitment_point,pubkey, +msgdata,onchaind_spend_fulfill,preimage,preimage, +msgdata,onchaind_spend_fulfill,wscript_len,u32, +msgdata,onchaind_spend_fulfill,wscript,u8,wscript_len + subtype,onchain_witness_element subtypedata,onchain_witness_element,is_signature,bool, subtypedata,onchain_witness_element,len,u32, diff --git a/onchaind/test/run-grind_feerate-bug.c b/onchaind/test/run-grind_feerate-bug.c index 3a44fb5a8..37b2135c7 100644 --- a/onchaind/test/run-grind_feerate-bug.c +++ b/onchaind/test/run-grind_feerate-bug.c @@ -282,6 +282,9 @@ u8 *towire_onchaind_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct /* Generated stub for towire_onchaind_notify_coin_mvt */ u8 *towire_onchaind_notify_coin_mvt(const tal_t *ctx UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED) { fprintf(stderr, "towire_onchaind_notify_coin_mvt called!\n"); abort(); } +/* Generated stub for towire_onchaind_spend_fulfill */ +u8 *towire_onchaind_spend_fulfill(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u64 htlc_id UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const struct preimage *preimage UNNEEDED, const u8 *wscript UNNEEDED) +{ fprintf(stderr, "towire_onchaind_spend_fulfill called!\n"); abort(); } /* Generated stub for towire_onchaind_spend_htlc_success */ u8 *towire_onchaind_spend_htlc_success(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, struct amount_sat fee UNNEEDED, u64 htlc_id UNNEEDED, u64 commit_num UNNEEDED, const struct bitcoin_signature *remote_htlc_sig UNNEEDED, const struct preimage *preimage UNNEEDED, const u8 *wscript UNNEEDED, const u8 *htlc_wscript UNNEEDED) { fprintf(stderr, "towire_onchaind_spend_htlc_success called!\n"); abort(); } diff --git a/onchaind/test/run-grind_feerate.c b/onchaind/test/run-grind_feerate.c index 5b4d8a51c..608e251cb 100644 --- a/onchaind/test/run-grind_feerate.c +++ b/onchaind/test/run-grind_feerate.c @@ -314,6 +314,9 @@ u8 *towire_onchaind_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct /* Generated stub for towire_onchaind_notify_coin_mvt */ u8 *towire_onchaind_notify_coin_mvt(const tal_t *ctx UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED) { fprintf(stderr, "towire_onchaind_notify_coin_mvt called!\n"); abort(); } +/* Generated stub for towire_onchaind_spend_fulfill */ +u8 *towire_onchaind_spend_fulfill(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u64 htlc_id UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const struct preimage *preimage UNNEEDED, const u8 *wscript UNNEEDED) +{ fprintf(stderr, "towire_onchaind_spend_fulfill called!\n"); abort(); } /* Generated stub for towire_onchaind_spend_htlc_success */ u8 *towire_onchaind_spend_htlc_success(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, struct amount_sat fee UNNEEDED, u64 htlc_id UNNEEDED, u64 commit_num UNNEEDED, const struct bitcoin_signature *remote_htlc_sig UNNEEDED, const struct preimage *preimage UNNEEDED, const u8 *wscript UNNEEDED, const u8 *htlc_wscript UNNEEDED) { fprintf(stderr, "towire_onchaind_spend_htlc_success called!\n"); abort(); } diff --git a/tests/test_closing.py b/tests/test_closing.py index 4b5534180..42e64eaaf 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -2382,15 +2382,16 @@ def test_onchain_middleman_their_unilateral_in(node_factory, bitcoind): l2.daemon.wait_for_log('THEIR_UNILATERAL/THEIR_HTLC') # l2 should fulfill HTLC onchain, immediately - l2.wait_for_onchaind_broadcast('THEIR_HTLC_FULFILL_TO_US', - 'THEIR_UNILATERAL/THEIR_HTLC') + ((_, txid2, blocks),) = l2.wait_for_onchaind_tx('THEIR_HTLC_FULFILL_TO_US', + 'THEIR_UNILATERAL/THEIR_HTLC') + assert blocks == 0 ((_, txid, blocks),) = l1.wait_for_onchaind_tx('OUR_DELAYED_RETURN_TO_WALLET', 'OUR_UNILATERAL/DELAYED_OUTPUT_TO_US') assert blocks == 4 # Payment should succeed. - l1.bitcoin.generate_block(1) + l1.bitcoin.generate_block(1, wait_for_mempool=txid2) l1.daemon.wait_for_log('OUR_UNILATERAL/OUR_HTLC gave us preimage') err = q.get(timeout=10) if err: @@ -3164,17 +3165,17 @@ def test_permfail_htlc_out(node_factory, bitcoind, executor): l2.daemon.wait_for_log('Propose handling OUR_UNILATERAL/OUR_HTLC by OUR_HTLC_TIMEOUT_TX \\(.*\\) after 6 blocks') l2.daemon.logsearch_start = needle - ((_, txid, blocks),) = l2.wait_for_onchaind_tx('OUR_DELAYED_RETURN_TO_WALLET', - 'OUR_UNILATERAL/DELAYED_OUTPUT_TO_US') + ((_, txid2, blocks),) = l2.wait_for_onchaind_tx('OUR_DELAYED_RETURN_TO_WALLET', + 'OUR_UNILATERAL/DELAYED_OUTPUT_TO_US') assert blocks == 4 l1.daemon.wait_for_log('Propose handling THEIR_UNILATERAL/THEIR_HTLC by THEIR_HTLC_TIMEOUT_TO_THEM \\(IGNORING\\) after 6 blocks') # l1 then gets preimage, uses it instead of ignoring - l1.wait_for_onchaind_broadcast('THEIR_HTLC_FULFILL_TO_US', - 'THEIR_UNILATERAL/THEIR_HTLC') - + ((_, txid1, blocks),) = l1.wait_for_onchaind_tx('THEIR_HTLC_FULFILL_TO_US', + 'THEIR_UNILATERAL/THEIR_HTLC') + assert blocks == 0 # l2 sees l1 fulfill tx. - bitcoind.generate_block(1) + bitcoind.generate_block(1, wait_for_mempool=txid1) l2.daemon.wait_for_log('OUR_UNILATERAL/OUR_HTLC gave us preimage') t.cancel() @@ -3183,7 +3184,7 @@ def test_permfail_htlc_out(node_factory, bitcoind, executor): bitcoind.generate_block(3) # Now, 100 blocks they should be done. - bitcoind.generate_block(95, txid) + bitcoind.generate_block(95, txid2) sync_blockheight(bitcoind, [l1, l2]) assert not l1.daemon.is_in_log('onchaind complete, forgetting peer') assert not l2.daemon.is_in_log('onchaind complete, forgetting peer')