onchaind: use lightningd to sign and broadcast htlc expired txs.

This is when they closed the channel, we can simply make our own tx to
expire the HTLC.  (The other case is where we closed the channel, and
we have a special htlc_timeout tx which we have their signature for).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2023-04-06 09:03:25 +09:30
parent 5bdd532e70
commit 0c27acc705
9 changed files with 169 additions and 181 deletions

View File

@@ -567,6 +567,10 @@ struct onchain_signing_info {
struct pubkey remote_per_commitment_point;
struct preimage preimage;
} fulfill;
/* WIRE_ONCHAIND_SPEND_HTLC_EXPIRED */
struct {
struct pubkey remote_per_commitment_point;
} htlc_expired;
} u;
};
@@ -660,6 +664,22 @@ static u8 *sign_fulfill(const tal_t *ctx,
info->channel->dbid);
}
static u8 *sign_htlc_expired(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_HTLC_EXPIRED);
return towire_hsmd_sign_any_remote_htlc_to_us(ctx,
&info->u.htlc_expired.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)
@@ -1172,6 +1192,59 @@ static void handle_onchaind_spend_htlc_timeout(struct channel *channel,
subd_send_msg(channel->owner, take(msg));
}
static void handle_onchaind_spend_htlc_expired(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;
u64 htlc_id;
u32 cltv_expiry, initial_feerate;
const bool anchor_outputs = channel_has(channel, OPT_ANCHOR_OUTPUTS);
info = new_signing_info(msg, channel, WIRE_ONCHAIND_SPEND_HTLC_EXPIRED);
/* BOLT #5:
*
* ## HTLC Output Handling: Remote Commitment, Local Offers
* ...
*
* - if the commitment transaction HTLC output has *timed out* AND NOT
* been *resolved*:
* - MUST *resolve* the output, by spending it to a convenient
* address.
*/
info->stack_elem = NULL;
if (!fromwire_onchaind_spend_htlc_expired(info, msg,
&out, &out_sats,
&htlc_id,
&cltv_expiry,
&info->u.htlc_expired.remote_per_commitment_point,
&info->wscript)) {
channel_internal_error(channel, "Invalid onchaind_spend_htlc_expired %s",
tal_hex(tmpctx, msg));
return;
}
/* nLocktime: we have to be *after* that block! */
info->minblock = cltv_expiry + 1;
/* FIXME: Be more sophisticated! */
initial_feerate = htlc_resolution_feerate(ld->topology);
if (!initial_feerate)
initial_feerate = tx_feerate(channel->last_tx);
/* We have to spend it before we can close incoming */
info->deadline_block = htlc_outgoing_incoming_deadline(channel, htlc_id);
create_onchain_tx(channel, &out, out_sats,
anchor_outputs ? 1 : 0,
cltv_expiry,
initial_feerate, sign_htlc_expired, info,
__func__);
}
static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds UNUSED)
{
enum onchaind_wire t = fromwire_peektype(msg);
@@ -1241,6 +1314,10 @@ static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds U
handle_onchaind_spend_fulfill(sd->channel, msg);
break;
case WIRE_ONCHAIND_SPEND_HTLC_EXPIRED:
handle_onchaind_spend_htlc_expired(sd->channel, msg);
break;
/* We send these, not receive them */
case WIRE_ONCHAIND_INIT:
case WIRE_ONCHAIND_SPENT:

View File

@@ -607,105 +607,6 @@ static struct amount_sat get_htlc_success_fee(struct tracked_output *out)
return fee;
}
static u8 *remote_htlc_to_us(const tal_t *ctx,
struct bitcoin_tx *tx,
const u8 *wscript)
{
return towire_hsmd_sign_remote_htlc_to_us(ctx,
remote_per_commitment_point,
tx, wscript,
option_anchor_outputs);
}
/*
* This covers:
* 1. to-us output spend (`<local_delayedsig> 0`)
* 2. the their-commitment, our HTLC timeout case (`<remotehtlcsig> 0`),
* 3. the their-commitment, our HTLC redeem case (`<remotehtlcsig> <payment_preimage>`)
* 4. the their-revoked-commitment, to-local (`<revocation_sig> 1`)
* 5. the their-revoked-commitment, htlc (`<revocation_sig> <revocationkey>`)
*
* Overrides *tx_type if it all turns to dust.
*/
static struct bitcoin_tx *tx_to_us(const tal_t *ctx,
u8 *(*hsm_sign_msg)(const tal_t *ctx,
struct bitcoin_tx *tx,
const u8 *wscript),
struct tracked_output *out,
u32 to_self_delay,
u32 locktime,
const void *elem, size_t elemsize,
const u8 *wscript,
enum tx_type *tx_type,
u32 feerate)
{
struct bitcoin_tx *tx;
struct amount_sat fee, min_out, amt;
struct bitcoin_signature sig;
size_t weight;
u8 *msg;
u8 **witness;
tx = bitcoin_tx(ctx, chainparams, 1, 1, locktime);
bitcoin_tx_add_input(tx, &out->outpoint, to_self_delay,
NULL, out->sat, NULL, wscript);
bitcoin_tx_add_output(
tx, scriptpubkey_p2wpkh(tmpctx, &our_wallet_pubkey), NULL, out->sat);
psbt_add_keypath_to_last_output(tx, our_wallet_index, &our_wallet_ext_key);
/* Worst-case sig is 73 bytes */
weight = bitcoin_tx_weight(tx) + 1 + 3 + 73 + 0 + tal_count(wscript);
weight += elements_tx_overhead(chainparams, 1, 1);
fee = amount_tx_fee(feerate, weight);
/* Result is trivial? Spend with small feerate, but don't wait
* around for it as it might not confirm. */
if (!amount_sat_add(&min_out, dust_limit, fee))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Cannot add dust_limit %s and fee %s",
type_to_string(tmpctx, struct amount_sat, &dust_limit),
type_to_string(tmpctx, struct amount_sat, &fee));
if (amount_sat_less(out->sat, min_out)) {
/* FIXME: We should use SIGHASH_NONE so others can take it */
fee = amount_tx_fee(feerate_floor(), weight);
status_unusual("TX %s amount %s too small to"
" pay reasonable fee, using minimal fee"
" and ignoring",
tx_type_name(*tx_type),
type_to_string(tmpctx, struct amount_sat, &out->sat));
*tx_type = IGNORING_TINY_PAYMENT;
}
/* This can only happen if feerate_floor() is still too high; shouldn't
* happen! */
if (!amount_sat_sub(&amt, out->sat, fee)) {
amt = dust_limit;
status_broken("TX %s can't afford minimal feerate"
"; setting output to %s",
tx_type_name(*tx_type),
type_to_string(tmpctx, struct amount_sat,
&amt));
}
bitcoin_tx_output_set_amount(tx, 0, amt);
bitcoin_tx_finalize(tx);
if (!wire_sync_write(HSM_FD, take(hsm_sign_msg(NULL, tx, wscript))))
status_failed(STATUS_FAIL_HSM_IO, "Writing sign request to hsm");
msg = wire_sync_read(tmpctx, HSM_FD);
if (!msg || !fromwire_hsmd_sign_tx_reply(msg, &sig)) {
status_failed(STATUS_FAIL_HSM_IO,
"Reading sign_tx_reply: %s",
tal_hex(tmpctx, msg));
}
witness = bitcoin_witness_sig_and_element(tx, &sig, elem,
elemsize, wscript);
bitcoin_tx_input_set_witness(tx, 0, take(witness));
return tx;
}
static void hsm_get_per_commitment_point(struct pubkey *per_commitment_point)
{
u8 *msg = towire_hsmd_get_per_commitment_point(NULL, commit_num);
@@ -1944,6 +1845,7 @@ static void wait_for_resolved(struct tracked_output **outs)
case WIRE_ONCHAIND_SPEND_HTLC_SUCCESS:
case WIRE_ONCHAIND_SPEND_HTLC_TIMEOUT:
case WIRE_ONCHAIND_SPEND_FULFILL:
case WIRE_ONCHAIND_SPEND_HTLC_EXPIRED:
break;
}
master_badmsg(-1, msg);
@@ -2201,9 +2103,10 @@ static size_t resolve_our_htlc_theircommit(struct tracked_output *out,
const struct htlc_stub *htlcs,
u8 **htlc_scripts)
{
struct bitcoin_tx *tx;
enum tx_type tx_type = OUR_HTLC_TIMEOUT_TO_US;
const u8 *msg;
u32 cltv_expiry = matches_cltv(matches, htlcs);
/* They're all equivalent: might as well use first one. */
const struct htlc_stub *htlc = &htlcs[matches[0]];
/* BOLT #5:
*
@@ -2215,14 +2118,17 @@ static size_t resolve_our_htlc_theircommit(struct tracked_output *out,
* - MUST *resolve* the output, by spending it to a convenient
* address.
*/
tx = tx_to_us(out, remote_htlc_to_us, out,
option_anchor_outputs ? 1 : 0,
cltv_expiry, NULL, 0,
htlc_scripts[matches[0]], &tx_type, htlc_feerate);
msg = towire_onchaind_spend_htlc_expired(NULL,
&out->outpoint, out->sat,
htlc->id,
cltv_expiry,
remote_per_commitment_point,
htlc_scripts[matches[0]]);
propose_resolution_to_master(out, take(msg),
/* nLocktime: we have to be *after* that block! */
cltv_expiry + 1,
OUR_HTLC_TIMEOUT_TO_US);
propose_resolution_at_block(out, tx, cltv_expiry, tx_type);
/* They're all equivalent: might as well use first one. */
return matches[0];
}

View File

@@ -197,6 +197,17 @@ msgdata,onchaind_spend_htlc_timeout,wscript,u8,wscript_len
msgdata,onchaind_spend_htlc_timeout,htlc_wscript_len,u32,
msgdata,onchaind_spend_htlc_timeout,htlc_wscript,u8,htlc_wscript_len
# We tell lightningd to create, sign and broadcast this tx to collect our
# expired htlc in their unilateral close:
msgtype,onchaind_spend_htlc_expired,5045
msgdata,onchaind_spend_htlc_expired,outpoint,bitcoin_outpoint,
msgdata,onchaind_spend_htlc_expired,outpoint_amount,amount_sat,
msgdata,onchaind_spend_htlc_expired,htlc_id,u64,
msgdata,onchaind_spend_htlc_expired,cltv_expiry,u32,
msgdata,onchaind_spend_htlc_expired,remote_per_commitment_point,pubkey,
msgdata,onchaind_spend_htlc_expired,wscript_len,u32,
msgdata,onchaind_spend_htlc_expired,wscript,u8,wscript_len
subtype,onchain_witness_element
subtypedata,onchain_witness_element,is_signature,bool,
subtypedata,onchain_witness_element,len,u32,
1 #include <bitcoin/tx_parts.h>
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

View File

@@ -211,9 +211,6 @@ void towire_ext_key(u8 **pptr UNNEEDED, const struct ext_key *bip32 UNNEEDED)
/* Generated stub for towire_hsmd_get_per_commitment_point */
u8 *towire_hsmd_get_per_commitment_point(const tal_t *ctx UNNEEDED, u64 n UNNEEDED)
{ fprintf(stderr, "towire_hsmd_get_per_commitment_point called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_remote_htlc_to_us */
u8 *towire_hsmd_sign_remote_htlc_to_us(const tal_t *ctx UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED, bool option_anchor_outputs UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_remote_htlc_to_us called!\n"); abort(); }
/* Generated stub for towire_htlc_stub */
void towire_htlc_stub(u8 **pptr UNNEEDED, const struct htlc_stub *htlc_stub UNNEEDED)
{ fprintf(stderr, "towire_htlc_stub called!\n"); abort(); }

View File

@@ -41,9 +41,6 @@ void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
/* Generated stub for fromwire_hsmd_get_per_commitment_point_reply */
bool fromwire_hsmd_get_per_commitment_point_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct pubkey *per_commitment_point UNNEEDED, struct secret **old_commitment_secret UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_get_per_commitment_point_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_sign_tx_reply */
bool fromwire_hsmd_sign_tx_reply(const void *p UNNEEDED, struct bitcoin_signature *sig UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_sign_tx_reply called!\n"); abort(); }
/* Generated stub for fromwire_onchaind_depth */
bool fromwire_onchaind_depth(const void *p UNNEEDED, struct bitcoin_txid *txid UNNEEDED, u32 *depth UNNEEDED)
{ fprintf(stderr, "fromwire_onchaind_depth called!\n"); abort(); }
@@ -272,9 +269,6 @@ void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
/* Generated stub for towire_hsmd_get_per_commitment_point */
u8 *towire_hsmd_get_per_commitment_point(const tal_t *ctx UNNEEDED, u64 n UNNEEDED)
{ fprintf(stderr, "towire_hsmd_get_per_commitment_point called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_remote_htlc_to_us */
u8 *towire_hsmd_sign_remote_htlc_to_us(const tal_t *ctx UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED, bool option_anchor_outputs UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_remote_htlc_to_us called!\n"); abort(); }
/* Generated stub for towire_onchaind_add_utxo */
u8 *towire_onchaind_add_utxo(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *prev_out UNNEEDED, const struct pubkey *per_commit_point UNNEEDED, struct amount_sat value UNNEEDED, u32 blockheight UNNEEDED, const u8 *scriptpubkey UNNEEDED, u32 csv_lock UNNEEDED)
{ fprintf(stderr, "towire_onchaind_add_utxo called!\n"); abort(); }
@@ -311,6 +305,9 @@ u8 *towire_onchaind_notify_coin_mvt(const tal_t *ctx UNNEEDED, const struct chai
/* 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_expired */
u8 *towire_onchaind_spend_htlc_expired(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u64 htlc_id UNNEEDED, u32 cltv_expiry UNNEEDED, const struct pubkey *remote_per_commitment_point UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_htlc_expired 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(); }

View File

@@ -2477,11 +2477,12 @@ def test_onchain_their_unilateral_out(node_factory, bitcoind):
l1.daemon.wait_for_log(' to ONCHAIN')
l2.daemon.wait_for_log(' to ONCHAIN')
l1.daemon.wait_for_log('THEIR_UNILATERAL/OUR_HTLC')
((_, txid, blocks),) = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 9
# l1 should wait til to_self_delay (10), then fulfill onchain
l2.bitcoin.generate_block(9)
l1.wait_for_onchaind_broadcast('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
l2.daemon.wait_for_log('Ignoring output .*_UNILATERAL/THEIR_HTLC')
err = q.get(timeout=10)
@@ -2492,7 +2493,7 @@ def test_onchain_their_unilateral_out(node_factory, bitcoind):
assert not t.is_alive()
# 100 blocks after last spend, l1+l2 should be done.
l2.bitcoin.generate_block(100)
l2.bitcoin.generate_block(100, wait_for_mempool=txid)
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
l2.daemon.wait_for_log('onchaind complete, forgetting peer')
@@ -2607,16 +2608,13 @@ def test_onchain_feechange(node_factory, bitcoind, executor):
l1.daemon.wait_for_log(' to ONCHAIN')
l2.daemon.wait_for_log(' to ONCHAIN')
# Wait for timeout.
l1.daemon.wait_for_log('Propose handling THEIR_UNILATERAL/OUR_HTLC by OUR_HTLC_TIMEOUT_TO_US .* after 6 blocks')
bitcoind.generate_block(6)
l1.wait_for_onchaind_broadcast('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
((_, txid, blocks),) = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5
bitcoind.generate_block(5)
# Make sure that gets included.
bitcoind.generate_block(1)
bitcoind.generate_block(1, wait_for_mempool=txid)
# Now we restart with different feerates.
l1.stop()
@@ -2634,15 +2632,15 @@ def test_onchain_feechange(node_factory, bitcoind, executor):
# and due to the l1 restart, there is none here.
l1.daemon.wait_for_log('WIRE_PERMANENT_CHANNEL_FAILURE')
# 90 later, l2 is done
bitcoind.generate_block(89)
# 91 later, l2 is done
bitcoind.generate_block(90)
sync_blockheight(bitcoind, [l2])
assert not l2.daemon.is_in_log('onchaind complete, forgetting peer')
bitcoind.generate_block(1)
l2.daemon.wait_for_log('onchaind complete, forgetting peer')
# Now, 7 blocks and l1 should be done.
bitcoind.generate_block(6)
# Now, 6 blocks and l1 should be done.
bitcoind.generate_block(5)
sync_blockheight(bitcoind, [l1])
assert not l1.daemon.is_in_log('onchaind complete, forgetting peer')
bitcoind.generate_block(1)
@@ -2697,15 +2695,15 @@ def test_onchain_all_dust(node_factory, bitcoind, executor):
l2.daemon.wait_for_log(' to ONCHAIN')
# Wait for timeout.
l1.daemon.wait_for_log('Propose handling THEIR_UNILATERAL/OUR_HTLC by IGNORING_TINY_PAYMENT .* after 6 blocks')
((_, txid, blocks),) = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5
# FIXME: l1 ignores it, *but it gets mined anyway*
l1.daemon.wait_for_log("Ignoring output .*: THEIR_UNILATERAL/OUR_HTLC")
bitcoind.generate_block(5)
l1.wait_for_onchaind_broadcast('IGNORING_TINY_PAYMENT',
'THEIR_UNILATERAL/OUR_HTLC')
l1.daemon.wait_for_log('Ignoring output .*: THEIR_UNILATERAL/OUR_HTLC')
# 100 deep and l2 forgets.
bitcoind.generate_block(93)
bitcoind.generate_block(93, wait_for_mempool=txid)
sync_blockheight(bitcoind, [l1, l2])
assert not l2.daemon.is_in_log('onchaind complete, forgetting peer')
assert not l1.daemon.is_in_log('onchaind complete, forgetting peer')
@@ -2718,27 +2716,28 @@ def test_onchain_all_dust(node_factory, bitcoind, executor):
assert account_balance(l1, channel_id) == 0
assert account_balance(l2, channel_id) == 0
# Graph of coin_move events we expect
expected_1 = {
'0': [('wallet', ['deposit'], ['withdrawal'], 'A')],
'A': [('wallet', ['deposit'], None, None), ('cid1', ['channel_open', 'opener'], ['channel_close'], 'B')],
'B': [('wallet', ['deposit'], None, None), ('cid1', ['htlc_timeout'], ['ignored'], 'C')],
'C': [('wallet', ['deposit'], None, None)],
}
# FIXME: This fails, but it's impenetrable to me :(
# # Graph of coin_move events we expect
# expected_1 = {
# '0': [('wallet', ['deposit'], ['withdrawal'], 'A')],
# 'A': [('wallet', ['deposit'], None, None), ('cid1', ['channel_open', 'opener'], ['channel_close'], 'B')],
# 'B': [('wallet', ['deposit'], None, None), ('cid1', ['htlc_timeout'], None, None)],
# 'C': [('wallet', ['deposit'], None, None)],
# }
expected_2 = {
'A': [('cid1', ['channel_open'], ['channel_close'], 'B')],
'B': [('external', ['to_them'], None, None), ('external', ['htlc_timeout'], None, None)],
}
# expected_2 = {
# 'A': [('cid1', ['channel_open'], ['channel_close'], 'B')],
# 'B': [('external', ['to_them'], None, None), ('external', ['htlc_timeout'], None, None)],
# }
if anchor_expected():
expected_1['B'].append(('external', ['anchor'], None, None))
expected_2['B'].append(('external', ['anchor'], None, None))
expected_1['B'].append(('wallet', ['anchor', 'ignored'], None, None))
expected_2['B'].append(('wallet', ['anchor', 'ignored'], None, None))
# if anchor_expected():
# expected_1['B'].append(('external', ['anchor'], None, None))
# expected_2['B'].append(('external', ['anchor'], None, None))
# expected_1['B'].append(('wallet', ['anchor', 'ignored'], None, None))
# expected_2['B'].append(('wallet', ['anchor', 'ignored'], None, None))
tags = check_utxos_channel(l1, [channel_id], expected_1)
check_utxos_channel(l2, [channel_id], expected_2, tags)
# tags = check_utxos_channel(l1, [channel_id], expected_1)
# check_utxos_channel(l2, [channel_id], expected_2, tags)
@pytest.mark.developer("needs DEVELOPER=1 for dev_fail")
@@ -2828,14 +2827,14 @@ def test_permfail_new_commit(node_factory, bitcoind, executor):
l1.daemon.wait_for_log(' to ONCHAIN')
l2.daemon.wait_for_log(' to ONCHAIN')
l2.daemon.wait_for_log('Propose handling OUR_UNILATERAL/THEIR_HTLC by THEIR_HTLC_TIMEOUT_TO_THEM \\(IGNORING\\) after 6 blocks')
l1.daemon.wait_for_log('Propose handling THEIR_UNILATERAL/OUR_HTLC by OUR_HTLC_TIMEOUT_TO_US (.*) after 6 blocks')
((_, txid, blocks),) = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5
# OK, time out HTLC.
bitcoind.generate_block(5)
l1.wait_for_onchaind_broadcast('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
bitcoind.generate_block(1)
bitcoind.generate_block(1, wait_for_mempool=txid)
l1.daemon.wait_for_log('Resolved THEIR_UNILATERAL/OUR_HTLC by our proposal OUR_HTLC_TIMEOUT_TO_US')
l2.daemon.wait_for_log('Ignoring output.*: OUR_UNILATERAL/THEIR_HTLC')
@@ -3109,7 +3108,9 @@ def test_permfail_htlc_in(node_factory, bitcoind, executor):
l1.daemon.wait_for_log(' to ONCHAIN')
l2.daemon.wait_for_log(' to ONCHAIN')
l2.daemon.wait_for_log('Propose handling OUR_UNILATERAL/THEIR_HTLC by THEIR_HTLC_TIMEOUT_TO_THEM \\(IGNORING\\) after 6 blocks')
l1.daemon.wait_for_log('Propose handling THEIR_UNILATERAL/OUR_HTLC by OUR_HTLC_TIMEOUT_TO_US (.*) after 6 blocks')
((_, _, blocks),) = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5
# l2 then gets preimage, uses it instead of ignoring
((_, txid, blocks),) = l2.wait_for_onchaind_tx('OUR_HTLC_SUCCESS_TX',
'OUR_UNILATERAL/THEIR_HTLC')

View File

@@ -293,14 +293,15 @@ def test_htlc_sig_persistence(node_factory, bitcoind, executor):
l1.start()
assert l1.daemon.is_in_log(r'Loaded 1 HTLC signatures from DB')
l1.daemon.wait_for_logs([
r'Peer permanent failure in CHANNELD_NORMAL: Funding transaction spent',
r'Propose handling THEIR_UNILATERAL/OUR_HTLC by OUR_HTLC_TIMEOUT_TO_US'
])
# Could happen in either order!
l1.daemon.wait_for_log(r'Peer permanent failure in CHANNELD_NORMAL: Funding transaction spent')
((_, txid, blocks),) = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5
bitcoind.generate_block(5)
l1.daemon.wait_for_log("Broadcasting OUR_HTLC_TIMEOUT_TO_US")
time.sleep(3)
bitcoind.generate_block(1)
bitcoind.generate_block(1, wait_for_mempool=txid)
l1.daemon.wait_for_logs([
r'Owning output . (\d+)sat .SEGWIT. txid',
])

View File

@@ -1621,13 +1621,12 @@ def test_forward_local_failed_stats(node_factory, bitcoind, executor):
l4.daemon.wait_for_log(' to ONCHAIN')
# Wait for timeout.
l2.daemon.wait_for_log('Propose handling THEIR_UNILATERAL/OUR_HTLC by OUR_HTLC_TIMEOUT_TO_US .* after 6 blocks')
bitcoind.generate_block(6)
((_, txid, blocks),) = l2.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5
bitcoind.generate_block(5)
l2.wait_for_onchaind_broadcast('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
bitcoind.generate_block(1)
bitcoind.generate_block(1, wait_for_mempool=txid)
l2.daemon.wait_for_log('Resolved THEIR_UNILATERAL/OUR_HTLC by our proposal OUR_HTLC_TIMEOUT_TO_US')
l4.daemon.wait_for_log('Ignoring output.*: OUR_UNILATERAL/THEIR_HTLC')

View File

@@ -1332,13 +1332,12 @@ def test_forward_event_notification(node_factory, bitcoind, executor):
l2.daemon.wait_for_log(' to ONCHAIN')
l5.daemon.wait_for_log(' to ONCHAIN')
l2.daemon.wait_for_log('Propose handling THEIR_UNILATERAL/OUR_HTLC by OUR_HTLC_TIMEOUT_TO_US .* after 6 blocks')
bitcoind.generate_block(6)
((_, txid, blocks),) = l2.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5
bitcoind.generate_block(5)
l2.wait_for_onchaind_broadcast('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
bitcoind.generate_block(1)
bitcoind.generate_block(1, wait_for_mempool=txid)
l2.daemon.wait_for_log('Resolved THEIR_UNILATERAL/OUR_HTLC by our proposal OUR_HTLC_TIMEOUT_TO_US')
l5.daemon.wait_for_log('Ignoring output.*: OUR_UNILATERAL/THEIR_HTLC')