onchaind: have lightningd create our penalty txs.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2023-04-06 09:03:24 +09:30
parent 36dd70e677
commit 3e53c6e359
7 changed files with 181 additions and 86 deletions

View File

@@ -546,6 +546,10 @@ struct onchain_signing_info {
struct { struct {
u64 commit_num; u64 commit_num;
} htlc_timedout; } htlc_timedout;
/* WIRE_ONCHAIND_SPEND_PENALTY */
struct {
struct secret remote_per_commitment_secret;
} spend_penalty;
} u; } u;
}; };
@@ -578,6 +582,19 @@ static u8 *sign_tx_to_us(const tal_t *ctx,
info->channel->dbid); info->channel->dbid);
} }
static u8 *sign_penalty(const tal_t *ctx,
const struct bitcoin_tx *tx,
const struct onchain_signing_info *info)
{
assert(info->msgtype == WIRE_ONCHAIND_SPEND_PENALTY);
return towire_hsmd_sign_any_penalty_to_us(ctx,
&info->u.spend_penalty.remote_per_commitment_secret,
tx, info->wscript,
0,
&info->channel->peer->id,
info->channel->dbid);
}
/* Matches bitcoin_witness_sig_and_element! */ /* Matches bitcoin_witness_sig_and_element! */
static const struct onchain_witness_element ** static const struct onchain_witness_element **
onchain_witness_sig_and_element(const tal_t *ctx, u8 **witness) onchain_witness_sig_and_element(const tal_t *ctx, u8 **witness)
@@ -791,6 +808,47 @@ static void handle_onchaind_spend_to_us(struct channel *channel,
__func__); __func__);
} }
static void handle_onchaind_spend_penalty(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;
u32 initial_feerate;
u8 *stack_elem;
info = new_signing_info(msg, channel, WIRE_ONCHAIND_SPEND_PENALTY);
/* We can always spend penalty txs immediately */
info->minblock = 0;
if (!fromwire_onchaind_spend_penalty(info, msg,
&out, &out_sats,
&info->u.spend_penalty.remote_per_commitment_secret,
&stack_elem,
&info->wscript)) {
channel_internal_error(channel, "Invalid onchaind_spend_penalty %s",
tal_hex(tmpctx, msg));
return;
}
/* info->stack_elem is const void * */
info->stack_elem = stack_elem;
/* FIXME: Be more sophisticated! */
initial_feerate = penalty_feerate(ld->topology);
if (!initial_feerate)
initial_feerate = tx_feerate(channel->last_tx);
/* FIXME: deadline for HTLCs is actually a bit longer, but for
* their output it's channel->our_config.to_self_delay after
* the commitment tx is mined. */
info->deadline_block = *channel->close_blockheight
+ channel->our_config.to_self_delay;
create_onchain_tx(channel, &out, out_sats,
0, 0,
initial_feerate, sign_penalty, info,
__func__);
}
static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds UNUSED) static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds UNUSED)
{ {
enum onchaind_wire t = fromwire_peektype(msg); enum onchaind_wire t = fromwire_peektype(msg);
@@ -844,6 +902,10 @@ static unsigned int onchain_msg(struct subd *sd, const u8 *msg, const int *fds U
handle_onchaind_spend_to_us(sd->channel, msg); handle_onchaind_spend_to_us(sd->channel, msg);
break; break;
case WIRE_ONCHAIND_SPEND_PENALTY:
handle_onchaind_spend_penalty(sd->channel, msg);
break;
/* We send these, not receive them */ /* We send these, not receive them */
case WIRE_ONCHAIND_INIT: case WIRE_ONCHAIND_INIT:
case WIRE_ONCHAIND_SPENT: case WIRE_ONCHAIND_SPENT:

View File

@@ -1,6 +1,7 @@
#include "config.h" #include "config.h"
#include <bitcoin/feerate.h> #include <bitcoin/feerate.h>
#include <bitcoin/script.h> #include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h> #include <ccan/asort/asort.h>
#include <ccan/cast/cast.h> #include <ccan/cast/cast.h>
#include <ccan/mem/mem.h> #include <ccan/mem/mem.h>
@@ -624,14 +625,6 @@ static u8 *remote_htlc_to_us(const tal_t *ctx,
option_anchor_outputs); option_anchor_outputs);
} }
static u8 *penalty_to_us(const tal_t *ctx,
struct bitcoin_tx *tx,
const u8 *wscript)
{
return towire_hsmd_sign_penalty_to_us(ctx, remote_per_commitment_secret,
tx, wscript);
}
/* /*
* This covers: * This covers:
* 1. to-us output spend (`<local_delayedsig> 0`) * 1. to-us output spend (`<local_delayedsig> 0`)
@@ -927,6 +920,17 @@ static void propose_resolution_to_master(struct tracked_output *out,
queue_until_msg(tmpctx, WIRE_ONCHAIND_SPEND_CREATED)); queue_until_msg(tmpctx, WIRE_ONCHAIND_SPEND_CREATED));
} }
/* Create and broadcast this tx now */
static void propose_immediate_resolution(struct tracked_output *out,
const u8 *send_message TAKES,
enum tx_type tx_type)
{
/* We add 1 to blockheight (meaning you can broadcast it now) to avoid
* having to check for < 0 in various places we print messages */
propose_resolution_to_master(out, send_message, out->tx_blockheight+1,
tx_type);
}
static bool is_valid_sig(const u8 *e) static bool is_valid_sig(const u8 *e)
{ {
struct bitcoin_signature sig; struct bitcoin_signature sig;
@@ -1417,11 +1421,10 @@ static void steal_htlc_tx(struct tracked_output *out,
enum tx_type htlc_tx_type, enum tx_type htlc_tx_type,
const struct bitcoin_outpoint *htlc_outpoint) const struct bitcoin_outpoint *htlc_outpoint)
{ {
struct bitcoin_tx *tx;
enum tx_type tx_type = OUR_PENALTY_TX;
struct tracked_output *htlc_out; struct tracked_output *htlc_out;
struct amount_asset asset; struct amount_asset asset;
struct amount_sat htlc_out_amt; struct amount_sat htlc_out_amt;
const u8 *msg;
u8 *wscript = bitcoin_wscript_htlc_tx(htlc_tx, to_self_delay[REMOTE], u8 *wscript = bitcoin_wscript_htlc_tx(htlc_tx, to_self_delay[REMOTE],
&keyset->self_revocation_key, &keyset->self_revocation_key,
@@ -1437,22 +1440,23 @@ static void steal_htlc_tx(struct tracked_output *out,
htlc_out_amt, htlc_out_amt,
DELAYED_CHEAT_OUTPUT_TO_THEM, DELAYED_CHEAT_OUTPUT_TO_THEM,
&out->htlc, wscript, NULL); &out->htlc, wscript, NULL);
/* mark commitment tx htlc output as 'resolved by them' */
resolved_by_other(out, &htlc_tx->txid, htlc_tx_type);
/* BOLT #3: /* BOLT #3:
* *
* To spend this via penalty, the remote node uses a witness stack * To spend this via penalty, the remote node uses a witness stack
* `<revocationsig> 1` * `<revocationsig> 1`
*/ */
tx = tx_to_us(htlc_out, penalty_to_us, htlc_out, msg = towire_onchaind_spend_penalty(NULL,
BITCOIN_TX_RBF_SEQUENCE, 0, htlc_outpoint, htlc_out_amt,
&ONE, sizeof(ONE), remote_per_commitment_secret,
htlc_out->wscript, tal_dup(tmpctx, u8, &ONE),
&tx_type, penalty_feerate); htlc_out->wscript);
/* mark commitment tx htlc output as 'resolved by them' */ /* Spend this immediately. */
resolved_by_other(out, &htlc_tx->txid, htlc_tx_type); propose_immediate_resolution(htlc_out, take(msg), OUR_PENALTY_TX);
/* annnd done! */
propose_resolution(htlc_out, tx, 0, tx_type);
} }
static void onchain_annotate_txout(const struct bitcoin_outpoint *outpoint, static void onchain_annotate_txout(const struct bitcoin_outpoint *outpoint,
@@ -1964,6 +1968,7 @@ static void wait_for_resolved(struct tracked_output **outs)
case WIRE_ONCHAIND_ANNOTATE_TXIN: case WIRE_ONCHAIND_ANNOTATE_TXIN:
case WIRE_ONCHAIND_NOTIFY_COIN_MVT: case WIRE_ONCHAIND_NOTIFY_COIN_MVT:
case WIRE_ONCHAIND_SPEND_TO_US: case WIRE_ONCHAIND_SPEND_TO_US:
case WIRE_ONCHAIND_SPEND_PENALTY:
break; break;
} }
master_badmsg(-1, msg); master_badmsg(-1, msg);
@@ -2753,9 +2758,7 @@ static void handle_our_unilateral(const struct tx_parts *tx,
* delay */ * delay */
static void steal_to_them_output(struct tracked_output *out, u32 csv) static void steal_to_them_output(struct tracked_output *out, u32 csv)
{ {
u8 *wscript; const u8 *wscript, *msg;
struct bitcoin_tx *tx;
enum tx_type tx_type = OUR_PENALTY_TX;
/* BOLT #3: /* BOLT #3:
* *
@@ -2768,16 +2771,19 @@ static void steal_to_them_output(struct tracked_output *out, u32 csv)
&keyset->self_revocation_key, &keyset->self_revocation_key,
&keyset->self_delayed_payment_key); &keyset->self_delayed_payment_key);
tx = tx_to_us(tmpctx, penalty_to_us, out, BITCOIN_TX_RBF_SEQUENCE, 0, msg = towire_onchaind_spend_penalty(NULL,
&ONE, sizeof(ONE), wscript, &tx_type, penalty_feerate); &out->outpoint, out->sat,
remote_per_commitment_secret,
tal_dup(tmpctx, u8, &ONE),
wscript);
propose_resolution(out, tx, 0, tx_type); /* Spend this immediately. */
propose_immediate_resolution(out, take(msg), OUR_PENALTY_TX);
} }
static void steal_htlc(struct tracked_output *out) static void steal_htlc(struct tracked_output *out)
{ {
struct bitcoin_tx *tx; const u8 *msg;
enum tx_type tx_type = OUR_PENALTY_TX;
u8 der[PUBKEY_CMPR_LEN]; u8 der[PUBKEY_CMPR_LEN];
/* BOLT #3: /* BOLT #3:
@@ -2788,11 +2794,15 @@ static void steal_htlc(struct tracked_output *out)
* <revocation_sig> <revocationpubkey> * <revocation_sig> <revocationpubkey>
*/ */
pubkey_to_der(der, &keyset->self_revocation_key); pubkey_to_der(der, &keyset->self_revocation_key);
tx = tx_to_us(out, penalty_to_us, out, BITCOIN_TX_RBF_SEQUENCE, 0,
der, sizeof(der), out->wscript, &tx_type,
penalty_feerate);
propose_resolution(out, tx, 0, tx_type); msg = towire_onchaind_spend_penalty(NULL,
&out->outpoint, out->sat,
remote_per_commitment_secret,
tal_dup_arr(tmpctx, u8, der, ARRAY_SIZE(der), 0),
out->wscript);
/* Spend this immediately. */
propose_immediate_resolution(out, take(msg), OUR_PENALTY_TX);
} }
/* Tell wallet that we have discovered a UTXO from a to-remote output, /* Tell wallet that we have discovered a UTXO from a to-remote output,

View File

@@ -149,6 +149,16 @@ msgdata,onchaind_spend_to_us,commit_num,u64,
msgdata,onchaind_spend_to_us,wscript_len,u32, msgdata,onchaind_spend_to_us,wscript_len,u32,
msgdata,onchaind_spend_to_us,wscript,u8,wscript_len msgdata,onchaind_spend_to_us,wscript,u8,wscript_len
# We tell lightningd to create, sign and broadcast this penalty tx:
msgtype,onchaind_spend_penalty,5041
msgdata,onchaind_spend_penalty,outpoint,bitcoin_outpoint,
msgdata,onchaind_spend_penalty,outpoint_amount,amount_sat,
msgdata,onchaind_spend_penalty,remote_per_commitment_secret,secret,
msgdata,onchaind_spend_penalty,stack_elem_len,u16,
msgdata,onchaind_spend_penalty,stack_elem,u8,stack_elem_len
msgdata,onchaind_spend_penalty,wscript_len,u32,
msgdata,onchaind_spend_penalty,wscript,u8,wscript_len
subtype,onchain_witness_element subtype,onchain_witness_element
subtypedata,onchain_witness_element,is_signature,bool, subtypedata,onchain_witness_element,is_signature,bool,
subtypedata,onchain_witness_element,len,u32, subtypedata,onchain_witness_element,len,u32,
1 #include <bitcoin/tx_parts.h>
149 msgdata,onchaind_spend_created,num_witnesses,u32,
150 msgdata,onchaind_spend_created,witness,onchain_witness_element,num_witnesses
151
152
153
154
155
156
157
158
159
160
161
162
163
164

View File

@@ -243,9 +243,6 @@ void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
/* Generated stub for towire_hsmd_get_per_commitment_point */ /* Generated stub for towire_hsmd_get_per_commitment_point */
u8 *towire_hsmd_get_per_commitment_point(const tal_t *ctx UNNEEDED, u64 n UNNEEDED) 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(); } { fprintf(stderr, "towire_hsmd_get_per_commitment_point called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_delayed_payment_to_us */
u8 *towire_hsmd_sign_delayed_payment_to_us(const tal_t *ctx UNNEEDED, u64 commit_num UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_delayed_payment_to_us called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_penalty_to_us */ /* Generated stub for towire_hsmd_sign_penalty_to_us */
u8 *towire_hsmd_sign_penalty_to_us(const tal_t *ctx UNNEEDED, const struct secret *revocation_secret UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED) u8 *towire_hsmd_sign_penalty_to_us(const tal_t *ctx UNNEEDED, const struct secret *revocation_secret UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_penalty_to_us called!\n"); abort(); } { fprintf(stderr, "towire_hsmd_sign_penalty_to_us called!\n"); abort(); }
@@ -285,6 +282,9 @@ u8 *towire_onchaind_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct
/* Generated stub for towire_onchaind_notify_coin_mvt */ /* 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) 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(); } { fprintf(stderr, "towire_onchaind_notify_coin_mvt called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_penalty */
u8 *towire_onchaind_spend_penalty(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, const struct secret *remote_per_commitment_secret UNNEEDED, const u8 *stack_elem UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_penalty called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_to_us */ /* Generated stub for towire_onchaind_spend_to_us */
u8 *towire_onchaind_spend_to_us(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u32 minblock UNNEEDED, u64 commit_num UNNEEDED, const u8 *wscript UNNEEDED) u8 *towire_onchaind_spend_to_us(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u32 minblock UNNEEDED, u64 commit_num UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_to_us called!\n"); abort(); } { fprintf(stderr, "towire_onchaind_spend_to_us called!\n"); abort(); }

View File

@@ -272,9 +272,6 @@ void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
/* Generated stub for towire_hsmd_get_per_commitment_point */ /* Generated stub for towire_hsmd_get_per_commitment_point */
u8 *towire_hsmd_get_per_commitment_point(const tal_t *ctx UNNEEDED, u64 n UNNEEDED) 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(); } { fprintf(stderr, "towire_hsmd_get_per_commitment_point called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_delayed_payment_to_us */
u8 *towire_hsmd_sign_delayed_payment_to_us(const tal_t *ctx UNNEEDED, u64 commit_num UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_delayed_payment_to_us called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_local_htlc_tx */ /* Generated stub for towire_hsmd_sign_local_htlc_tx */
u8 *towire_hsmd_sign_local_htlc_tx(const tal_t *ctx UNNEEDED, u64 commit_num UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED, bool option_anchor_outputs UNNEEDED) u8 *towire_hsmd_sign_local_htlc_tx(const tal_t *ctx UNNEEDED, u64 commit_num UNNEEDED, const struct bitcoin_tx *tx UNNEEDED, const u8 *wscript UNNEEDED, bool option_anchor_outputs UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_local_htlc_tx called!\n"); abort(); } { fprintf(stderr, "towire_hsmd_sign_local_htlc_tx called!\n"); abort(); }
@@ -317,6 +314,9 @@ u8 *towire_onchaind_missing_htlc_output(const tal_t *ctx UNNEEDED, const struct
/* Generated stub for towire_onchaind_notify_coin_mvt */ /* 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) 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(); } { fprintf(stderr, "towire_onchaind_notify_coin_mvt called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_penalty */
u8 *towire_onchaind_spend_penalty(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, const struct secret *remote_per_commitment_secret UNNEEDED, const u8 *stack_elem UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_penalty called!\n"); abort(); }
/* Generated stub for towire_onchaind_spend_to_us */ /* Generated stub for towire_onchaind_spend_to_us */
u8 *towire_onchaind_spend_to_us(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u32 minblock UNNEEDED, u64 commit_num UNNEEDED, const u8 *wscript UNNEEDED) u8 *towire_onchaind_spend_to_us(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, struct amount_sat outpoint_amount UNNEEDED, u32 minblock UNNEEDED, u64 commit_num UNNEEDED, const u8 *wscript UNNEEDED)
{ fprintf(stderr, "towire_onchaind_spend_to_us called!\n"); abort(); } { fprintf(stderr, "towire_onchaind_spend_to_us called!\n"); abort(); }

View File

@@ -582,22 +582,22 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams):
# l2 should spend all of the outputs (except to-us). # l2 should spend all of the outputs (except to-us).
# Could happen in any order, depending on commitment tx. # Could happen in any order, depending on commitment tx.
needle = l2.daemon.logsearch_start ((_, txid1, blocks1), (_, txid2, blocks2)) = \
l2.wait_for_onchaind_broadcast('OUR_PENALTY_TX', l2.wait_for_onchaind_tx('OUR_PENALTY_TX',
'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM') 'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM',
l2.daemon.logsearch_start = needle 'OUR_PENALTY_TX',
l2.wait_for_onchaind_broadcast('OUR_PENALTY_TX',
'THEIR_REVOKED_UNILATERAL/THEIR_HTLC') 'THEIR_REVOKED_UNILATERAL/THEIR_HTLC')
assert blocks1 == 0
assert blocks2 == 0
# FIXME: test HTLC tx race! # FIXME: test HTLC tx race!
bitcoind.generate_block(100) bitcoind.generate_block(100, wait_for_mempool=[txid1, txid2])
sync_blockheight(bitcoind, [l1, l2]) sync_blockheight(bitcoind, [l1, l2])
wait_for(lambda: l2.rpc.listpeerchannels()['channels'] == []) wait_for(lambda: l2.rpc.listpeerchannels()['channels'] == [])
# Do one last pass over the logs to extract the reactions l2 sent # Do one last pass over the logs to extract the reactions l2 sent
l2.daemon.logsearch_start = needle
needles = [ needles = [
# The first needle will match, but since we don't have a direct output # The first needle will match, but since we don't have a direct output
# for l2 it won't result in an output, hence the comment: # for l2 it won't result in an output, hence the comment:
@@ -708,11 +708,13 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams):
# l2 should spend all of the outputs (except to-us). # l2 should spend all of the outputs (except to-us).
# Could happen in any order, depending on commitment tx. # Could happen in any order, depending on commitment tx.
needle = l2.daemon.logsearch_start needle = l2.daemon.logsearch_start
l2.wait_for_onchaind_broadcast('OUR_PENALTY_TX', ((_, txid1, blocks1), (_, txid2, blocks2)) = \
'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM') l2.wait_for_onchaind_tx('OUR_PENALTY_TX',
l2.daemon.logsearch_start = needle 'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM',
l2.wait_for_onchaind_broadcast('OUR_PENALTY_TX', 'OUR_PENALTY_TX',
'THEIR_REVOKED_UNILATERAL/OUR_HTLC') 'THEIR_REVOKED_UNILATERAL/OUR_HTLC')
assert blocks1 == 0
assert blocks2 == 0
l2.daemon.logsearch_start = needle l2.daemon.logsearch_start = needle
l2.daemon.wait_for_log('Ignoring output.*: THEIR_REVOKED_UNILATERAL/OUTPUT_TO_US') l2.daemon.wait_for_log('Ignoring output.*: THEIR_REVOKED_UNILATERAL/OUTPUT_TO_US')
@@ -720,7 +722,7 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams):
# FIXME: test HTLC tx race! # FIXME: test HTLC tx race!
# 100 blocks later, all resolved. # 100 blocks later, all resolved.
bitcoind.generate_block(100) bitcoind.generate_block(100, wait_for_mempool=[txid1, txid2])
sync_blockheight(bitcoind, [l1, l2]) sync_blockheight(bitcoind, [l1, l2])
peer = only_one(l2.rpc.listpeers()["peers"]) peer = only_one(l2.rpc.listpeers()["peers"])
@@ -1316,15 +1318,19 @@ def test_penalty_htlc_tx_fulfill(node_factory, bitcoind, chainparams):
# notes that they've successfully claimed to_local and the fulfilled htlc) # notes that they've successfully claimed to_local and the fulfilled htlc)
l3.start() l3.start()
sync_blockheight(bitcoind, [l3]) sync_blockheight(bitcoind, [l3])
l3.daemon.wait_for_logs(['Propose handling THEIR_REVOKED_UNILATERAL/OUR_HTLC by OUR_PENALTY_TX',
'Propose handling THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM ' txids = []
'by OUR_PENALTY_TX', for (_, txid, blocks) in l3.wait_for_onchaind_tx('OUR_PENALTY_TX',
'Resolved THEIR_REVOKED_UNILATERAL/OUR_HTLC by OUR_HTLC_FULFILL_TO_THEM', 'THEIR_REVOKED_UNILATERAL/OUR_HTLC',
'Propose handling OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM' 'OUR_PENALTY_TX',
' by OUR_PENALTY_TX']) 'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM',
l3.wait_for_onchaind_broadcast('OUR_PENALTY_TX', 'OUR_PENALTY_TX',
'OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM') 'OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM'):
bitcoind.generate_block(1) assert blocks == 0
txids.append(txid)
# First one is already spent by their fulfill attempt
bitcoind.generate_block(1, wait_for_mempool=txids[1:])
l3.daemon.wait_for_log('Resolved OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM ' l3.daemon.wait_for_log('Resolved OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM '
'by our proposal OUR_PENALTY_TX') 'by our proposal OUR_PENALTY_TX')
l2.daemon.wait_for_log('Unknown spend of OUR_HTLC_SUCCESS_TX/DELAYED_OUTPUT_TO_US') l2.daemon.wait_for_log('Unknown spend of OUR_HTLC_SUCCESS_TX/DELAYED_OUTPUT_TO_US')
@@ -1518,31 +1524,34 @@ def test_penalty_htlc_tx_timeout(node_factory, bitcoind, chainparams):
# notes that they've successfully claimed to_local and the fulfilled htlc) # notes that they've successfully claimed to_local and the fulfilled htlc)
l3.start() l3.start()
sync_blockheight(bitcoind, [l3]) sync_blockheight(bitcoind, [l3])
l3.daemon.wait_for_logs(['Propose handling THEIR_REVOKED_UNILATERAL/OUR_HTLC by OUR_PENALTY_TX',
'Propose handling THEIR_REVOKED_UNILATERAL/THEIR_HTLC by OUR_PENALTY_TX', txids = []
'Propose handling THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM ' for (_, txid, blocks) in l3.wait_for_onchaind_tx('OUR_PENALTY_TX',
'by OUR_PENALTY_TX', 'THEIR_REVOKED_UNILATERAL/OUR_HTLC',
'OUR_PENALTY_TX',
'THEIR_REVOKED_UNILATERAL/THEIR_HTLC',
'OUR_PENALTY_TX',
'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM',
'OUR_PENALTY_TX',
'OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM',
'OUR_PENALTY_TX',
'THEIR_HTLC_TIMEOUT_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM'):
assert blocks == 0
txids.append(txid)
# Unfortunately, only the last one succeeds, since they already took the rest!
bitcoind.generate_block(1, wait_for_mempool=txids[-1])
# And they resolve (intermingled with the above in some cases)
l3.daemon.logsearch_start = 0
l3.daemon.wait_for_logs(['Resolved THEIR_HTLC_TIMEOUT_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM '
'by our proposal OUR_PENALTY_TX',
'Resolved THEIR_REVOKED_UNILATERAL/OUR_HTLC by OUR_HTLC_FULFILL_TO_THEM', 'Resolved THEIR_REVOKED_UNILATERAL/OUR_HTLC by OUR_HTLC_FULFILL_TO_THEM',
'Propose handling OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM'
' by OUR_PENALTY_TX',
'Resolved OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM ' 'Resolved OUR_HTLC_FULFILL_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM '
'by THEIR_DELAYED_CHEAT', 'by THEIR_DELAYED_CHEAT',
'Resolved THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM ' 'Resolved THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM '
'by THEIR_DELAYED_CHEAT', 'by THEIR_DELAYED_CHEAT',
'Resolved THEIR_REVOKED_UNILATERAL/THEIR_HTLC by THEIR_HTLC_TIMEOUT_TO_THEM', 'Resolved THEIR_REVOKED_UNILATERAL/THEIR_HTLC by THEIR_HTLC_TIMEOUT_TO_THEM'])
'Propose handling THEIR_HTLC_TIMEOUT_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM by OUR_PENALTY_TX'])
# Make sure we've broadcast the tx we expect (other channels shutting down can create
# unrelated txs!)
# In theory this could have occurred before all the previous loglines appeared.
l3.daemon.logsearch_start = 0
line = l3.daemon.wait_for_log(r'Broadcasting OUR_PENALTY_TX \([0-9a-f]*\) to resolve THEIR_HTLC_TIMEOUT_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM')
tx = re.search(r'\(([0-9a-f]*)\)', line).group(1)
txid = bitcoind.rpc.decoderawtransaction(tx)['txid']
bitcoind.generate_block(1, wait_for_mempool=[txid])
l3.daemon.wait_for_log('Resolved THEIR_HTLC_TIMEOUT_TO_THEM/DELAYED_CHEAT_OUTPUT_TO_THEM '
'by our proposal OUR_PENALTY_TX')
l2.daemon.wait_for_log('Unknown spend of OUR_HTLC_TIMEOUT_TX/DELAYED_OUTPUT_TO_US') l2.daemon.wait_for_log('Unknown spend of OUR_HTLC_TIMEOUT_TX/DELAYED_OUTPUT_TO_US')
# 100 blocks later, l3+l2 are both done # 100 blocks later, l3+l2 are both done

View File

@@ -3782,9 +3782,11 @@ def test_upgrade_statickey_onchaind(node_factory, executor, bitcoind):
bitcoind.rpc.sendrawtransaction(tx) bitcoind.rpc.sendrawtransaction(tx)
bitcoind.generate_block(1) bitcoind.generate_block(1)
l2.wait_for_onchaind_broadcast('OUR_PENALTY_TX', ((_, txid, blocks),) = l2.wait_for_onchaind_tx('OUR_PENALTY_TX',
'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM') 'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM')
bitcoind.generate_block(100) assert blocks == 0
bitcoind.generate_block(100, wait_for_mempool=txid)
# This works even if they disconnect and listpeerchannels() is empty: # This works even if they disconnect and listpeerchannels() is empty:
wait_for(lambda: l2.rpc.listpeerchannels()['channels'] == []) wait_for(lambda: l2.rpc.listpeerchannels()['channels'] == [])
@@ -3807,9 +3809,11 @@ def test_upgrade_statickey_onchaind(node_factory, executor, bitcoind):
bitcoind.rpc.sendrawtransaction(tx) bitcoind.rpc.sendrawtransaction(tx)
bitcoind.generate_block(1) bitcoind.generate_block(1)
l2.wait_for_onchaind_broadcast('OUR_PENALTY_TX', ((_, txid, blocks),) = l2.wait_for_onchaind_tx('OUR_PENALTY_TX',
'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM') 'THEIR_REVOKED_UNILATERAL/DELAYED_CHEAT_OUTPUT_TO_THEM')
bitcoind.generate_block(100) assert blocks == 0
bitcoind.generate_block(100, wait_for_mempool=txid)
# This works even if they disconnect and listpeers() is empty: # This works even if they disconnect and listpeers() is empty:
wait_for(lambda: len(l2.rpc.listpeerchannels()['channels']) == 0) wait_for(lambda: len(l2.rpc.listpeerchannels()['channels']) == 0)