From aee7ebbeeffc8d91af07d0c1153d99334763c7bf Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 14 Aug 2025 10:57:52 +0930 Subject: [PATCH] onchaind: don't consider our anchors to be payments into the wallet. This makes our final balance not match our wallet: 1. We only spend the anchor when we need to boost the commitment tx, which we don't always do (sometimes the peer does, sometimes it's not worth it). 2. We don't put the UTXO in our wallet, because we don't consider it "ours": anyone can spend it after 16 blocks. We used to use the tag "ignored" for this, but that's overly complex IMHO. Signed-off-by: Rusty Russell --- onchaind/onchaind.c | 22 +++++++++++----------- tests/test_closing.py | 34 +++++++++++++++++----------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index 3ded3c1be..5dcb1d266 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -331,15 +331,15 @@ static void record_to_them_htlc_fulfilled(struct tracked_output *out, &out->payment_hash))); } -static void record_anchor(struct tracked_output *out) +static void record_our_anchor(struct tracked_output *out) { - enum mvt_tag *tags = new_tag_arr(NULL, ANCHOR); - tal_arr_expand(&tags, IGNORED); - send_coin_mvt(take(new_coin_wallet_deposit_tagged(NULL, - &out->outpoint, - out->tx_blockheight, - out->sat, - tags))); + /* We *could* treat this as a deposit to our wallet, but we + * never record spending it, and in many cases we don't: we + * might not need it, or our peer may use the other anchor, and + * it can be spent by anyone after 16 blocks. Our + * implementation doesn't ever spend it unless it needs to + * boost, so it's fair to record it as going "external". */ + record_external_deposit(out, out->tx_blockheight, ANCHOR); } static void record_coin_movements(struct tracked_output *out, @@ -2325,7 +2325,7 @@ static void handle_our_unilateral(const struct tx_parts *tx, ANCHOR_TO_US, NULL, NULL, NULL); ignore_output(out); - record_anchor(out); + record_our_anchor(out); anchor[LOCAL] = NULL; continue; } @@ -2809,7 +2809,7 @@ static void handle_their_cheat(const struct tx_parts *tx, ANCHOR_TO_US, NULL, NULL, NULL); ignore_output(out); - record_anchor(out); + record_our_anchor(out); anchor[LOCAL] = NULL; continue; } @@ -3135,7 +3135,7 @@ static void handle_their_unilateral(const struct tx_parts *tx, NULL, NULL, NULL); ignore_output(out); - record_anchor(out); + record_our_anchor(out); anchor[LOCAL] = NULL; continue; } diff --git a/tests/test_closing.py b/tests/test_closing.py index 426afaa01..c6afa1f31 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -630,10 +630,10 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams, anchors): } if anchors: + expected_1['B'].append(('external', ['anchor'], None, None)) 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)) + expected_2['B'].append(('external', ['anchor'], None, None)) # We use a subset of tags in expected_2 that are used in expected_1 tags = check_utxos_channel(l1, [channel_id], expected_1) @@ -766,10 +766,10 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams, anchors) } if anchors: + expected_1['B'].append(('external', ['anchor'], None, None)) 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)) + expected_2['B'].append(('external', ['anchor'], None, None)) # We use a subset of tags in expected_2 that are used in expected_1 tags = check_utxos_channel(l1, [channel_id], expected_1) @@ -1353,10 +1353,10 @@ def test_penalty_htlc_tx_fulfill(node_factory, bitcoind, chainparams, anchors): } if anchors: + expected_2['B'].append(('external', ['anchor'], None, None)) expected_2['B'].append(('external', ['anchor'], None, None)) expected_3['B'].append(('external', ['anchor'], None, None)) - expected_2['B'].append(('wallet', ['anchor', 'ignored'], None, None)) - expected_3['B'].append(('wallet', ['anchor', 'ignored'], None, None)) + expected_3['B'].append(('external', ['anchor'], None, None)) # We RBF spend the HTLC tx, which creates a new deposit expected_2['C'].append(('wallet', ['deposit'], None, None)) @@ -1577,10 +1577,10 @@ def test_penalty_htlc_tx_timeout(node_factory, bitcoind, chainparams, anchors): } if anchors: + expected_2['B'].append(('external', ['anchor'], None, None)) expected_2['B'].append(('external', ['anchor'], None, None)) expected_3['B'].append(('external', ['anchor'], None, None)) - expected_2['B'].append(('wallet', ['anchor', 'ignored'], None, None)) - expected_3['B'].append(('wallet', ['anchor', 'ignored'], None, None)) + expected_3['B'].append(('external', ['anchor'], None, None)) # FIXME: Why does this fail? if not anchors: @@ -1720,7 +1720,7 @@ def test_penalty_rbf_normal(node_factory, bitcoind, executor, chainparams, ancho if anchors: expected_2['B'].append(('external', ['anchor'], None, None)) - expected_2['B'].append(('wallet', ['anchor', 'ignored'], None, None)) + expected_2['B'].append(('external', ['anchor'], None, None)) check_utxos_channel(l2, [channel_id], expected_2) @@ -2068,10 +2068,10 @@ def test_onchain_timeout(node_factory, bitcoind, executor, chainparams, anchors) } if anchors: + expected_1['B'].append(('external', ['anchor'], None, None)) 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)) + expected_2['B'].append(('external', ['anchor'], None, None)) # FIXME: Why does this fail? if not anchors: @@ -2202,10 +2202,10 @@ def test_onchain_middleman_simple(node_factory, bitcoind, chainparams, anchors): } if anchors: + expected_1['B'].append(('external', ['anchor'], None, None)) 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)) + expected_2['B'].append(('external', ['anchor'], None, None)) # FIXME: Why does this fail? if not anchors: @@ -2332,10 +2332,10 @@ def test_onchain_middleman_their_unilateral_in(node_factory, bitcoind, chainpara } if anchors: + expected_1['B'].append(('external', ['anchor'], None, None)) 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)) + expected_2['B'].append(('external', ['anchor'], None, None)) chan2_id = first_channel_id(l2, l3) # FIXME: Why does this fail? @@ -2424,7 +2424,7 @@ def test_onchain_their_unilateral_out(node_factory, bitcoind, chainparams, ancho # Funding tx 'A': [('wallet', ['deposit'], None, None), ('cid1', ['channel_open', 'opener'], ['channel_close'], 'B')], # Commitment tx - 'B': [('wallet', ['deposit'], None, None), ('cid1', ['htlc_timeout'], ['to_wallet'], 'C'), ('external', ['anchor'], None, None), ('wallet', ['anchor', 'ignored'], None, None)], + 'B': [('wallet', ['deposit'], None, None), ('cid1', ['htlc_timeout'], ['to_wallet'], 'C'), ('external', ['anchor'], None, None), ('external', ['anchor'], None, None)], # HTLC timeout tx 'C': [('wallet', ['deposit'], None, None)], } @@ -2433,7 +2433,7 @@ def test_onchain_their_unilateral_out(node_factory, bitcoind, chainparams, ancho # Funding tx 'A': [('cid1', ['channel_open'], ['channel_close'], 'B')], # Commitment tx - 'B': [('external', ['to_them'], None, None), ('external', ['htlc_timeout'], None, None), ('external', ['anchor'], None, None), ('wallet', ['anchor', 'ignored'], None, None)], + 'B': [('external', ['to_them'], None, None), ('external', ['htlc_timeout'], None, None), ('external', ['anchor'], None, None), ('external', ['anchor'], None, None)], } else: expected_1 = {