@@ -1646,6 +1646,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
16461646 do_test_revoked_counterparty_htlc_tx_balances ( true ) ;
16471647}
16481648
1649+ fn do_test_revoked_counterparty_aggregated_claims ( anchors : bool ) {
16491650 // Tests `get_claimable_balances` for revoked counterparty commitment transactions when
16501651 // claiming with an aggregated claim transaction.
16511652 let mut chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
@@ -1655,9 +1656,25 @@ fn test_revoked_counterparty_htlc_tx_balances() {
16551656 // transaction which, from the point of view of our keys_manager, is revoked.
16561657 chanmon_cfgs[ 1 ] . keys_manager . disable_revocation_policy_check = true ;
16571658 let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1658- let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
1659+ let mut user_config = test_default_channel_config ( ) ;
1660+ if anchors {
1661+ user_config. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = true ;
1662+ user_config. manually_accept_inbound_channels = true ;
1663+ }
1664+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( user_config) , Some ( user_config) ] ) ;
16591665 let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
16601666
1667+ let coinbase_tx = Transaction {
1668+ version : 2 ,
1669+ lock_time : PackedLockTime :: ZERO ,
1670+ input : vec ! [ TxIn { ..Default :: default ( ) } ] ,
1671+ output : vec ! [ TxOut {
1672+ value: Amount :: ONE_BTC . to_sat( ) ,
1673+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1674+ } ] ,
1675+ } ;
1676+ nodes[ 0 ] . wallet_source . add_utxo ( bitcoin:: OutPoint { txid : coinbase_tx. txid ( ) , vout : 0 } , coinbase_tx. output [ 0 ] . value ) ;
1677+
16611678 let ( _, _, chan_id, funding_tx) =
16621679 create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 100_000_000 ) ;
16631680 let funding_outpoint = OutPoint { txid : funding_tx. txid ( ) , index : 0 } ;
@@ -1680,9 +1697,11 @@ fn test_revoked_counterparty_htlc_tx_balances() {
16801697 // Now get the latest commitment transaction from A and then update the fee to revoke it
16811698 let as_revoked_txn = get_local_commitment_txn ! ( nodes[ 0 ] , chan_id) ;
16821699
1683- assert_eq ! ( as_revoked_txn. len( ) , 2 ) ;
1700+ assert_eq ! ( as_revoked_txn. len( ) , if anchors { 1 } else { 2 } ) ;
16841701 check_spends ! ( as_revoked_txn[ 0 ] , funding_tx) ;
1685- check_spends ! ( as_revoked_txn[ 1 ] , as_revoked_txn[ 0 ] ) ; // The HTLC-Claim transaction
1702+ if !anchors {
1703+ check_spends ! ( as_revoked_txn[ 1 ] , as_revoked_txn[ 0 ] ) ; // The HTLC-Claim transaction
1704+ }
16861705
16871706 let channel_type_features = get_channel_type_features ! ( nodes[ 0 ] , nodes[ 1 ] , chan_id) ;
16881707 let chan_feerate = get_feerate ! ( nodes[ 0 ] , nodes[ 1 ] , chan_id) as u64 ;
@@ -1721,51 +1740,93 @@ fn test_revoked_counterparty_htlc_tx_balances() {
17211740 check_closed_event ! ( nodes[ 1 ] , 1 , ClosureReason :: CommitmentTxConfirmed , [ nodes[ 0 ] . node. get_our_node_id( ) ] , 1000000 ) ;
17221741 check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
17231742
1724- let mut claim_txn: Vec < _ > = nodes[ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . drain ( ..) . filter ( |tx| tx. input . iter ( ) . any ( |inp| inp. previous_output . txid == as_revoked_txn[ 0 ] . txid ( ) ) ) . collect ( ) ;
1725- // Currently the revoked commitment outputs are all claimed in one aggregated transaction
1726- assert_eq ! ( claim_txn. len( ) , 1 ) ;
1727- assert_eq ! ( claim_txn[ 0 ] . input. len( ) , 3 ) ;
1728- check_spends ! ( claim_txn[ 0 ] , as_revoked_txn[ 0 ] ) ;
1743+ let mut claim_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcast ( ) ;
1744+ assert_eq ! ( claim_txn. len( ) , if anchors { 2 } else { 1 } ) ;
1745+ let revoked_to_self_claim = if anchors {
1746+ assert_eq ! ( claim_txn[ 0 ] . input. len( ) , 1 ) ;
1747+ assert_eq ! ( claim_txn[ 0 ] . input[ 0 ] . previous_output. vout, 5 ) ; // Separate to_remote claim
1748+ check_spends ! ( claim_txn[ 0 ] , as_revoked_txn[ 0 ] ) ;
1749+ assert_eq ! ( claim_txn[ 1 ] . input. len( ) , 2 ) ;
1750+ assert_eq ! ( claim_txn[ 1 ] . input[ 0 ] . previous_output. vout, 2 ) ;
1751+ assert_eq ! ( claim_txn[ 1 ] . input[ 1 ] . previous_output. vout, 3 ) ;
1752+ check_spends ! ( claim_txn[ 1 ] , as_revoked_txn[ 0 ] ) ;
1753+ Some ( claim_txn. remove ( 0 ) )
1754+ } else {
1755+ assert_eq ! ( claim_txn[ 0 ] . input. len( ) , 3 ) ;
1756+ assert_eq ! ( claim_txn[ 0 ] . input[ 0 ] . previous_output. vout, 3 ) ;
1757+ assert_eq ! ( claim_txn[ 0 ] . input[ 1 ] . previous_output. vout, 0 ) ;
1758+ assert_eq ! ( claim_txn[ 0 ] . input[ 2 ] . previous_output. vout, 1 ) ;
1759+ check_spends ! ( claim_txn[ 0 ] , as_revoked_txn[ 0 ] ) ;
1760+ None
1761+ } ;
17291762
17301763 let to_remote_maturity = nodes[ 1 ] . best_block_info ( ) . 1 + ANTI_REORG_DELAY - 1 ;
17311764
1765+ let commitment_tx_fee = chan_feerate *
1766+ ( channel:: commitment_tx_base_weight ( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
1767+ let anchor_outputs_value = if anchors { channel:: ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } ;
17321768 assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
17331769 // to_remote output in A's revoked commitment
17341770 amount_satoshis: 100_000 - 4_000 - 3_000 ,
17351771 confirmation_height: to_remote_maturity,
17361772 } , Balance :: CounterpartyRevokedOutputClaimable {
17371773 // to_self output in A's revoked commitment
1738- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1739- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1774+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
17401775 } , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
17411776 amount_satoshis: 4_000 ,
17421777 } , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 2
17431778 amount_satoshis: 3_000 ,
17441779 } ] ) ,
17451780 sorted_vec( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
17461781
1747- // Confirm A's HTLC-Success tranasction which presumably raced B's claim, causing B to create a
1782+ // Confirm A's HTLC-Success transaction which presumably raced B's claim, causing B to create a
17481783 // new claim.
1749- mine_transaction ( & nodes[ 1 ] , & as_revoked_txn[ 1 ] ) ;
1784+ if anchors {
1785+ mine_transaction ( & nodes[ 0 ] , & as_revoked_txn[ 0 ] ) ;
1786+ check_closed_broadcast ( & nodes[ 0 ] , 1 , true ) ;
1787+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
1788+ check_closed_event ! ( & nodes[ 0 ] , 1 , ClosureReason :: CommitmentTxConfirmed , false , [ nodes[ 1 ] . node. get_our_node_id( ) ] , 1_000_000 ) ;
1789+ handle_bump_htlc_event ( & nodes[ 0 ] , 1 ) ;
1790+ }
1791+ let htlc_success_claim = if anchors {
1792+ let mut txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
1793+ assert_eq ! ( txn. len( ) , 1 ) ;
1794+ check_spends ! ( txn[ 0 ] , as_revoked_txn[ 0 ] , coinbase_tx) ;
1795+ txn. pop ( ) . unwrap ( )
1796+ } else {
1797+ as_revoked_txn[ 1 ] . clone ( )
1798+ } ;
1799+ mine_transaction ( & nodes[ 1 ] , & htlc_success_claim) ;
17501800 expect_payment_sent ( & nodes[ 1 ] , claimed_payment_preimage, None , true , false ) ;
1751- let mut claim_txn_2 : Vec < _ > = nodes [ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . clone ( ) ;
1752- claim_txn_2 . sort_unstable_by_key ( |tx| if tx . input . iter ( ) . any ( |inp| inp . previous_output . txid == as_revoked_txn [ 0 ] . txid ( ) ) { 0 } else { 1 } ) ;
1801+
1802+ let mut claim_txn_2 = nodes [ 1 ] . tx_broadcaster . txn_broadcast ( ) ;
17531803 // Once B sees the HTLC-Success transaction it splits its claim transaction into two, though in
17541804 // theory it could re-aggregate the claims as well.
17551805 assert_eq ! ( claim_txn_2. len( ) , 2 ) ;
1756- assert_eq ! ( claim_txn_2[ 0 ] . input. len( ) , 2 ) ;
1757- check_spends ! ( claim_txn_2[ 0 ] , as_revoked_txn[ 0 ] ) ;
1758- assert_eq ! ( claim_txn_2[ 1 ] . input. len( ) , 1 ) ;
1759- check_spends ! ( claim_txn_2[ 1 ] , as_revoked_txn[ 1 ] ) ;
1806+ if anchors {
1807+ assert_eq ! ( claim_txn_2[ 0 ] . input. len( ) , 1 ) ;
1808+ assert_eq ! ( claim_txn_2[ 0 ] . input[ 0 ] . previous_output. vout, 0 ) ;
1809+ check_spends ! ( claim_txn_2[ 0 ] , & htlc_success_claim) ;
1810+ assert_eq ! ( claim_txn_2[ 1 ] . input. len( ) , 1 ) ;
1811+ assert_eq ! ( claim_txn_2[ 1 ] . input[ 0 ] . previous_output. vout, 3 ) ;
1812+ check_spends ! ( claim_txn_2[ 1 ] , as_revoked_txn[ 0 ] ) ;
1813+ } else {
1814+ assert_eq ! ( claim_txn_2[ 0 ] . input. len( ) , 1 ) ;
1815+ assert_eq ! ( claim_txn_2[ 0 ] . input[ 0 ] . previous_output. vout, 0 ) ;
1816+ check_spends ! ( claim_txn_2[ 0 ] , as_revoked_txn[ 1 ] ) ;
1817+ assert_eq ! ( claim_txn_2[ 1 ] . input. len( ) , 2 ) ;
1818+ assert_eq ! ( claim_txn_2[ 1 ] . input[ 0 ] . previous_output. vout, 3 ) ;
1819+ assert_eq ! ( claim_txn_2[ 1 ] . input[ 1 ] . previous_output. vout, 1 ) ;
1820+ check_spends ! ( claim_txn_2[ 1 ] , as_revoked_txn[ 0 ] ) ;
1821+ }
17601822
17611823 assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
17621824 // to_remote output in A's revoked commitment
17631825 amount_satoshis: 100_000 - 4_000 - 3_000 ,
17641826 confirmation_height: to_remote_maturity,
17651827 } , Balance :: CounterpartyRevokedOutputClaimable {
17661828 // to_self output in A's revoked commitment
1767- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1768- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1829+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
17691830 } , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
17701831 amount_satoshis: 4_000 ,
17711832 } , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 2
@@ -1781,8 +1842,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
17811842
17821843 assert_eq ! ( sorted_vec( vec![ Balance :: CounterpartyRevokedOutputClaimable {
17831844 // to_self output in A's revoked commitment
1784- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1785- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1845+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
17861846 } , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
17871847 amount_satoshis: 4_000 ,
17881848 } , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 2
@@ -1793,47 +1853,75 @@ fn test_revoked_counterparty_htlc_tx_balances() {
17931853 } ] ) ,
17941854 sorted_vec( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
17951855
1796- mine_transaction ( & nodes[ 1 ] , & claim_txn_2[ 1 ] ) ;
1856+ mine_transaction ( & nodes[ 1 ] , & claim_txn_2[ 0 ] ) ;
17971857 let htlc_2_claim_maturity = nodes[ 1 ] . best_block_info ( ) . 1 + ANTI_REORG_DELAY - 1 ;
17981858
17991859 assert_eq ! ( sorted_vec( vec![ Balance :: CounterpartyRevokedOutputClaimable {
18001860 // to_self output in A's revoked commitment
1801- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1802- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1861+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
18031862 } , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
18041863 amount_satoshis: 4_000 ,
18051864 } , Balance :: ClaimableAwaitingConfirmations { // HTLC 2
1806- amount_satoshis: claim_txn_2[ 1 ] . output[ 0 ] . value,
1865+ amount_satoshis: claim_txn_2[ 0 ] . output[ 0 ] . value,
18071866 confirmation_height: htlc_2_claim_maturity,
18081867 } ] ) ,
18091868 sorted_vec( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
18101869
18111870 connect_blocks ( & nodes[ 1 ] , 5 ) ;
1812- test_spendable_output ( & nodes[ 1 ] , & claim_txn_2[ 1 ] , false ) ;
1871+ test_spendable_output ( & nodes[ 1 ] , & claim_txn_2[ 0 ] , false ) ;
18131872
18141873 assert_eq ! ( sorted_vec( vec![ Balance :: CounterpartyRevokedOutputClaimable {
18151874 // to_self output in A's revoked commitment
1816- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1817- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1875+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
18181876 } , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
18191877 amount_satoshis: 4_000 ,
18201878 } ] ) ,
18211879 sorted_vec( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
18221880
1823- mine_transaction ( & nodes[ 1 ] , & claim_txn_2[ 0 ] ) ;
1881+ if anchors {
1882+ mine_transactions ( & nodes[ 1 ] , & [ & claim_txn_2[ 1 ] , revoked_to_self_claim. as_ref ( ) . unwrap ( ) ] ) ;
1883+ } else {
1884+ mine_transaction ( & nodes[ 1 ] , & claim_txn_2[ 1 ] ) ;
1885+ }
18241886 let rest_claim_maturity = nodes[ 1 ] . best_block_info ( ) . 1 + ANTI_REORG_DELAY - 1 ;
18251887
1826- assert_eq ! ( vec![ Balance :: ClaimableAwaitingConfirmations {
1827- amount_satoshis: claim_txn_2[ 0 ] . output[ 0 ] . value,
1828- confirmation_height: rest_claim_maturity,
1829- } ] ,
1830- nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ;
1888+ if anchors {
1889+ assert_eq ! ( vec![ Balance :: ClaimableAwaitingConfirmations {
1890+ amount_satoshis: claim_txn_2[ 1 ] . output[ 0 ] . value,
1891+ confirmation_height: rest_claim_maturity,
1892+ } , Balance :: ClaimableAwaitingConfirmations {
1893+ amount_satoshis: revoked_to_self_claim. as_ref( ) . unwrap( ) . output[ 0 ] . value,
1894+ confirmation_height: rest_claim_maturity,
1895+ } ] ,
1896+ nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ;
1897+ } else {
1898+ assert_eq ! ( vec![ Balance :: ClaimableAwaitingConfirmations {
1899+ amount_satoshis: claim_txn_2[ 1 ] . output[ 0 ] . value,
1900+ confirmation_height: rest_claim_maturity,
1901+ } ] ,
1902+ nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ;
1903+ }
18311904
18321905 assert ! ( nodes[ 1 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ; // We shouldn't fail the payment until we spend the output
18331906
18341907 connect_blocks ( & nodes[ 1 ] , 5 ) ;
18351908 expect_payment_failed ! ( nodes[ 1 ] , revoked_payment_hash, false ) ;
1836- test_spendable_output ( & nodes[ 1 ] , & claim_txn_2[ 0 ] , false ) ;
1909+ if anchors {
1910+ let events = nodes[ 1 ] . chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
1911+ assert_eq ! ( events. len( ) , 2 ) ;
1912+ for ( i, event) in events. into_iter ( ) . enumerate ( ) {
1913+ if let Event :: SpendableOutputs { outputs, .. } = event {
1914+ assert_eq ! ( outputs. len( ) , 1 ) ;
1915+ let spend_tx = nodes[ 1 ] . keys_manager . backing . spend_spendable_outputs (
1916+ & [ & outputs[ 0 ] ] , Vec :: new ( ) , Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_RETURN ) . into_script ( ) ,
1917+ 253 , None , & Secp256k1 :: new ( )
1918+ ) . unwrap ( ) ;
1919+ check_spends ! ( spend_tx, if i == 0 { & claim_txn_2[ 1 ] } else { revoked_to_self_claim. as_ref( ) . unwrap( ) } ) ;
1920+ } else { panic ! ( ) ; }
1921+ }
1922+ } else {
1923+ test_spendable_output ( & nodes[ 1 ] , & claim_txn_2[ 1 ] , false ) ;
1924+ }
18371925 assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) . is_empty( ) ) ;
18381926
18391927 // Ensure that even if we connect more blocks, potentially replaying the entire chain if we're
@@ -1845,6 +1933,12 @@ fn test_revoked_counterparty_htlc_tx_balances() {
18451933 assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) . is_empty( ) ) ;
18461934}
18471935
1936+ #[ test]
1937+ fn test_revoked_counterparty_aggregated_claims ( ) {
1938+ do_test_revoked_counterparty_aggregated_claims ( false ) ;
1939+ do_test_revoked_counterparty_aggregated_claims ( true ) ;
1940+ }
1941+
18481942fn do_test_restored_packages_retry ( check_old_monitor_retries_after_upgrade : bool ) {
18491943 // Tests that we'll retry packages that were previously timelocked after we've restored them.
18501944 let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
0 commit comments