@@ -1672,6 +1672,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
1672
1672
do_test_revoked_counterparty_htlc_tx_balances ( true ) ;
1673
1673
}
1674
1674
1675
+ fn do_test_revoked_counterparty_aggregated_claims ( anchors : bool ) {
1675
1676
// Tests `get_claimable_balances` for revoked counterparty commitment transactions when
1676
1677
// claiming with an aggregated claim transaction.
1677
1678
let mut chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
@@ -1681,9 +1682,25 @@ fn test_revoked_counterparty_htlc_tx_balances() {
1681
1682
// transaction which, from the point of view of our keys_manager, is revoked.
1682
1683
chanmon_cfgs[ 1 ] . keys_manager . disable_revocation_policy_check = true ;
1683
1684
let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1684
- let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
1685
+ let mut user_config = test_default_channel_config ( ) ;
1686
+ if anchors {
1687
+ user_config. channel_handshake_config . negotiate_anchors_zero_fee_htlc_tx = true ;
1688
+ user_config. manually_accept_inbound_channels = true ;
1689
+ }
1690
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ Some ( user_config) , Some ( user_config) ] ) ;
1685
1691
let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1686
1692
1693
+ let coinbase_tx = Transaction {
1694
+ version : 2 ,
1695
+ lock_time : PackedLockTime :: ZERO ,
1696
+ input : vec ! [ TxIn { ..Default :: default ( ) } ] ,
1697
+ output : vec ! [ TxOut {
1698
+ value: Amount :: ONE_BTC . to_sat( ) ,
1699
+ script_pubkey: nodes[ 0 ] . wallet_source. get_change_script( ) . unwrap( ) ,
1700
+ } ] ,
1701
+ } ;
1702
+ nodes[ 0 ] . wallet_source . add_utxo ( bitcoin:: OutPoint { txid : coinbase_tx. txid ( ) , vout : 0 } , coinbase_tx. output [ 0 ] . value ) ;
1703
+
1687
1704
let ( _, _, chan_id, funding_tx) =
1688
1705
create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 100_000_000 ) ;
1689
1706
let funding_outpoint = OutPoint { txid : funding_tx. txid ( ) , index : 0 } ;
@@ -1706,9 +1723,11 @@ fn test_revoked_counterparty_htlc_tx_balances() {
1706
1723
// Now get the latest commitment transaction from A and then update the fee to revoke it
1707
1724
let as_revoked_txn = get_local_commitment_txn ! ( nodes[ 0 ] , chan_id) ;
1708
1725
1709
- assert_eq ! ( as_revoked_txn. len( ) , 2 ) ;
1726
+ assert_eq ! ( as_revoked_txn. len( ) , if anchors { 1 } else { 2 } ) ;
1710
1727
check_spends ! ( as_revoked_txn[ 0 ] , funding_tx) ;
1711
- check_spends ! ( as_revoked_txn[ 1 ] , as_revoked_txn[ 0 ] ) ; // The HTLC-Claim transaction
1728
+ if !anchors {
1729
+ check_spends ! ( as_revoked_txn[ 1 ] , as_revoked_txn[ 0 ] ) ; // The HTLC-Claim transaction
1730
+ }
1712
1731
1713
1732
let channel_type_features = get_channel_type_features ! ( nodes[ 0 ] , nodes[ 1 ] , chan_id) ;
1714
1733
let chan_feerate = get_feerate ! ( nodes[ 0 ] , nodes[ 1 ] , chan_id) as u64 ;
@@ -1747,51 +1766,93 @@ fn test_revoked_counterparty_htlc_tx_balances() {
1747
1766
check_closed_event ! ( nodes[ 1 ] , 1 , ClosureReason :: CommitmentTxConfirmed , [ nodes[ 0 ] . node. get_our_node_id( ) ] , 1000000 ) ;
1748
1767
check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
1749
1768
1750
- 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 ( ) ;
1751
- // Currently the revoked commitment outputs are all claimed in one aggregated transaction
1752
- assert_eq ! ( claim_txn. len( ) , 1 ) ;
1753
- assert_eq ! ( claim_txn[ 0 ] . input. len( ) , 3 ) ;
1754
- check_spends ! ( claim_txn[ 0 ] , as_revoked_txn[ 0 ] ) ;
1769
+ let mut claim_txn = nodes[ 1 ] . tx_broadcaster . txn_broadcast ( ) ;
1770
+ assert_eq ! ( claim_txn. len( ) , if anchors { 2 } else { 1 } ) ;
1771
+ let revoked_to_self_claim = if anchors {
1772
+ assert_eq ! ( claim_txn[ 0 ] . input. len( ) , 1 ) ;
1773
+ assert_eq ! ( claim_txn[ 0 ] . input[ 0 ] . previous_output. vout, 5 ) ; // Separate to_remote claim
1774
+ check_spends ! ( claim_txn[ 0 ] , as_revoked_txn[ 0 ] ) ;
1775
+ assert_eq ! ( claim_txn[ 1 ] . input. len( ) , 2 ) ;
1776
+ assert_eq ! ( claim_txn[ 1 ] . input[ 0 ] . previous_output. vout, 2 ) ;
1777
+ assert_eq ! ( claim_txn[ 1 ] . input[ 1 ] . previous_output. vout, 3 ) ;
1778
+ check_spends ! ( claim_txn[ 1 ] , as_revoked_txn[ 0 ] ) ;
1779
+ Some ( claim_txn. remove ( 0 ) )
1780
+ } else {
1781
+ assert_eq ! ( claim_txn[ 0 ] . input. len( ) , 3 ) ;
1782
+ assert_eq ! ( claim_txn[ 0 ] . input[ 0 ] . previous_output. vout, 3 ) ;
1783
+ assert_eq ! ( claim_txn[ 0 ] . input[ 1 ] . previous_output. vout, 0 ) ;
1784
+ assert_eq ! ( claim_txn[ 0 ] . input[ 2 ] . previous_output. vout, 1 ) ;
1785
+ check_spends ! ( claim_txn[ 0 ] , as_revoked_txn[ 0 ] ) ;
1786
+ None
1787
+ } ;
1755
1788
1756
1789
let to_remote_maturity = nodes[ 1 ] . best_block_info ( ) . 1 + ANTI_REORG_DELAY - 1 ;
1757
1790
1791
+ let commitment_tx_fee = chan_feerate *
1792
+ ( channel:: commitment_tx_base_weight ( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ;
1793
+ let anchor_outputs_value = if anchors { channel:: ANCHOR_OUTPUT_VALUE_SATOSHI * 2 } else { 0 } ;
1758
1794
assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
1759
1795
// to_remote output in A's revoked commitment
1760
1796
amount_satoshis: 100_000 - 4_000 - 3_000 ,
1761
1797
confirmation_height: to_remote_maturity,
1762
1798
} , Balance :: CounterpartyRevokedOutputClaimable {
1763
1799
// to_self output in A's revoked commitment
1764
- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1765
- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1800
+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
1766
1801
} , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
1767
1802
amount_satoshis: 4_000 ,
1768
1803
} , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 2
1769
1804
amount_satoshis: 3_000 ,
1770
1805
} ] ) ,
1771
1806
sorted_vec( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
1772
1807
1773
- // Confirm A's HTLC-Success tranasction which presumably raced B's claim, causing B to create a
1808
+ // Confirm A's HTLC-Success transaction which presumably raced B's claim, causing B to create a
1774
1809
// new claim.
1775
- mine_transaction ( & nodes[ 1 ] , & as_revoked_txn[ 1 ] ) ;
1810
+ if anchors {
1811
+ mine_transaction ( & nodes[ 0 ] , & as_revoked_txn[ 0 ] ) ;
1812
+ check_closed_broadcast ( & nodes[ 0 ] , 1 , true ) ;
1813
+ check_added_monitors ( & nodes[ 0 ] , 1 ) ;
1814
+ check_closed_event ! ( & nodes[ 0 ] , 1 , ClosureReason :: CommitmentTxConfirmed , false , [ nodes[ 1 ] . node. get_our_node_id( ) ] , 1_000_000 ) ;
1815
+ handle_bump_htlc_event ( & nodes[ 0 ] , 1 ) ;
1816
+ }
1817
+ let htlc_success_claim = if anchors {
1818
+ let mut txn = nodes[ 0 ] . tx_broadcaster . txn_broadcast ( ) ;
1819
+ assert_eq ! ( txn. len( ) , 1 ) ;
1820
+ check_spends ! ( txn[ 0 ] , as_revoked_txn[ 0 ] , coinbase_tx) ;
1821
+ txn. pop ( ) . unwrap ( )
1822
+ } else {
1823
+ as_revoked_txn[ 1 ] . clone ( )
1824
+ } ;
1825
+ mine_transaction ( & nodes[ 1 ] , & htlc_success_claim) ;
1776
1826
expect_payment_sent ( & nodes[ 1 ] , claimed_payment_preimage, None , true , false ) ;
1777
- let mut claim_txn_2 : Vec < _ > = nodes [ 1 ] . tx_broadcaster . txn_broadcasted . lock ( ) . unwrap ( ) . clone ( ) ;
1778
- 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 } ) ;
1827
+
1828
+ let mut claim_txn_2 = nodes [ 1 ] . tx_broadcaster . txn_broadcast ( ) ;
1779
1829
// Once B sees the HTLC-Success transaction it splits its claim transaction into two, though in
1780
1830
// theory it could re-aggregate the claims as well.
1781
1831
assert_eq ! ( claim_txn_2. len( ) , 2 ) ;
1782
- assert_eq ! ( claim_txn_2[ 0 ] . input. len( ) , 2 ) ;
1783
- check_spends ! ( claim_txn_2[ 0 ] , as_revoked_txn[ 0 ] ) ;
1784
- assert_eq ! ( claim_txn_2[ 1 ] . input. len( ) , 1 ) ;
1785
- check_spends ! ( claim_txn_2[ 1 ] , as_revoked_txn[ 1 ] ) ;
1832
+ if anchors {
1833
+ assert_eq ! ( claim_txn_2[ 0 ] . input. len( ) , 1 ) ;
1834
+ assert_eq ! ( claim_txn_2[ 0 ] . input[ 0 ] . previous_output. vout, 0 ) ;
1835
+ check_spends ! ( claim_txn_2[ 0 ] , & htlc_success_claim) ;
1836
+ assert_eq ! ( claim_txn_2[ 1 ] . input. len( ) , 1 ) ;
1837
+ assert_eq ! ( claim_txn_2[ 1 ] . input[ 0 ] . previous_output. vout, 3 ) ;
1838
+ check_spends ! ( claim_txn_2[ 1 ] , as_revoked_txn[ 0 ] ) ;
1839
+ } else {
1840
+ assert_eq ! ( claim_txn_2[ 0 ] . input. len( ) , 1 ) ;
1841
+ assert_eq ! ( claim_txn_2[ 0 ] . input[ 0 ] . previous_output. vout, 0 ) ;
1842
+ check_spends ! ( claim_txn_2[ 0 ] , as_revoked_txn[ 1 ] ) ;
1843
+ assert_eq ! ( claim_txn_2[ 1 ] . input. len( ) , 2 ) ;
1844
+ assert_eq ! ( claim_txn_2[ 1 ] . input[ 0 ] . previous_output. vout, 3 ) ;
1845
+ assert_eq ! ( claim_txn_2[ 1 ] . input[ 1 ] . previous_output. vout, 1 ) ;
1846
+ check_spends ! ( claim_txn_2[ 1 ] , as_revoked_txn[ 0 ] ) ;
1847
+ }
1786
1848
1787
1849
assert_eq ! ( sorted_vec( vec![ Balance :: ClaimableAwaitingConfirmations {
1788
1850
// to_remote output in A's revoked commitment
1789
1851
amount_satoshis: 100_000 - 4_000 - 3_000 ,
1790
1852
confirmation_height: to_remote_maturity,
1791
1853
} , Balance :: CounterpartyRevokedOutputClaimable {
1792
1854
// to_self output in A's revoked commitment
1793
- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1794
- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1855
+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
1795
1856
} , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
1796
1857
amount_satoshis: 4_000 ,
1797
1858
} , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 2
@@ -1807,8 +1868,7 @@ fn test_revoked_counterparty_htlc_tx_balances() {
1807
1868
1808
1869
assert_eq ! ( sorted_vec( vec![ Balance :: CounterpartyRevokedOutputClaimable {
1809
1870
// to_self output in A's revoked commitment
1810
- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1811
- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1871
+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
1812
1872
} , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
1813
1873
amount_satoshis: 4_000 ,
1814
1874
} , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 2
@@ -1819,47 +1879,75 @@ fn test_revoked_counterparty_htlc_tx_balances() {
1819
1879
} ] ) ,
1820
1880
sorted_vec( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
1821
1881
1822
- mine_transaction ( & nodes[ 1 ] , & claim_txn_2[ 1 ] ) ;
1882
+ mine_transaction ( & nodes[ 1 ] , & claim_txn_2[ 0 ] ) ;
1823
1883
let htlc_2_claim_maturity = nodes[ 1 ] . best_block_info ( ) . 1 + ANTI_REORG_DELAY - 1 ;
1824
1884
1825
1885
assert_eq ! ( sorted_vec( vec![ Balance :: CounterpartyRevokedOutputClaimable {
1826
1886
// to_self output in A's revoked commitment
1827
- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1828
- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1887
+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
1829
1888
} , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
1830
1889
amount_satoshis: 4_000 ,
1831
1890
} , Balance :: ClaimableAwaitingConfirmations { // HTLC 2
1832
- amount_satoshis: claim_txn_2[ 1 ] . output[ 0 ] . value,
1891
+ amount_satoshis: claim_txn_2[ 0 ] . output[ 0 ] . value,
1833
1892
confirmation_height: htlc_2_claim_maturity,
1834
1893
} ] ) ,
1835
1894
sorted_vec( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
1836
1895
1837
1896
connect_blocks ( & nodes[ 1 ] , 5 ) ;
1838
- test_spendable_output ( & nodes[ 1 ] , & claim_txn_2[ 1 ] , false ) ;
1897
+ test_spendable_output ( & nodes[ 1 ] , & claim_txn_2[ 0 ] , false ) ;
1839
1898
1840
1899
assert_eq ! ( sorted_vec( vec![ Balance :: CounterpartyRevokedOutputClaimable {
1841
1900
// to_self output in A's revoked commitment
1842
- amount_satoshis: 1_000_000 - 100_000 - chan_feerate *
1843
- ( channel:: commitment_tx_base_weight( & channel_type_features) + 2 * channel:: COMMITMENT_TX_WEIGHT_PER_HTLC ) / 1000 ,
1901
+ amount_satoshis: 1_000_000 - 100_000 - commitment_tx_fee - anchor_outputs_value,
1844
1902
} , Balance :: CounterpartyRevokedOutputClaimable { // HTLC 1
1845
1903
amount_satoshis: 4_000 ,
1846
1904
} ] ) ,
1847
1905
sorted_vec( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ) ;
1848
1906
1849
- mine_transaction ( & nodes[ 1 ] , & claim_txn_2[ 0 ] ) ;
1907
+ if anchors {
1908
+ mine_transactions ( & nodes[ 1 ] , & [ & claim_txn_2[ 1 ] , revoked_to_self_claim. as_ref ( ) . unwrap ( ) ] ) ;
1909
+ } else {
1910
+ mine_transaction ( & nodes[ 1 ] , & claim_txn_2[ 1 ] ) ;
1911
+ }
1850
1912
let rest_claim_maturity = nodes[ 1 ] . best_block_info ( ) . 1 + ANTI_REORG_DELAY - 1 ;
1851
1913
1852
- assert_eq ! ( vec![ Balance :: ClaimableAwaitingConfirmations {
1853
- amount_satoshis: claim_txn_2[ 0 ] . output[ 0 ] . value,
1854
- confirmation_height: rest_claim_maturity,
1855
- } ] ,
1856
- nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ;
1914
+ if anchors {
1915
+ assert_eq ! ( vec![ Balance :: ClaimableAwaitingConfirmations {
1916
+ amount_satoshis: claim_txn_2[ 1 ] . output[ 0 ] . value,
1917
+ confirmation_height: rest_claim_maturity,
1918
+ } , Balance :: ClaimableAwaitingConfirmations {
1919
+ amount_satoshis: revoked_to_self_claim. as_ref( ) . unwrap( ) . output[ 0 ] . value,
1920
+ confirmation_height: rest_claim_maturity,
1921
+ } ] ,
1922
+ nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ;
1923
+ } else {
1924
+ assert_eq ! ( vec![ Balance :: ClaimableAwaitingConfirmations {
1925
+ amount_satoshis: claim_txn_2[ 1 ] . output[ 0 ] . value,
1926
+ confirmation_height: rest_claim_maturity,
1927
+ } ] ,
1928
+ nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) ) ;
1929
+ }
1857
1930
1858
1931
assert ! ( nodes[ 1 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ; // We shouldn't fail the payment until we spend the output
1859
1932
1860
1933
connect_blocks ( & nodes[ 1 ] , 5 ) ;
1861
1934
expect_payment_failed ! ( nodes[ 1 ] , revoked_payment_hash, false ) ;
1862
- test_spendable_output ( & nodes[ 1 ] , & claim_txn_2[ 0 ] , false ) ;
1935
+ if anchors {
1936
+ let events = nodes[ 1 ] . chain_monitor . chain_monitor . get_and_clear_pending_events ( ) ;
1937
+ assert_eq ! ( events. len( ) , 2 ) ;
1938
+ for ( i, event) in events. into_iter ( ) . enumerate ( ) {
1939
+ if let Event :: SpendableOutputs { outputs, .. } = event {
1940
+ assert_eq ! ( outputs. len( ) , 1 ) ;
1941
+ let spend_tx = nodes[ 1 ] . keys_manager . backing . spend_spendable_outputs (
1942
+ & [ & outputs[ 0 ] ] , Vec :: new ( ) , Builder :: new ( ) . push_opcode ( opcodes:: all:: OP_RETURN ) . into_script ( ) ,
1943
+ 253 , None , & Secp256k1 :: new ( )
1944
+ ) . unwrap ( ) ;
1945
+ check_spends ! ( spend_tx, if i == 0 { & claim_txn_2[ 1 ] } else { revoked_to_self_claim. as_ref( ) . unwrap( ) } ) ;
1946
+ } else { panic ! ( ) ; }
1947
+ }
1948
+ } else {
1949
+ test_spendable_output ( & nodes[ 1 ] , & claim_txn_2[ 1 ] , false ) ;
1950
+ }
1863
1951
assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) . is_empty( ) ) ;
1864
1952
1865
1953
// Ensure that even if we connect more blocks, potentially replaying the entire chain if we're
@@ -1871,6 +1959,12 @@ fn test_revoked_counterparty_htlc_tx_balances() {
1871
1959
assert ! ( nodes[ 1 ] . chain_monitor. chain_monitor. get_monitor( funding_outpoint) . unwrap( ) . get_claimable_balances( ) . is_empty( ) ) ;
1872
1960
}
1873
1961
1962
+ #[ test]
1963
+ fn test_revoked_counterparty_aggregated_claims ( ) {
1964
+ do_test_revoked_counterparty_aggregated_claims ( false ) ;
1965
+ do_test_revoked_counterparty_aggregated_claims ( true ) ;
1966
+ }
1967
+
1874
1968
fn do_test_restored_packages_retry ( check_old_monitor_retries_after_upgrade : bool ) {
1875
1969
// Tests that we'll retry packages that were previously timelocked after we've restored them.
1876
1970
let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
0 commit comments