Add anchors coverage to test_revoked_counterparty_htlc_tx_balances
[rust-lightning] / lightning / src / ln / monitor_tests.rs
index ce51fe4f955265aaeaaae8bc9b83b3b362249ebf..b83f40cee1a53aed904cccce9311f0ea3a005235 100644 (file)
@@ -644,8 +644,7 @@ fn test_claim_value_force_close() {
        do_test_claim_value_force_close(true, false);
 }
 
-#[test]
-fn test_balances_on_local_commitment_htlcs() {
+fn do_test_balances_on_local_commitment_htlcs(anchors: bool) {
        // Previously, when handling the broadcast of a local commitment transactions (with associated
        // CSV delays prior to spendability), we incorrectly handled the CSV delays on HTLC
        // transactions. This caused us to miss spendable outputs for HTLCs which were awaiting a CSV
@@ -657,9 +656,34 @@ fn test_balances_on_local_commitment_htlcs() {
        // claim by our counterparty).
        let chanmon_cfgs = create_chanmon_cfgs(2);
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
-       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let mut user_config = test_default_channel_config();
+       if anchors {
+               user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+               user_config.manually_accept_inbound_channels = true;
+       }
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(user_config), Some(user_config)]);
        let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
+       let coinbase_tx = Transaction {
+               version: 2,
+               lock_time: PackedLockTime::ZERO,
+               input: vec![TxIn { ..Default::default() }],
+               output: vec![
+                       TxOut {
+                               value: Amount::ONE_BTC.to_sat(),
+                               script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
+                       },
+                       TxOut {
+                               value: Amount::ONE_BTC.to_sat(),
+                               script_pubkey: nodes[1].wallet_source.get_change_script().unwrap(),
+                       },
+               ],
+       };
+       if anchors {
+               nodes[0].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value);
+               nodes[1].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 1 }, coinbase_tx.output[1].value);
+       }
+
        // Create a single channel with two pending HTLCs from nodes[0] to nodes[1], one which nodes[1]
        // knows the preimage for, one which it does not.
        let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
@@ -697,20 +721,26 @@ fn test_balances_on_local_commitment_htlcs() {
        let chan_feerate = get_feerate!(nodes[0], nodes[1], chan_id) as u64;
        let channel_type_features = get_channel_type_features!(nodes[0], nodes[1], chan_id);
 
-       // Get nodes[0]'s commitment transaction and HTLC-Timeout transactions
-       let as_txn = get_local_commitment_txn!(nodes[0], chan_id);
-       assert_eq!(as_txn.len(), 3);
-       check_spends!(as_txn[1], as_txn[0]);
-       check_spends!(as_txn[2], as_txn[0]);
-       check_spends!(as_txn[0], funding_tx);
-
        // First confirm the commitment transaction on nodes[0], which should leave us with three
        // claimable balances.
        let node_a_commitment_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32;
-       let commitment_tx_conf_height_a = block_from_scid(&mine_transaction(&nodes[0], &as_txn[0]));
+       nodes[0].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
        check_added_monitors!(nodes[0], 1);
        check_closed_broadcast!(nodes[0], true);
-       check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed, [nodes[1].node.get_our_node_id()], 1000000);
+       check_closed_event!(nodes[0], 1, ClosureReason::HolderForceClosed, [nodes[1].node.get_our_node_id()], 1000000);
+       let commitment_tx = {
+               let mut txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
+               assert_eq!(txn.len(), 1);
+               let commitment_tx = txn.pop().unwrap();
+               check_spends!(commitment_tx, funding_tx);
+               commitment_tx
+       };
+       let commitment_tx_conf_height_a = block_from_scid(&mine_transaction(&nodes[0], &commitment_tx));
+       if anchors && nodes[0].connect_style.borrow().updates_best_block_first() {
+               let mut txn = nodes[0].tx_broadcaster.txn_broadcast();
+               assert_eq!(txn.len(), 1);
+               assert_eq!(txn[0].txid(), commitment_tx.txid());
+       }
 
        let htlc_balance_known_preimage = Balance::MaybeTimeoutClaimableHTLC {
                amount_satoshis: 10_000,
@@ -723,43 +753,49 @@ fn test_balances_on_local_commitment_htlcs() {
                payment_hash: payment_hash_2,
        };
 
+       let commitment_tx_fee = chan_feerate *
+               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
+       let anchor_outputs_value = if anchors { 2 * channel::ANCHOR_OUTPUT_VALUE_SATOSHI } else { 0 };
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value,
                        confirmation_height: node_a_commitment_claimable,
                }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
        // Get nodes[1]'s HTLC claim tx for the second HTLC
-       mine_transaction(&nodes[1], &as_txn[0]);
+       mine_transaction(&nodes[1], &commitment_tx);
        check_added_monitors!(nodes[1], 1);
        check_closed_broadcast!(nodes[1], true);
        check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed, [nodes[0].node.get_our_node_id()], 1000000);
        let bs_htlc_claim_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
        assert_eq!(bs_htlc_claim_txn.len(), 1);
-       check_spends!(bs_htlc_claim_txn[0], as_txn[0]);
+       check_spends!(bs_htlc_claim_txn[0], commitment_tx);
 
        // Connect blocks until the HTLCs expire, allowing us to (validly) broadcast the HTLC-Timeout
        // transaction.
-       connect_blocks(&nodes[0], TEST_FINAL_CLTV - 1);
+       connect_blocks(&nodes[0], TEST_FINAL_CLTV);
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value,
                        confirmation_height: node_a_commitment_claimable,
                }, htlc_balance_known_preimage.clone(), htlc_balance_unknown_preimage.clone()]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
-       assert_eq!(as_txn[1].lock_time.0, nodes[0].best_block_info().1 + 1); // as_txn[1] can be included in the next block
+       if anchors {
+               handle_bump_htlc_event(&nodes[0], 2);
+       }
+       let timeout_htlc_txn = nodes[0].tx_broadcaster.unique_txn_broadcast();
+       assert_eq!(timeout_htlc_txn.len(), 2);
+       check_spends!(timeout_htlc_txn[0], commitment_tx, coinbase_tx);
+       check_spends!(timeout_htlc_txn[1], commitment_tx, coinbase_tx);
 
        // Now confirm nodes[0]'s HTLC-Timeout transaction, which changes the claimable balance to an
        // "awaiting confirmations" one.
        let node_a_htlc_claimable = nodes[0].best_block_info().1 + BREAKDOWN_TIMEOUT as u32;
-       mine_transaction(&nodes[0], &as_txn[1]);
+       mine_transaction(&nodes[0], &timeout_htlc_txn[0]);
        // Note that prior to the fix in the commit which introduced this test, this (and the next
        // balance) check failed. With this check removed, the code panicked in the `connect_blocks`
        // call, as described, two hunks down.
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value,
                        confirmation_height: node_a_commitment_claimable,
                }, Balance::ClaimableAwaitingConfirmations {
                        amount_satoshis: 10_000,
@@ -772,8 +808,7 @@ fn test_balances_on_local_commitment_htlcs() {
        mine_transaction(&nodes[0], &bs_htlc_claim_txn[0]);
        expect_payment_sent(&nodes[0], payment_preimage_2, None, true, false);
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value,
                        confirmation_height: node_a_commitment_claimable,
                }, Balance::ClaimableAwaitingConfirmations {
                        amount_satoshis: 10_000,
@@ -788,8 +823,7 @@ fn test_balances_on_local_commitment_htlcs() {
        expect_payment_failed!(nodes[0], payment_hash, false);
 
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       amount_satoshis: 1_000_000 - 10_000 - 20_000 - commitment_tx_fee - anchor_outputs_value,
                        confirmation_height: node_a_commitment_claimable,
                }, Balance::ClaimableAwaitingConfirmations {
                        amount_satoshis: 10_000,
@@ -801,16 +835,16 @@ fn test_balances_on_local_commitment_htlcs() {
        // `SpendableOutputs` event and removing the claimable balance entry.
        connect_blocks(&nodes[0], node_a_commitment_claimable - nodes[0].best_block_info().1 - 1);
        assert!(get_monitor!(nodes[0], chan_id)
-               .get_spendable_outputs(&as_txn[0], commitment_tx_conf_height_a).is_empty());
+               .get_spendable_outputs(&commitment_tx, commitment_tx_conf_height_a).is_empty());
        connect_blocks(&nodes[0], 1);
        assert_eq!(vec![Balance::ClaimableAwaitingConfirmations {
                        amount_satoshis: 10_000,
                        confirmation_height: node_a_htlc_claimable,
                }],
                nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
-       let to_self_spendable_output = test_spendable_output(&nodes[0], &as_txn[0], false);
+       let to_self_spendable_output = test_spendable_output(&nodes[0], &commitment_tx, false);
        assert_eq!(
-               get_monitor!(nodes[0], chan_id).get_spendable_outputs(&as_txn[0], commitment_tx_conf_height_a),
+               get_monitor!(nodes[0], chan_id).get_spendable_outputs(&commitment_tx, commitment_tx_conf_height_a),
                to_self_spendable_output
        );
 
@@ -829,6 +863,12 @@ fn test_balances_on_local_commitment_htlcs() {
        assert!(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances().is_empty());
 }
 
+#[test]
+fn test_balances_on_local_commitment_htlcs() {
+       do_test_balances_on_local_commitment_htlcs(false);
+       do_test_balances_on_local_commitment_htlcs(true);
+}
+
 #[test]
 fn test_no_preimage_inbound_htlc_balances() {
        // Tests that MaybePreimageClaimableHTLC are generated for inbound HTLCs for which we do not
@@ -1060,7 +1100,7 @@ fn sorted_vec_with_additions<T: Ord + Clone>(v_orig: &Vec<T>, extra_ts: &[&T]) -
        v
 }
 
-fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bool) {
+fn do_test_revoked_counterparty_commitment_balances(anchors: bool, confirm_htlc_spend_first: bool) {
        // Tests `get_claimable_balances` for revoked counterparty commitment transactions.
        let mut chanmon_cfgs = create_chanmon_cfgs(2);
        // We broadcast a second-to-latest commitment transaction, without providing the revocation
@@ -1069,7 +1109,12 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
        // transaction which, from the point of view of our keys_manager, is revoked.
        chanmon_cfgs[1].keys_manager.disable_revocation_policy_check = true;
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
-       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let mut user_config = test_default_channel_config();
+       if anchors {
+               user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+               user_config.manually_accept_inbound_channels = true;
+       }
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(user_config), Some(user_config)]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
        let (_, _, chan_id, funding_tx) =
@@ -1179,16 +1224,23 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
 
        // The following constants were determined experimentally
        const BS_TO_SELF_CLAIM_EXP_WEIGHT: usize = 483;
-       const OUTBOUND_HTLC_CLAIM_EXP_WEIGHT: usize = 571;
-       const INBOUND_HTLC_CLAIM_EXP_WEIGHT: usize = 578;
+       let outbound_htlc_claim_exp_weight: usize = if anchors { 574 } else { 571 };
+       let inbound_htlc_claim_exp_weight: usize = if anchors { 582 } else { 578 };
 
        // Check that the weight is close to the expected weight. Note that signature sizes vary
        // somewhat so it may not always be exact.
-       fuzzy_assert_eq(claim_txn[0].weight(), OUTBOUND_HTLC_CLAIM_EXP_WEIGHT);
-       fuzzy_assert_eq(claim_txn[1].weight(), INBOUND_HTLC_CLAIM_EXP_WEIGHT);
-       fuzzy_assert_eq(claim_txn[2].weight(), INBOUND_HTLC_CLAIM_EXP_WEIGHT);
+       fuzzy_assert_eq(claim_txn[0].weight(), outbound_htlc_claim_exp_weight);
+       fuzzy_assert_eq(claim_txn[1].weight(), inbound_htlc_claim_exp_weight);
+       fuzzy_assert_eq(claim_txn[2].weight(), inbound_htlc_claim_exp_weight);
        fuzzy_assert_eq(claim_txn[3].weight(), BS_TO_SELF_CLAIM_EXP_WEIGHT);
 
+       let commitment_tx_fee = chan_feerate *
+               (channel::commitment_tx_base_weight(&channel_type_features) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
+       let anchor_outputs_value = if anchors { channel::ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 };
+       let inbound_htlc_claim_fee = chan_feerate * inbound_htlc_claim_exp_weight as u64 / 1000;
+       let outbound_htlc_claim_fee = chan_feerate * outbound_htlc_claim_exp_weight as u64 / 1000;
+       let to_self_claim_fee = chan_feerate * claim_txn[3].weight() as u64 / 1000;
+
        // The expected balance for the next three checks, with the largest-HTLC and to_self output
        // claim balances separated out.
        let expected_balance = vec![Balance::ClaimableAwaitingConfirmations {
@@ -1202,8 +1254,7 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
                }];
 
        let to_self_unclaimed_balance = Balance::CounterpartyRevokedOutputClaimable {
-               amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate *
-                       (channel::commitment_tx_base_weight(&channel_type_features) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+               amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value,
        };
        let to_self_claimed_avail_height;
        let largest_htlc_unclaimed_balance = Balance::CounterpartyRevokedOutputClaimable {
@@ -1228,13 +1279,11 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
        }
 
        let largest_htlc_claimed_balance = Balance::ClaimableAwaitingConfirmations {
-               amount_satoshis: 5_000 - chan_feerate * INBOUND_HTLC_CLAIM_EXP_WEIGHT as u64 / 1000,
+               amount_satoshis: 5_000 - inbound_htlc_claim_fee,
                confirmation_height: largest_htlc_claimed_avail_height,
        };
        let to_self_claimed_balance = Balance::ClaimableAwaitingConfirmations {
-               amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate *
-                       (channel::commitment_tx_base_weight(&channel_type_features) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
-                       - chan_feerate * claim_txn[3].weight() as u64 / 1000,
+               amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - to_self_claim_fee,
                confirmation_height: to_self_claimed_avail_height,
        };
 
@@ -1264,18 +1313,16 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
                        amount_satoshis: 100_000 - 5_000 - 4_000 - 3,
                        confirmation_height: nodes[1].best_block_info().1 + 1,
                }, Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 1_000_000 - 100_000 - 3_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(&channel_type_features) + 3 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000
-                               - chan_feerate * claim_txn[3].weight() as u64 / 1000,
+                       amount_satoshis: 1_000_000 - 100_000 - 3_000 - commitment_tx_fee - anchor_outputs_value - to_self_claim_fee,
                        confirmation_height: to_self_claimed_avail_height,
                }, Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 3_000 - chan_feerate * OUTBOUND_HTLC_CLAIM_EXP_WEIGHT as u64 / 1000,
+                       amount_satoshis: 3_000 - outbound_htlc_claim_fee,
                        confirmation_height: nodes[1].best_block_info().1 + 4,
                }, Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 4_000 - chan_feerate * INBOUND_HTLC_CLAIM_EXP_WEIGHT as u64 / 1000,
+                       amount_satoshis: 4_000 - inbound_htlc_claim_fee,
                        confirmation_height: nodes[1].best_block_info().1 + 5,
                }, Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: 5_000 - chan_feerate * INBOUND_HTLC_CLAIM_EXP_WEIGHT as u64 / 1000,
+                       amount_satoshis: 5_000 - inbound_htlc_claim_fee,
                        confirmation_height: largest_htlc_claimed_avail_height,
                }]),
                sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
@@ -1312,19 +1359,45 @@ fn do_test_revoked_counterparty_commitment_balances(confirm_htlc_spend_first: bo
 
 #[test]
 fn test_revoked_counterparty_commitment_balances() {
-       do_test_revoked_counterparty_commitment_balances(true);
-       do_test_revoked_counterparty_commitment_balances(false);
+       do_test_revoked_counterparty_commitment_balances(false, true);
+       do_test_revoked_counterparty_commitment_balances(false, false);
+       do_test_revoked_counterparty_commitment_balances(true, true);
+       do_test_revoked_counterparty_commitment_balances(true, false);
 }
 
-#[test]
-fn test_revoked_counterparty_htlc_tx_balances() {
+fn do_test_revoked_counterparty_htlc_tx_balances(anchors: bool) {
        // Tests `get_claimable_balances` for revocation spends of HTLC transactions.
        let mut chanmon_cfgs = create_chanmon_cfgs(2);
        chanmon_cfgs[1].keys_manager.disable_revocation_policy_check = true;
        let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
-       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let mut user_config = test_default_channel_config();
+       if anchors {
+               user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+               user_config.manually_accept_inbound_channels = true;
+       }
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(user_config), Some(user_config)]);
        let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
 
+       let coinbase_tx = Transaction {
+               version: 2,
+               lock_time: PackedLockTime::ZERO,
+               input: vec![TxIn { ..Default::default() }],
+               output: vec![
+                       TxOut {
+                               value: Amount::ONE_BTC.to_sat(),
+                               script_pubkey: nodes[0].wallet_source.get_change_script().unwrap(),
+                       },
+                       TxOut {
+                               value: Amount::ONE_BTC.to_sat(),
+                               script_pubkey: nodes[1].wallet_source.get_change_script().unwrap(),
+                       },
+               ],
+       };
+       if anchors {
+               nodes[0].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value);
+               nodes[1].wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 1 }, coinbase_tx.output[1].value);
+       }
+
        // Create some initial channels
        let (_, _, chan_id, funding_tx) =
                create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 11_000_000);
@@ -1336,9 +1409,15 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        let revoked_local_txn = get_local_commitment_txn!(nodes[1], chan_id);
        assert_eq!(revoked_local_txn[0].input.len(), 1);
        assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, funding_tx.txid());
+       if anchors {
+               assert_eq!(revoked_local_txn[0].output[4].value, 10000); // to_self output
+       } else {
+               assert_eq!(revoked_local_txn[0].output[2].value, 10000); // to_self output
+       }
 
-       // The to-be-revoked commitment tx should have two HTLCs and an output for both sides
-       assert_eq!(revoked_local_txn[0].output.len(), 4);
+       // The to-be-revoked commitment tx should have two HTLCs, an output for each side, and an
+       // anchor output for each side if enabled.
+       assert_eq!(revoked_local_txn[0].output.len(), if anchors { 6 } else { 4 });
 
        claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
 
@@ -1350,16 +1429,25 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        check_closed_broadcast!(nodes[1], true);
        check_added_monitors!(nodes[1], 1);
        check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed, [nodes[0].node.get_our_node_id()], 1000000);
+       if anchors {
+               handle_bump_htlc_event(&nodes[1], 1);
+       }
        let revoked_htlc_success = {
                let mut txn = nodes[1].tx_broadcaster.txn_broadcast();
                assert_eq!(txn.len(), 1);
-               assert_eq!(txn[0].input.len(), 1);
-               assert_eq!(txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
-               check_spends!(txn[0], revoked_local_txn[0]);
+               assert_eq!(txn[0].input.len(), if anchors { 2 } else { 1 });
+               assert_eq!(txn[0].input[0].previous_output.vout, if anchors { 3 } else { 1 });
+               assert_eq!(txn[0].input[0].witness.last().unwrap().len(),
+                       if anchors { ACCEPTED_HTLC_SCRIPT_WEIGHT_ANCHORS } else { ACCEPTED_HTLC_SCRIPT_WEIGHT });
+               check_spends!(txn[0], revoked_local_txn[0], coinbase_tx);
                txn.pop().unwrap()
        };
+       let revoked_htlc_success_fee = chan_feerate * revoked_htlc_success.weight() as u64 / 1000;
 
        connect_blocks(&nodes[1], TEST_FINAL_CLTV);
+       if anchors {
+               handle_bump_htlc_event(&nodes[1], 2);
+       }
        let revoked_htlc_timeout = {
                let mut txn = nodes[1].tx_broadcaster.unique_txn_broadcast();
                assert_eq!(txn.len(), 2);
@@ -1369,7 +1457,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
                        txn.remove(0)
                }
        };
-       check_spends!(revoked_htlc_timeout, revoked_local_txn[0]);
+       check_spends!(revoked_htlc_timeout, revoked_local_txn[0], coinbase_tx);
        assert_ne!(revoked_htlc_success.input[0].previous_output, revoked_htlc_timeout.input[0].previous_output);
        assert_eq!(revoked_htlc_success.lock_time.0, 0);
        assert_ne!(revoked_htlc_timeout.lock_time.0, 0);
@@ -1381,17 +1469,37 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        check_closed_event!(nodes[0], 1, ClosureReason::CommitmentTxConfirmed, [nodes[1].node.get_our_node_id()], 1000000);
        let to_remote_conf_height = nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1;
 
-       let as_commitment_claim_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
-       assert_eq!(as_commitment_claim_txn.len(), 1);
-       check_spends!(as_commitment_claim_txn[0], revoked_local_txn[0]);
+       let revoked_to_self_claim = {
+               let mut as_commitment_claim_txn = nodes[0].tx_broadcaster.txn_broadcast();
+               assert_eq!(as_commitment_claim_txn.len(), if anchors { 2 } else { 1 });
+               if anchors {
+                       assert_eq!(as_commitment_claim_txn[0].input.len(), 1);
+                       assert_eq!(as_commitment_claim_txn[0].input[0].previous_output.vout, 4); // Separate to_remote claim
+                       check_spends!(as_commitment_claim_txn[0], revoked_local_txn[0]);
+                       assert_eq!(as_commitment_claim_txn[1].input.len(), 2);
+                       assert_eq!(as_commitment_claim_txn[1].input[0].previous_output.vout, 2);
+                       assert_eq!(as_commitment_claim_txn[1].input[1].previous_output.vout, 3);
+                       check_spends!(as_commitment_claim_txn[1], revoked_local_txn[0]);
+                       Some(as_commitment_claim_txn.remove(0))
+               } else {
+                       assert_eq!(as_commitment_claim_txn[0].input.len(), 3);
+                       assert_eq!(as_commitment_claim_txn[0].input[0].previous_output.vout, 2);
+                       assert_eq!(as_commitment_claim_txn[0].input[1].previous_output.vout, 0);
+                       assert_eq!(as_commitment_claim_txn[0].input[2].previous_output.vout, 1);
+                       check_spends!(as_commitment_claim_txn[0], revoked_local_txn[0]);
+                       None
+               }
+       };
 
        // The next two checks have the same balance set for A - even though we confirm a revoked HTLC
        // transaction our balance tracking doesn't use the on-chain value so the
        // `CounterpartyRevokedOutputClaimable` entry doesn't change.
+       let commitment_tx_fee = chan_feerate *
+               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000;
+       let anchor_outputs_value = if anchors { channel::ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 };
        let as_balances = sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        // to_remote output in B's revoked commitment
-                       amount_satoshis: 1_000_000 - 11_000 - 3_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       amount_satoshis: 1_000_000 - 11_000 - 3_000 - commitment_tx_fee - anchor_outputs_value,
                        confirmation_height: to_remote_conf_height,
                }, Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in B's revoked commitment
@@ -1407,22 +1515,36 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        mine_transaction(&nodes[0], &revoked_htlc_success);
        let as_htlc_claim_tx = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
        assert_eq!(as_htlc_claim_tx.len(), 2);
+       assert_eq!(as_htlc_claim_tx[0].input.len(), 1);
        check_spends!(as_htlc_claim_tx[0], revoked_htlc_success);
-       check_spends!(as_htlc_claim_tx[1], revoked_local_txn[0]); // A has to generate a new claim for the remaining revoked
-                                                                 // outputs (which no longer includes the spent HTLC output)
+       // A has to generate a new claim for the remaining revoked outputs (which no longer includes the
+       // spent HTLC output)
+       assert_eq!(as_htlc_claim_tx[1].input.len(), if anchors { 1 } else { 2 });
+       assert_eq!(as_htlc_claim_tx[1].input[0].previous_output.vout, 2);
+       if !anchors {
+               assert_eq!(as_htlc_claim_tx[1].input[1].previous_output.vout, 0);
+       }
+       check_spends!(as_htlc_claim_tx[1], revoked_local_txn[0]);
 
        assert_eq!(as_balances,
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
        assert_eq!(as_htlc_claim_tx[0].output.len(), 1);
-       fuzzy_assert_eq(as_htlc_claim_tx[0].output[0].value,
-               3_000 - chan_feerate * (revoked_htlc_success.weight() + as_htlc_claim_tx[0].weight()) as u64 / 1000);
+       let as_revoked_htlc_success_claim_fee = chan_feerate * as_htlc_claim_tx[0].weight() as u64 / 1000;
+       if anchors {
+               // With anchors, B can pay for revoked_htlc_success's fee with additional inputs, rather
+               // than with the HTLC itself.
+               fuzzy_assert_eq(as_htlc_claim_tx[0].output[0].value,
+                       3_000 - as_revoked_htlc_success_claim_fee);
+       } else {
+               fuzzy_assert_eq(as_htlc_claim_tx[0].output[0].value,
+                       3_000 - revoked_htlc_success_fee - as_revoked_htlc_success_claim_fee);
+       }
 
        mine_transaction(&nodes[0], &as_htlc_claim_tx[0]);
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        // to_remote output in B's revoked commitment
-                       amount_satoshis: 1_000_000 - 11_000 - 3_000 - chan_feerate *
-                               (channel::commitment_tx_base_weight(&channel_type_features) + 2 * channel::COMMITMENT_TX_WEIGHT_PER_HTLC) / 1000,
+                       amount_satoshis: 1_000_000 - 11_000 - 3_000 - commitment_tx_fee - anchor_outputs_value,
                        confirmation_height: to_remote_conf_height,
                }, Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in B's revoked commitment
@@ -1476,11 +1598,24 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        }
 
        mine_transaction(&nodes[0], &revoked_htlc_timeout);
-       let as_second_htlc_claim_tx = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
-       assert_eq!(as_second_htlc_claim_tx.len(), 2);
-
-       check_spends!(as_second_htlc_claim_tx[0], revoked_htlc_timeout);
-       check_spends!(as_second_htlc_claim_tx[1], revoked_local_txn[0]);
+       let (revoked_htlc_timeout_claim, revoked_to_self_claim) = {
+               let mut as_second_htlc_claim_tx = nodes[0].tx_broadcaster.txn_broadcast();
+               assert_eq!(as_second_htlc_claim_tx.len(), if anchors { 1 } else { 2 });
+               if anchors {
+                       assert_eq!(as_second_htlc_claim_tx[0].input.len(), 1);
+                       assert_eq!(as_second_htlc_claim_tx[0].input[0].previous_output.vout, 0);
+                       check_spends!(as_second_htlc_claim_tx[0], revoked_htlc_timeout);
+                       (as_second_htlc_claim_tx.remove(0), revoked_to_self_claim.unwrap())
+               } else {
+                       assert_eq!(as_second_htlc_claim_tx[0].input.len(), 1);
+                       assert_eq!(as_second_htlc_claim_tx[0].input[0].previous_output.vout, 0);
+                       check_spends!(as_second_htlc_claim_tx[0], revoked_htlc_timeout);
+                       assert_eq!(as_second_htlc_claim_tx[1].input.len(), 1);
+                       assert_eq!(as_second_htlc_claim_tx[1].input[0].previous_output.vout, 2);
+                       check_spends!(as_second_htlc_claim_tx[1], revoked_local_txn[0]);
+                       (as_second_htlc_claim_tx.remove(0), as_second_htlc_claim_tx.remove(0))
+               }
+       };
 
        // Connect blocks to finalize the HTLC resolution with the HTLC-Timeout transaction. In a
        // previous iteration of the revoked balance handling this would result in us "forgetting" that
@@ -1494,31 +1629,31 @@ fn test_revoked_counterparty_htlc_tx_balances() {
                }]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
-       mine_transaction(&nodes[0], &as_second_htlc_claim_tx[0]);
+       mine_transaction(&nodes[0], &revoked_htlc_timeout_claim);
        assert_eq!(sorted_vec(vec![Balance::CounterpartyRevokedOutputClaimable {
                        // to_self output in B's revoked commitment
                        amount_satoshis: 10_000,
                }, Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: as_second_htlc_claim_tx[0].output[0].value,
+                       amount_satoshis: revoked_htlc_timeout_claim.output[0].value,
                        confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1,
                }]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
-       mine_transaction(&nodes[0], &as_second_htlc_claim_tx[1]);
+       mine_transaction(&nodes[0], &revoked_to_self_claim);
        assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
                        // to_self output in B's revoked commitment
-                       amount_satoshis: as_second_htlc_claim_tx[1].output[0].value,
+                       amount_satoshis: revoked_to_self_claim.output[0].value,
                        confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 1,
                }, Balance::ClaimableAwaitingConfirmations {
-                       amount_satoshis: as_second_htlc_claim_tx[0].output[0].value,
+                       amount_satoshis: revoked_htlc_timeout_claim.output[0].value,
                        confirmation_height: nodes[0].best_block_info().1 + ANTI_REORG_DELAY - 2,
                }]),
                sorted_vec(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
 
        connect_blocks(&nodes[0], ANTI_REORG_DELAY - 2);
-       test_spendable_output(&nodes[0], &as_second_htlc_claim_tx[0], false);
+       test_spendable_output(&nodes[0], &revoked_htlc_timeout_claim, false);
        connect_blocks(&nodes[0], 1);
-       test_spendable_output(&nodes[0], &as_second_htlc_claim_tx[1], false);
+       test_spendable_output(&nodes[0], &revoked_to_self_claim, false);
 
        assert_eq!(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances(), Vec::new());
 
@@ -1531,6 +1666,12 @@ fn test_revoked_counterparty_htlc_tx_balances() {
        assert!(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances().is_empty());
 }
 
+#[test]
+fn test_revoked_counterparty_htlc_tx_balances() {
+       do_test_revoked_counterparty_htlc_tx_balances(false);
+       do_test_revoked_counterparty_htlc_tx_balances(true);
+}
+
 #[test]
 fn test_revoked_counterparty_aggregated_claims() {
        // Tests `get_claimable_balances` for revoked counterparty commitment transactions when