onchaind: propose_ignore specifically to ignore if output reaches depth.

We do this for HTLCs which will timeout to them: we watch them in case we
want to fulfill them as a preimage comes in, but once they reach depth we
can forget about them.

We change the message, which causes some more test churn.

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 c5b7dbcd98
commit 9496e9fbef
2 changed files with 51 additions and 47 deletions

View File

@ -727,42 +727,17 @@ static void proposal_meets_depth(struct tracked_output *out)
/* Otherwise we will get a callback when it's in a block. */
}
static void propose_resolution(struct tracked_output *out,
const struct bitcoin_tx *tx STEALS,
unsigned int depth_required,
enum tx_type tx_type)
static struct proposed_resolution *new_proposed_resolution(struct tracked_output *out,
unsigned int block_required,
enum tx_type tx_type)
{
status_debug("Propose handling %s/%s by %s (%s) after %u blocks",
tx_type_name(out->tx_type),
output_type_name(out->output_type),
tx_type_name(tx_type),
tx ? type_to_string(tmpctx, struct bitcoin_tx, tx):"IGNORING",
depth_required);
struct proposed_resolution *proposal = tal(out, struct proposed_resolution);
proposal->via_lightningd = true;
proposal->tx = NULL;
proposal->tx_type = tx_type;
proposal->depth_required = block_required - out->tx_blockheight;
out->proposal = tal(out, struct proposed_resolution);
out->proposal->tx = tal_steal(out->proposal, tx);
out->proposal->via_lightningd = false;
out->proposal->welements = NULL;
out->proposal->depth_required = depth_required;
out->proposal->tx_type = tx_type;
if (depth_required == 0)
proposal_meets_depth(out);
}
static void propose_resolution_at_block(struct tracked_output *out,
const struct bitcoin_tx *tx STEALS,
unsigned int block_required,
enum tx_type tx_type)
{
u32 depth;
/* Expiry could be in the past! */
if (block_required < out->tx_blockheight)
depth = 0;
else /* Note that out->tx_blockheight is already at depth 1 */
depth = block_required - out->tx_blockheight + 1;
propose_resolution(out, tx, depth, tx_type);
return proposal;
}
/* Modern style: we don't create tx outselves, but tell lightningd. */
@ -780,12 +755,7 @@ static void propose_resolution_to_master(struct tracked_output *out,
output_type_name(out->output_type),
block_required - 1, block_required - 1 - out->tx_blockheight);
out->proposal = tal(out, struct proposed_resolution);
out->proposal->via_lightningd = true;
out->proposal->tx = NULL;
out->proposal->welements = NULL;
out->proposal->tx_type = tx_type;
out->proposal->depth_required = block_required - out->tx_blockheight;
out->proposal = new_proposed_resolution(out, block_required, tx_type);
wire_sync_write(REQ_FD, send_message);
@ -806,6 +776,31 @@ static void propose_immediate_resolution(struct tracked_output *out,
tx_type);
}
/* If UTXO reaches this block, ignore it (it's not for us, it's ok!) */
static void propose_ignore(struct tracked_output *out,
unsigned int block_required,
enum tx_type tx_type)
{
status_debug("Propose ignoring %s/%s as %s"
" after block %u (%i more blocks)",
tx_type_name(out->tx_type),
output_type_name(out->output_type),
tx_type_name(tx_type),
block_required,
block_required - out->tx_blockheight);
/* If it's already passed, don't underflow. */
if (block_required < out->tx_blockheight)
block_required = out->tx_blockheight;
out->proposal = new_proposed_resolution(out, block_required, tx_type);
out->proposal->welements = NULL;
/* Can we immediately ignore? */
if (out->proposal->depth_required == 0)
ignore_output(out);
}
static bool is_valid_sig(const u8 *e)
{
struct bitcoin_signature sig;
@ -1580,10 +1575,19 @@ static void tx_new_depth(struct tracked_output **outs,
/* Otherwise, is this something we have a pending
* resolution for? */
if (outs[i]->proposal
&& !outs[i]->proposal->via_lightningd
&& bitcoin_txid_eq(&outs[i]->outpoint.txid, txid)
&& depth >= outs[i]->proposal->depth_required) {
proposal_meets_depth(outs[i]);
if (outs[i]->proposal->via_lightningd) {
if (!outs[i]->proposal->welements) {
ignore_output(outs[i]);
if (outs[i]->proposal->tx_type == THEIR_HTLC_TIMEOUT_TO_THEM)
record_external_deposit(outs[i], outs[i]->tx_blockheight,
HTLC_TIMEOUT);
}
} else {
proposal_meets_depth(outs[i]);
}
}
}
}
@ -2172,8 +2176,8 @@ static size_t resolve_their_htlc(struct tracked_output *out,
}
/* If we hit timeout depth, resolve by ignoring. */
propose_resolution_at_block(out, NULL, htlcs[which_htlc].cltv_expiry,
THEIR_HTLC_TIMEOUT_TO_THEM);
propose_ignore(out, htlcs[which_htlc].cltv_expiry,
THEIR_HTLC_TIMEOUT_TO_THEM);
return which_htlc;
}

View File

@ -2826,7 +2826,7 @@ def test_permfail_new_commit(node_factory, bitcoind, executor):
l1.daemon.wait_for_log('Their unilateral tx, new commit point')
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')
l2.daemon.wait_for_log(r'Propose ignoring OUR_UNILATERAL/THEIR_HTLC as THEIR_HTLC_TIMEOUT_TO_THEM after block [0-9]* \(5 more blocks\)')
_, txid, blocks = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
@ -3107,7 +3107,7 @@ def test_permfail_htlc_in(node_factory, bitcoind, executor):
l1.daemon.wait_for_log('Their unilateral tx, old commit point')
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')
l2.daemon.wait_for_log(r'Propose ignoring OUR_UNILATERAL/THEIR_HTLC as THEIR_HTLC_TIMEOUT_TO_THEM after block [0-9]* \(5 more blocks\)')
_, _, blocks = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5
@ -3166,7 +3166,7 @@ def test_permfail_htlc_out(node_factory, bitcoind, executor):
assert blocks1 == 5
assert blocks2 == 4
l1.daemon.wait_for_log('Propose handling THEIR_UNILATERAL/THEIR_HTLC by THEIR_HTLC_TIMEOUT_TO_THEM \\(IGNORING\\) after 6 blocks')
l1.daemon.wait_for_log(r'Propose ignoring THEIR_UNILATERAL/THEIR_HTLC as THEIR_HTLC_TIMEOUT_TO_THEM after block [0-9]* \(5 more blocks\)')
# l1 then gets preimage, uses it instead of ignoring
_, txid1, blocks = l1.wait_for_onchaind_tx('THEIR_HTLC_FULFILL_TO_US',
'THEIR_UNILATERAL/THEIR_HTLC')