@@ -1365,15 +1365,39 @@ fn test_revoked_counterparty_commitment_balances() {
13651365 do_test_revoked_counterparty_commitment_balances ( true , false ) ;
13661366}
13671367
1368- #[ test]
1369- fn test_revoked_counterparty_htlc_tx_balances ( ) {
1368+ fn do_test_revoked_counterparty_htlc_tx_balances ( anchors : bool ) {
13701369 // Tests `get_claimable_balances` for revocation spends of HTLC transactions.
13711370 let mut chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
13721371 chanmon_cfgs[ 1 ] . keys_manager . disable_revocation_policy_check = true ;
13731372 let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1374- let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
1373+ let mut user_config = test_default_channel_config ( ) ;
1374+ if anchors {
1375+ user_config. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = true ;
1376+ user_config. manually_accept_inbound_channels = true ;
1377+ }
1378+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( user_config) , Some ( user_config) ] ) ;
13751379 let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
13761380
1381+ let coinbase_tx = Transaction {
1382+ version : 2 ,
1383+ lock_time : PackedLockTime :: ZERO ,
1384+ input : vec ! [ TxIn { ..Default :: default ( ) } ] ,
1385+ output : vec ! [
1386+ TxOut {
1387+ value: Amount :: ONE_BTC . to_sat( ) ,
1388+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1389+ } ,
1390+ TxOut {
1391+ value: Amount :: ONE_BTC . to_sat( ) ,
1392+ script_pubkey: nodes[ 1 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1393+ } ,
1394+ ] ,
1395+ } ;
1396+ if anchors {
1397+ nodes[ 0 ] . wallet_source . add_utxo ( bitcoin:: OutPoint { txid : coinbase_tx. txid ( ) , vout : 0 } , coinbase_tx. output [ 0 ] . value ) ;
1398+ nodes[ 1 ] . wallet_source . add_utxo ( bitcoin:: OutPoint { txid : coinbase_tx. txid ( ) , vout : 1 } , coinbase_tx. output [ 1 ] . value ) ;
1399+ }
1400+
13771401 // Create some initial channels
13781402 let ( _, _, chan_id, funding_tx) =
13791403 create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 11_000_000 ) ;
@@ -1385,9 +1409,15 @@ fn test_revoked_counterparty_htlc_tx_balances() {
13851409 let revoked_local_txn = get_local_commitment_txn ! ( nodes[ 1 ] , chan_id) ;
13861410 assert_eq ! ( revoked_local_txn[ 0 ] . input. len( ) , 1 ) ;
13871411 assert_eq ! ( revoked_local_txn[ 0 ] . input[ 0 ] . previous_output. txid, funding_tx. txid( ) ) ;
1412+ if anchors {
1413+ assert_eq ! ( revoked_local_txn[ 0 ] . output[ 4 ] . value, 10000 ) ; // to_self output
1414+ } else {
1415+ assert_eq ! ( revoked_local_txn[ 0 ] . output[ 2 ] . value, 10000 ) ; // to_self output
1416+ }
13881417
1389- // The to-be-revoked commitment tx should have two HTLCs and an output for both sides
1390- assert_eq ! ( revoked_local_txn[ 0 ] . output. len( ) , 4 ) ;
1418+ // The to-be-revoked commitment tx should have two HTLCs, an output for each side, and an
1419+ // anchor output for each side if enabled.
1420+ assert_eq ! ( revoked_local_txn[ 0 ] . output. len( ) , if anchors { 6 } else { 4 } ) ;
13911421
13921422 claim_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , payment_preimage) ;
13931423
@@ -1399,16 +1429,25 @@ fn test_revoked_counterparty_htlc_tx_balances() {
13991429 check_closed_broadcast ! ( nodes[ 1 ] , true ) ;
14001430 check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
14011431 check_closed_event ! ( nodes[ 1 ] , 1 , ClosureReason :: CommitmentTxConfirmed , [ nodes[ 0 ] . node. get_our_node_id( ) ] , 1000000 ) ;
1432+ if anchors {
1433+ handle_bump_htlc_event ( & nodes[ 1 ] , 1 ) ;
1434+ }
14021435 let revoked_htlc_success = {
14031436 let mut txn = nodes[ 1 ] . tx_broadcaster . txn_broadcast ( ) ;
14041437 assert_eq ! ( txn. len( ) , 1 ) ;
1405- assert_eq ! ( txn[ 0 ] . input. len( ) , 1 ) ;
1406- assert_eq ! ( txn[ 0 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) , ACCEPTED_HTLC_SCRIPT_WEIGHT ) ;
1407- check_spends ! ( txn[ 0 ] , revoked_local_txn[ 0 ] ) ;
1438+ assert_eq ! ( txn[ 0 ] . input. len( ) , if anchors { 2 } else { 1 } ) ;
1439+ assert_eq ! ( txn[ 0 ] . input[ 0 ] . previous_output. vout, if anchors { 3 } else { 1 } ) ;
1440+ assert_eq ! ( txn[ 0 ] . input[ 0 ] . witness. last( ) . unwrap( ) . len( ) ,
1441+ if anchors { ACCEPTED_HTLC_SCRIPT_WEIGHT_ANCHORS } else { ACCEPTED_HTLC_SCRIPT_WEIGHT } ) ;
1442+ check_spends ! ( txn[ 0 ] , revoked_local_txn[ 0 ] , coinbase_tx) ;
14081443 txn. pop ( ) . unwrap ( )
14091444 } ;
1445+ let revoked_htlc_success_fee = chan_feerate * revoked_htlc_success. weight ( ) as u64 / 1000 ;
14101446
14111447 connect_blocks ( & nodes[ 1 ] , TEST_FINAL_CLTV ) ;
1448+ if anchors {
1449+ handle_bump_htlc_event ( & nodes[ 1 ] , 2 ) ;
1450+ }
14121451 let revoked_htlc_timeout = {
14131452 let mut txn = nodes[ 1 ] . tx_broadcaster . unique_txn_broadcast ( ) ;
14141453 assert_eq ! ( txn. len( ) , 2 ) ;
@@ -1418,7 +1457,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
14181457 txn. remove ( 0 )
14191458 }
14201459 } ;
1421- check_spends ! ( revoked_htlc_timeout, revoked_local_txn[ 0 ] ) ;
1460+ check_spends ! ( revoked_htlc_timeout, revoked_local_txn[ 0 ] , coinbase_tx ) ;
14221461 assert_ne ! ( revoked_htlc_success. input[ 0 ] . previous_output, revoked_htlc_timeout. input[ 0 ] . previous_output) ;
14231462 assert_eq ! ( revoked_htlc_success. lock_time. 0 , 0 ) ;
14241463 assert_ne ! ( revoked_htlc_timeout. lock_time. 0 , 0 ) ;
@@ -1430,17 +1469,37 @@ fn test_revoked_counterparty_htlc_tx_balances() {
14301469 check_closed_event ! ( nodes[ 0 ] , 1 , ClosureReason :: CommitmentTxConfirmed , [ nodes[ 1 ] . node. get_our_node_id( ) ] , 1000000 ) ;
14311470 let to_remote_conf_height = nodes[ 0 ] . best_block_info ( ) . 1 + ANTI_REORG_DELAY - 1 ;
14321471
1433- let as_commitment_claim_txn = nodes[ 0 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . split_off ( 0 ) ;
1434- assert_eq ! ( as_commitment_claim_txn. len( ) , 1 ) ;
1435- check_spends ! ( as_commitment_claim_txn[ 0 ] , revoked_local_txn[ 0 ] ) ;
1472+ let revoked_to_self_claim = {
1473+ let mut as_commitment_claim_txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
1474+ assert_eq ! ( as_commitment_claim_txn. len( ) , if anchors { 2 } else { 1 } ) ;
1475+ if anchors {
1476+ assert_eq ! ( as_commitment_claim_txn[ 0 ] . input. len( ) , 1 ) ;
1477+ assert_eq ! ( as_commitment_claim_txn[ 0 ] . input[ 0 ] . previous_output. vout, 4 ) ; // Separate to_remote claim
1478+ check_spends ! ( as_commitment_claim_txn[ 0 ] , revoked_local_txn[ 0 ] ) ;
1479+ assert_eq ! ( as_commitment_claim_txn[ 1 ] . input. len( ) , 2 ) ;
1480+ assert_eq ! ( as_commitment_claim_txn[ 1 ] . input[ 0 ] . previous_output. vout, 2 ) ;
1481+ assert_eq ! ( as_commitment_claim_txn[ 1 ] . input[ 1 ] . previous_output. vout, 3 ) ;
1482+ check_spends ! ( as_commitment_claim_txn[ 1 ] , revoked_local_txn[ 0 ] ) ;
1483+ Some ( as_commitment_claim_txn. remove ( 0 ) )
1484+ } else {
1485+ assert_eq ! ( as_commitment_claim_txn[ 0 ] . input. len( ) , 3 ) ;
1486+ assert_eq ! ( as_commitment_claim_txn[ 0 ] . input[ 0 ] . previous_output. vout, 2 ) ;
1487+ assert_eq ! ( as_commitment_claim_txn[ 0 ] . input[ 1 ] . previous_output. vout, 0 ) ;
1488+ assert_eq ! ( as_commitment_claim_txn[ 0 ] . input[ 2 ] . previous_output. vout, 1 ) ;
1489+ check_spends ! ( as_commitment_claim_txn[ 0 ] , revoked_local_txn[ 0 ] ) ;
1490+ None
1491+ }
1492+ } ;
14361493
14371494 // The next two checks have the same balance set for A - even though we confirm a revoked HTLC
14381495 // transaction our balance tracking doesn't use the on-chain value so the
14391496 // `CounterpartyRevokedOutputClaimable` entry doesn't change.
1497+ let commitment_tx_fee = chan_feerate *
1498+ ( channel:: commitment_tx_base_weight ( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
1499+ let anchor_outputs_value = if anchors { channel:: ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } ;
14401500 let as_balances = sorted_vec ( vec ! [ Balance :: ClaimableAwaitingConfirmations {
14411501 // to_remote output in B's revoked commitment
1442- amount_satoshis: 1_000_000 - 11_000 - 3_000 - chan_feerate *
1443- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1502+ amount_satoshis: 1_000_000 - 11_000 - 3_000 - commitment_tx_fee - anchor_outputs_value,
14441503 confirmation_height: to_remote_conf_height,
14451504 } , Balance :: CounterpartyRevokedOutputClaimable {
14461505 // to_self output in B's revoked commitment
@@ -1456,22 +1515,36 @@ fn test_revoked_counterparty_htlc_tx_balances() {
14561515 mine_transaction ( & nodes[ 0 ] , & revoked_htlc_success) ;
14571516 let as_htlc_claim_tx = nodes[ 0 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . split_off ( 0 ) ;
14581517 assert_eq ! ( as_htlc_claim_tx. len( ) , 2 ) ;
1518+ assert_eq ! ( as_htlc_claim_tx[ 0 ] . input. len( ) , 1 ) ;
14591519 check_spends ! ( as_htlc_claim_tx[ 0 ] , revoked_htlc_success) ;
1460- check_spends ! ( as_htlc_claim_tx[ 1 ] , revoked_local_txn[ 0 ] ) ; // A has to generate a new claim for the remaining revoked
1461- // outputs (which no longer includes the spent HTLC output)
1520+ // A has to generate a new claim for the remaining revoked outputs (which no longer includes the
1521+ // spent HTLC output)
1522+ assert_eq ! ( as_htlc_claim_tx[ 1 ] . input. len( ) , if anchors { 1 } else { 2 } ) ;
1523+ assert_eq ! ( as_htlc_claim_tx[ 1 ] . input[ 0 ] . previous_output. vout, 2 ) ;
1524+ if !anchors {
1525+ assert_eq ! ( as_htlc_claim_tx[ 1 ] . input[ 1 ] . previous_output. vout, 0 ) ;
1526+ }
1527+ check_spends ! ( as_htlc_claim_tx[ 1 ] , revoked_local_txn[ 0 ] ) ;
14621528
14631529 assert_eq ! ( as_balances,
14641530 sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
14651531
14661532 assert_eq ! ( as_htlc_claim_tx[ 0 ] . output. len( ) , 1 ) ;
1467- fuzzy_assert_eq ( as_htlc_claim_tx[ 0 ] . output [ 0 ] . value ,
1468- 3_000 - chan_feerate * ( revoked_htlc_success. weight ( ) + as_htlc_claim_tx[ 0 ] . weight ( ) ) as u64 / 1000 ) ;
1533+ let as_revoked_htlc_success_claim_fee = chan_feerate * as_htlc_claim_tx[ 0 ] . weight ( ) as u64 / 1000 ;
1534+ if anchors {
1535+ // With anchors, B can pay for revoked_htlc_success's fee with additional inputs, rather
1536+ // than with the HTLC itself.
1537+ fuzzy_assert_eq ( as_htlc_claim_tx[ 0 ] . output [ 0 ] . value ,
1538+ 3_000 - as_revoked_htlc_success_claim_fee) ;
1539+ } else {
1540+ fuzzy_assert_eq ( as_htlc_claim_tx[ 0 ] . output [ 0 ] . value ,
1541+ 3_000 - revoked_htlc_success_fee - as_revoked_htlc_success_claim_fee) ;
1542+ }
14691543
14701544 mine_transaction ( & nodes[ 0 ] , & as_htlc_claim_tx[ 0 ] ) ;
14711545 assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
14721546 // to_remote output in B's revoked commitment
1473- amount_satoshis: 1_000_000 - 11_000 - 3_000 - chan_feerate *
1474- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1547+ amount_satoshis: 1_000_000 - 11_000 - 3_000 - commitment_tx_fee - anchor_outputs_value,
14751548 confirmation_height: to_remote_conf_height,
14761549 } , Balance :: CounterpartyRevokedOutputClaimable {
14771550 // to_self output in B's revoked commitment
@@ -1525,11 +1598,24 @@ fn test_revoked_counterparty_htlc_tx_balances() {
15251598 }
15261599
15271600 mine_transaction ( & nodes[ 0 ] , & revoked_htlc_timeout) ;
1528- let as_second_htlc_claim_tx = nodes[ 0 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . split_off ( 0 ) ;
1529- assert_eq ! ( as_second_htlc_claim_tx. len( ) , 2 ) ;
1530-
1531- check_spends ! ( as_second_htlc_claim_tx[ 0 ] , revoked_htlc_timeout) ;
1532- check_spends ! ( as_second_htlc_claim_tx[ 1 ] , revoked_local_txn[ 0 ] ) ;
1601+ let ( revoked_htlc_timeout_claim, revoked_to_self_claim) = {
1602+ let mut as_second_htlc_claim_tx = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
1603+ assert_eq ! ( as_second_htlc_claim_tx. len( ) , if anchors { 1 } else { 2 } ) ;
1604+ if anchors {
1605+ assert_eq ! ( as_second_htlc_claim_tx[ 0 ] . input. len( ) , 1 ) ;
1606+ assert_eq ! ( as_second_htlc_claim_tx[ 0 ] . input[ 0 ] . previous_output. vout, 0 ) ;
1607+ check_spends ! ( as_second_htlc_claim_tx[ 0 ] , revoked_htlc_timeout) ;
1608+ ( as_second_htlc_claim_tx. remove ( 0 ) , revoked_to_self_claim. unwrap ( ) )
1609+ } else {
1610+ assert_eq ! ( as_second_htlc_claim_tx[ 0 ] . input. len( ) , 1 ) ;
1611+ assert_eq ! ( as_second_htlc_claim_tx[ 0 ] . input[ 0 ] . previous_output. vout, 0 ) ;
1612+ check_spends ! ( as_second_htlc_claim_tx[ 0 ] , revoked_htlc_timeout) ;
1613+ assert_eq ! ( as_second_htlc_claim_tx[ 1 ] . input. len( ) , 1 ) ;
1614+ assert_eq ! ( as_second_htlc_claim_tx[ 1 ] . input[ 0 ] . previous_output. vout, 2 ) ;
1615+ check_spends ! ( as_second_htlc_claim_tx[ 1 ] , revoked_local_txn[ 0 ] ) ;
1616+ ( as_second_htlc_claim_tx. remove ( 0 ) , as_second_htlc_claim_tx. remove ( 0 ) )
1617+ }
1618+ } ;
15331619
15341620 // Connect blocks to finalize the HTLC resolution with the HTLC-Timeout transaction. In a
15351621 // previous iteration of the revoked balance handling this would result in us "forgetting" that
@@ -1543,31 +1629,31 @@ fn test_revoked_counterparty_htlc_tx_balances() {
15431629 } ] ) ,
15441630 sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
15451631
1546- mine_transaction ( & nodes[ 0 ] , & as_second_htlc_claim_tx [ 0 ] ) ;
1632+ mine_transaction ( & nodes[ 0 ] , & revoked_htlc_timeout_claim ) ;
15471633 assert_eq ! ( sorted_vec( vec![ Balance :: CounterpartyRevokedOutputClaimable {
15481634 // to_self output in B's revoked commitment
15491635 amount_satoshis: 10_000 ,
15501636 } , Balance :: ClaimableAwaitingConfirmations {
1551- amount_satoshis: as_second_htlc_claim_tx [ 0 ] . output[ 0 ] . value,
1637+ amount_satoshis: revoked_htlc_timeout_claim . output[ 0 ] . value,
15521638 confirmation_height: nodes[ 0 ] . best_block_info( ) . 1 + ANTI_REORG_DELAY - 1 ,
15531639 } ] ) ,
15541640 sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
15551641
1556- mine_transaction ( & nodes[ 0 ] , & as_second_htlc_claim_tx [ 1 ] ) ;
1642+ mine_transaction ( & nodes[ 0 ] , & revoked_to_self_claim ) ;
15571643 assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
15581644 // to_self output in B's revoked commitment
1559- amount_satoshis: as_second_htlc_claim_tx [ 1 ] . output[ 0 ] . value,
1645+ amount_satoshis: revoked_to_self_claim . output[ 0 ] . value,
15601646 confirmation_height: nodes[ 0 ] . best_block_info( ) . 1 + ANTI_REORG_DELAY - 1 ,
15611647 } , Balance :: ClaimableAwaitingConfirmations {
1562- amount_satoshis: as_second_htlc_claim_tx [ 0 ] . output[ 0 ] . value,
1648+ amount_satoshis: revoked_htlc_timeout_claim . output[ 0 ] . value,
15631649 confirmation_height: nodes[ 0 ] . best_block_info( ) . 1 + ANTI_REORG_DELAY - 2 ,
15641650 } ] ) ,
15651651 sorted_vec( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
15661652
15671653 connect_blocks ( & nodes[ 0 ] , ANTI_REORG_DELAY - 2 ) ;
1568- test_spendable_output ( & nodes[ 0 ] , & as_second_htlc_claim_tx [ 0 ] , false ) ;
1654+ test_spendable_output ( & nodes[ 0 ] , & revoked_htlc_timeout_claim , false ) ;
15691655 connect_blocks ( & nodes[ 0 ] , 1 ) ;
1570- test_spendable_output ( & nodes[ 0 ] , & as_second_htlc_claim_tx [ 1 ] , false ) ;
1656+ test_spendable_output ( & nodes[ 0 ] , & revoked_to_self_claim , false ) ;
15711657
15721658 assert_eq ! ( nodes[ 0 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) , Vec :: new( ) ) ;
15731659
@@ -1581,7 +1667,11 @@ fn test_revoked_counterparty_htlc_tx_balances() {
15811667}
15821668
15831669#[ test]
1584- fn test_revoked_counterparty_aggregated_claims ( ) {
1670+ fn test_revoked_counterparty_htlc_tx_balances ( ) {
1671+ do_test_revoked_counterparty_htlc_tx_balances ( false ) ;
1672+ do_test_revoked_counterparty_htlc_tx_balances ( true ) ;
1673+ }
1674+
15851675 // Tests `get_claimable_balances` for revoked counterparty commitment transactions when
15861676 // claiming with an aggregated claim transaction.
15871677 let mut chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
0 commit comments