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. */ /* Otherwise we will get a callback when it's in a block. */
} }
static void propose_resolution(struct tracked_output *out, static struct proposed_resolution *new_proposed_resolution(struct tracked_output *out,
const struct bitcoin_tx *tx STEALS,
unsigned int depth_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);
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, unsigned int block_required,
enum tx_type tx_type) enum tx_type tx_type)
{ {
u32 depth; 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;
/* Expiry could be in the past! */ return proposal;
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);
} }
/* Modern style: we don't create tx outselves, but tell lightningd. */ /* 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), output_type_name(out->output_type),
block_required - 1, block_required - 1 - out->tx_blockheight); block_required - 1, block_required - 1 - out->tx_blockheight);
out->proposal = tal(out, struct proposed_resolution); out->proposal = new_proposed_resolution(out, block_required, tx_type);
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;
wire_sync_write(REQ_FD, send_message); wire_sync_write(REQ_FD, send_message);
@@ -806,6 +776,31 @@ static void propose_immediate_resolution(struct tracked_output *out,
tx_type); 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) static bool is_valid_sig(const u8 *e)
{ {
struct bitcoin_signature sig; struct bitcoin_signature sig;
@@ -1580,12 +1575,21 @@ static void tx_new_depth(struct tracked_output **outs,
/* Otherwise, is this something we have a pending /* Otherwise, is this something we have a pending
* resolution for? */ * resolution for? */
if (outs[i]->proposal if (outs[i]->proposal
&& !outs[i]->proposal->via_lightningd
&& bitcoin_txid_eq(&outs[i]->outpoint.txid, txid) && bitcoin_txid_eq(&outs[i]->outpoint.txid, txid)
&& depth >= outs[i]->proposal->depth_required) { && depth >= outs[i]->proposal->depth_required) {
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]); proposal_meets_depth(outs[i]);
} }
} }
}
} }
/* BOLT #5: /* BOLT #5:
@@ -2172,7 +2176,7 @@ static size_t resolve_their_htlc(struct tracked_output *out,
} }
/* If we hit timeout depth, resolve by ignoring. */ /* If we hit timeout depth, resolve by ignoring. */
propose_resolution_at_block(out, NULL, htlcs[which_htlc].cltv_expiry, propose_ignore(out, htlcs[which_htlc].cltv_expiry,
THEIR_HTLC_TIMEOUT_TO_THEM); THEIR_HTLC_TIMEOUT_TO_THEM);
return which_htlc; 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('Their unilateral tx, new commit point')
l1.daemon.wait_for_log(' to ONCHAIN') l1.daemon.wait_for_log(' to ONCHAIN')
l2.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', _, txid, blocks = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC') '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('Their unilateral tx, old commit point')
l1.daemon.wait_for_log(' to ONCHAIN') l1.daemon.wait_for_log(' to ONCHAIN')
l2.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', _, _, blocks = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC') 'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5 assert blocks == 5
@@ -3166,7 +3166,7 @@ def test_permfail_htlc_out(node_factory, bitcoind, executor):
assert blocks1 == 5 assert blocks1 == 5
assert blocks2 == 4 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 # l1 then gets preimage, uses it instead of ignoring
_, txid1, blocks = l1.wait_for_onchaind_tx('THEIR_HTLC_FULFILL_TO_US', _, txid1, blocks = l1.wait_for_onchaind_tx('THEIR_HTLC_FULFILL_TO_US',
'THEIR_UNILATERAL/THEIR_HTLC') 'THEIR_UNILATERAL/THEIR_HTLC')