@@ -1806,8 +1806,8 @@ fn miner_forking() {
1806
1806
1807
1807
let mut run_loop_2 = boot_nakamoto:: BootRunLoop :: new ( conf_node_2. clone ( ) ) . unwrap ( ) ;
1808
1808
let Counters {
1809
- naka_skip_commit_op,
1810
- naka_submitted_commits : second_miner_commits_submitted ,
1809
+ naka_skip_commit_op : skip_commit_op_rl2 ,
1810
+ naka_submitted_commits : commits_submitted_rl2 ,
1811
1811
..
1812
1812
} = run_loop_2. counters ( ) ;
1813
1813
let _run_loop_2_thread = thread:: Builder :: new ( )
@@ -1828,149 +1828,256 @@ fn miner_forking() {
1828
1828
} )
1829
1829
. expect ( "Timed out waiting for boostrapped node to catch up to the miner" ) ;
1830
1830
1831
+ let commits_submitted_rl1 = signer_test. running_nodes . commits_submitted . clone ( ) ;
1832
+ let skip_commit_op_rl1 = signer_test
1833
+ . running_nodes
1834
+ . nakamoto_test_skip_commit_op
1835
+ . clone ( ) ;
1836
+
1831
1837
let pre_nakamoto_peer_1_height = get_chain_info ( & conf) . stacks_tip_height ;
1832
1838
1833
- naka_skip_commit_op. set ( true ) ;
1839
+ let mining_pk_1 = StacksPublicKey :: from_private ( & conf. miner . mining_key . unwrap ( ) ) ;
1840
+ let mining_pk_2 = StacksPublicKey :: from_private ( & conf_node_2. miner . mining_key . unwrap ( ) ) ;
1841
+ let mining_pkh_1 = Hash160 :: from_node_public_key ( & mining_pk_1) ;
1842
+ let mining_pkh_2 = Hash160 :: from_node_public_key ( & mining_pk_2) ;
1843
+ debug ! ( "The mining key for miner 1 is {mining_pkh_1}" ) ;
1844
+ debug ! ( "The mining key for miner 2 is {mining_pkh_2}" ) ;
1845
+
1846
+ let sortdb = conf. get_burnchain ( ) . open_sortition_db ( true ) . unwrap ( ) ;
1847
+ let get_burn_height = || {
1848
+ SortitionDB :: get_canonical_burn_chain_tip ( sortdb. conn ( ) )
1849
+ . unwrap ( )
1850
+ . block_height
1851
+ } ;
1834
1852
info ! ( "------------------------- Reached Epoch 3.0 -------------------------" ) ;
1835
1853
1836
- let mut sortitions_seen = Vec :: new ( ) ;
1837
- let run_sortition = || {
1838
- info ! ( "Pausing stacks block proposal to force an empty tenure commit from RL2" ) ;
1839
- TEST_BROADCAST_STALL . lock ( ) . unwrap ( ) . replace ( true ) ;
1854
+ info ! ( "Pausing both miners' block commit submissions" ) ;
1855
+ skip_commit_op_rl1. set ( true ) ;
1856
+ skip_commit_op_rl2. set ( true ) ;
1840
1857
1841
- let rl2_commits_before = second_miner_commits_submitted. load ( Ordering :: SeqCst ) ;
1842
- let rl1_commits_before = signer_test
1843
- . running_nodes
1844
- . commits_submitted
1845
- . load ( Ordering :: SeqCst ) ;
1858
+ info ! ( "Flushing any pending commits to enable custom winner selection" ) ;
1859
+ let burn_height_before = get_burn_height ( ) ;
1860
+ next_block_and (
1861
+ & mut signer_test. running_nodes . btc_regtest_controller ,
1862
+ 30 ,
1863
+ || Ok ( get_burn_height ( ) > burn_height_before) ,
1864
+ )
1865
+ . unwrap ( ) ;
1846
1866
1847
- signer_test
1848
- . running_nodes
1849
- . btc_regtest_controller
1850
- . build_next_block ( 1 ) ;
1851
- naka_skip_commit_op. set ( false ) ;
1867
+ info ! ( "------------------------- RL1 Wins Sortition -------------------------" ) ;
1868
+ info ! ( "Pausing stacks block proposal to force an empty tenure commit from RL2" ) ;
1869
+ TEST_BROADCAST_STALL . lock ( ) . unwrap ( ) . replace ( true ) ;
1870
+ let rl1_commits_before = commits_submitted_rl1. load ( Ordering :: SeqCst ) ;
1852
1871
1853
- // wait until a commit is submitted by run_loop_2
1854
- wait_for ( 60 , || {
1855
- let commits_count = second_miner_commits_submitted. load ( Ordering :: SeqCst ) ;
1856
- Ok ( commits_count > rl2_commits_before)
1857
- } )
1872
+ info ! ( "Unpausing commits from RL1" ) ;
1873
+ skip_commit_op_rl1. set ( false ) ;
1874
+
1875
+ info ! ( "Waiting for commits from RL1" ) ;
1876
+ wait_for ( 30 , || {
1877
+ Ok ( commits_submitted_rl1. load ( Ordering :: SeqCst ) > rl1_commits_before)
1878
+ } )
1879
+ . expect ( "Timed out waiting for miner 1 to submit a commit op" ) ;
1880
+
1881
+ info ! ( "Pausing commits from RL1" ) ;
1882
+ skip_commit_op_rl1. set ( true ) ;
1883
+
1884
+ let burn_height_before = get_burn_height ( ) ;
1885
+ info ! ( "Mine RL1 Tenure" ) ;
1886
+ next_block_and (
1887
+ & mut signer_test. running_nodes . btc_regtest_controller ,
1888
+ 30 ,
1889
+ || Ok ( get_burn_height ( ) > burn_height_before) ,
1890
+ )
1891
+ . unwrap ( ) ;
1892
+
1893
+ // fetch the current sortition info
1894
+ let sortdb = conf. get_burnchain ( ) . open_sortition_db ( true ) . unwrap ( ) ;
1895
+ let tip = SortitionDB :: get_canonical_burn_chain_tip ( sortdb. conn ( ) ) . unwrap ( ) ;
1896
+ // make sure the tenure was won by RL1
1897
+ assert ! ( tip. sortition, "No sortition was won" ) ;
1898
+ assert_eq ! (
1899
+ tip. miner_pk_hash. unwrap( ) ,
1900
+ mining_pkh_1,
1901
+ "RL1 did not win the sortition"
1902
+ ) ;
1903
+
1904
+ info ! (
1905
+ "------------------------- RL2 Wins Sortition With Outdated View -------------------------"
1906
+ ) ;
1907
+ let rl2_commits_before = commits_submitted_rl2. load ( Ordering :: SeqCst ) ;
1908
+
1909
+ info ! ( "Unpausing commits from RL2" ) ;
1910
+ skip_commit_op_rl2. set ( false ) ;
1911
+
1912
+ info ! ( "Waiting for commits from RL2" ) ;
1913
+ wait_for ( 30 , || {
1914
+ Ok ( commits_submitted_rl2. load ( Ordering :: SeqCst ) > rl2_commits_before)
1915
+ } )
1916
+ . expect ( "Timed out waiting for miner 1 to submit a commit op" ) ;
1917
+
1918
+ info ! ( "Pausing commits from RL2" ) ;
1919
+ skip_commit_op_rl2. set ( true ) ;
1920
+
1921
+ // unblock block mining
1922
+ let blocks_len = test_observer:: get_blocks ( ) . len ( ) ;
1923
+ TEST_BROADCAST_STALL . lock ( ) . unwrap ( ) . replace ( false ) ;
1924
+
1925
+ // Wait for the block to be broadcasted and processed
1926
+ wait_for ( 30 , || Ok ( test_observer:: get_blocks ( ) . len ( ) > blocks_len) )
1927
+ . expect ( "Timed out waiting for a block to be processed" ) ;
1928
+
1929
+ // sleep for 2*first_proposal_burn_block_timing to prevent the block timing from allowing a fork by the signer set
1930
+ thread:: sleep ( Duration :: from_secs ( first_proposal_burn_block_timing * 2 ) ) ;
1931
+
1932
+ let nakamoto_headers: HashMap < _ , _ > = get_nakamoto_headers ( & conf)
1933
+ . into_iter ( )
1934
+ . map ( |header| {
1935
+ info ! ( "Nakamoto block" ; "height" => header. stacks_block_height, "consensus_hash" => %header. consensus_hash, "last_sortition_hash" => %tip. consensus_hash) ;
1936
+ ( header. consensus_hash , header)
1937
+ } )
1938
+ . collect ( ) ;
1939
+
1940
+ let header_info = nakamoto_headers. get ( & tip. consensus_hash ) . unwrap ( ) ;
1941
+ let header = header_info
1942
+ . anchored_header
1943
+ . as_stacks_nakamoto ( )
1944
+ . unwrap ( )
1945
+ . clone ( ) ;
1946
+
1947
+ mining_pk_1
1948
+ . verify (
1949
+ header. miner_signature_hash ( ) . as_bytes ( ) ,
1950
+ & header. miner_signature ,
1951
+ )
1858
1952
. unwrap ( ) ;
1859
- // wait until a commit is submitted by run_loop_1
1860
- wait_for ( 60 , || {
1861
- let commits_count = signer_test
1862
- . running_nodes
1863
- . commits_submitted
1864
- . load ( Ordering :: SeqCst ) ;
1865
- Ok ( commits_count > rl1_commits_before)
1953
+
1954
+ let blocks_len = test_observer:: get_blocks ( ) . len ( ) ;
1955
+ let burn_height_before = get_burn_height ( ) ;
1956
+ info ! ( "Mine RL2 Tenure" ) ;
1957
+ next_block_and (
1958
+ & mut signer_test. running_nodes . btc_regtest_controller ,
1959
+ 30 ,
1960
+ || Ok ( get_burn_height ( ) > burn_height_before) ,
1961
+ )
1962
+ . unwrap ( ) ;
1963
+
1964
+ // Ensure that RL2 doesn't produce a valid block
1965
+ assert ! (
1966
+ wait_for( 60 , || Ok ( test_observer:: get_blocks( ) . len( ) > blocks_len) ) . is_err( ) ,
1967
+ "RL2 produced a block"
1968
+ ) ;
1969
+
1970
+ // fetch the current sortition info
1971
+ let tip = SortitionDB :: get_canonical_burn_chain_tip ( sortdb. conn ( ) ) . unwrap ( ) ;
1972
+ // make sure the tenure was won by RL2
1973
+ assert ! ( tip. sortition, "No sortition was won" ) ;
1974
+ assert_eq ! (
1975
+ tip. miner_pk_hash. unwrap( ) ,
1976
+ mining_pkh_2,
1977
+ "RL2 did not win the sortition"
1978
+ ) ;
1979
+
1980
+ let nakamoto_headers: HashMap < _ , _ > = get_nakamoto_headers ( & conf)
1981
+ . into_iter ( )
1982
+ . map ( |header| {
1983
+ info ! ( "Nakamoto block" ; "height" => header. stacks_block_height, "consensus_hash" => %header. consensus_hash, "last_sortition_hash" => %tip. consensus_hash) ;
1984
+ ( header. consensus_hash , header)
1866
1985
} )
1867
- . unwrap ( ) ;
1986
+ . collect ( ) ;
1987
+ assert ! ( !nakamoto_headers. contains_key( & tip. consensus_hash) ) ;
1868
1988
1869
- // fetch the current sortition info
1870
- let sortdb = conf. get_burnchain ( ) . open_sortition_db ( true ) . unwrap ( ) ;
1871
- let sort_tip = SortitionDB :: get_canonical_burn_chain_tip ( sortdb. conn ( ) ) . unwrap ( ) ;
1989
+ info ! ( "------------------------- RL1 RBFs its Own Commit -------------------------" ) ;
1990
+ info ! ( "Pausing stacks block proposal to test RBF capability" ) ;
1991
+ TEST_BROADCAST_STALL . lock ( ) . unwrap ( ) . replace ( true ) ;
1992
+ let rl1_commits_before = commits_submitted_rl1. load ( Ordering :: SeqCst ) ;
1872
1993
1873
- // block commits from RL2 -- this will block until the start of the next iteration
1874
- // in this loop.
1875
- naka_skip_commit_op. set ( true ) ;
1876
- // ensure RL1 performs an RBF after unblock block broadcast
1877
- let rl1_commits_before = signer_test
1878
- . running_nodes
1879
- . commits_submitted
1880
- . load ( Ordering :: SeqCst ) ;
1994
+ info ! ( "Unpausing commits from RL1" ) ;
1995
+ skip_commit_op_rl1. set ( false ) ;
1881
1996
1882
- // unblock block mining
1883
- let blocks_len = test_observer:: get_blocks ( ) . len ( ) ;
1884
- TEST_BROADCAST_STALL . lock ( ) . unwrap ( ) . replace ( false ) ;
1997
+ info ! ( "Waiting for commits from RL1" ) ;
1998
+ wait_for ( 30 , || {
1999
+ Ok ( commits_submitted_rl1. load ( Ordering :: SeqCst ) > rl1_commits_before)
2000
+ } )
2001
+ . expect ( "Timed out waiting for miner 1 to submit a commit op" ) ;
1885
2002
1886
- // wait for a block to be processed (or timeout!)
1887
- if wait_for ( 60 , || Ok ( test_observer:: get_blocks ( ) . len ( ) > blocks_len) ) . is_err ( ) {
1888
- info ! ( "Timeout waiting for a block process: assuming this is because RL2 attempted to fork-- will check at end of test" ) ;
1889
- return ( sort_tip, false ) ;
1890
- }
2003
+ info ! ( "Pausing commits from RL1" ) ;
2004
+ skip_commit_op_rl1. set ( true ) ;
1891
2005
1892
- info ! ( "Nakamoto block processed, waiting for commit from RL1" ) ;
2006
+ let burn_height_before = get_burn_height ( ) ;
2007
+ info ! ( "Mine RL1 Tenure" ) ;
2008
+ next_block_and (
2009
+ & mut signer_test. running_nodes . btc_regtest_controller ,
2010
+ 30 ,
2011
+ || Ok ( get_burn_height ( ) > burn_height_before) ,
2012
+ )
2013
+ . unwrap ( ) ;
1893
2014
1894
- // wait for a commit from RL1
1895
- wait_for ( 60 , || {
1896
- let commits_count = signer_test
1897
- . running_nodes
1898
- . commits_submitted
1899
- . load ( Ordering :: SeqCst ) ;
1900
- Ok ( commits_count > rl1_commits_before)
1901
- } )
1902
- . unwrap ( ) ;
2015
+ let rl1_commits_before = commits_submitted_rl1. load ( Ordering :: SeqCst ) ;
1903
2016
1904
- // sleep for 2*first_proposal_burn_block_timing to prevent the block timing from allowing a fork by the signer set
1905
- thread:: sleep ( Duration :: from_secs ( first_proposal_burn_block_timing * 2 ) ) ;
1906
- ( sort_tip, true )
1907
- } ;
2017
+ info ! ( "Unpausing commits from RL1" ) ;
2018
+ skip_commit_op_rl1. set ( false ) ;
1908
2019
1909
- let mut won_by_miner_2_but_no_tenure = false ;
1910
- let mut won_by_miner_1_after_tenureless_miner_2 = false ;
1911
- let miner_1_pk = StacksPublicKey :: from_private ( conf. miner . mining_key . as_ref ( ) . unwrap ( ) ) ;
1912
- // miner 2 is expected to be valid iff:
1913
- // (a) its the first nakamoto tenure
1914
- // (b) the prior sortition didn't have a tenure (because by this time RL2 will have up-to-date block processing)
1915
- let mut expects_miner_2_to_be_valid = true ;
1916
- // due to the random nature of mining sortitions, the way this test is structured
1917
- // is that keeps track of two scenarios that we want to cover, and once enough sortitions
1918
- // have been produced to cover those scenarios, it stops and checks the results at the end.
1919
- while !( won_by_miner_2_but_no_tenure && won_by_miner_1_after_tenureless_miner_2) {
1920
- let nmb_sortitions_seen = sortitions_seen. len ( ) ;
1921
- assert ! ( max_sortitions >= nmb_sortitions_seen, "Produced {nmb_sortitions_seen} sortitions, but didn't cover the test scenarios, aborting" ) ;
1922
- let ( sortition_data, had_tenure) = run_sortition ( ) ;
1923
- sortitions_seen. push ( ( sortition_data. clone ( ) , had_tenure) ) ;
1924
-
1925
- let nakamoto_headers: HashMap < _ , _ > = get_nakamoto_headers ( & conf)
1926
- . into_iter ( )
1927
- . map ( |header| {
1928
- info ! ( "Nakamoto block" ; "height" => header. stacks_block_height, "consensus_hash" => %header. consensus_hash, "last_sortition_hash" => %sortition_data. consensus_hash) ;
1929
- ( header. consensus_hash , header)
1930
- } )
1931
- . collect ( ) ;
2020
+ info ! ( "Waiting for commits from RL1" ) ;
2021
+ wait_for ( 30 , || {
2022
+ Ok ( commits_submitted_rl1. load ( Ordering :: SeqCst ) > rl1_commits_before)
2023
+ } )
2024
+ . expect ( "Timed out waiting for miner 1 to submit a commit op" ) ;
1932
2025
1933
- if had_tenure {
1934
- let header_info = nakamoto_headers
1935
- . get ( & sortition_data. consensus_hash )
1936
- . unwrap ( ) ;
1937
- let header = header_info
1938
- . anchored_header
1939
- . as_stacks_nakamoto ( )
1940
- . unwrap ( )
1941
- . clone ( ) ;
1942
- let mined_by_miner_1 = miner_1_pk
1943
- . verify (
1944
- header. miner_signature_hash ( ) . as_bytes ( ) ,
1945
- & header. miner_signature ,
1946
- )
1947
- . unwrap ( ) ;
2026
+ let rl1_commits_before = commits_submitted_rl1. load ( Ordering :: SeqCst ) ;
2027
+ // unblock block mining
2028
+ let blocks_len = test_observer:: get_blocks ( ) . len ( ) ;
2029
+ TEST_BROADCAST_STALL . lock ( ) . unwrap ( ) . replace ( false ) ;
1948
2030
1949
- info ! ( "Block check" ;
1950
- "height" => header. chain_length,
1951
- "consensus_hash" => %header. consensus_hash,
1952
- "block_hash" => %header. block_hash( ) ,
1953
- "stacks_block_id" => %header. block_id( ) ,
1954
- "mined_by_miner_1?" => mined_by_miner_1,
1955
- "expects_miner_2_to_be_valid?" => expects_miner_2_to_be_valid) ;
1956
- if !mined_by_miner_1 {
1957
- assert ! ( expects_miner_2_to_be_valid, "If a block was produced by miner 2, we should have expected miner 2 to be valid" ) ;
1958
- } else if won_by_miner_2_but_no_tenure {
1959
- // the tenure was won by miner 1, they produced a block, and this follows a tenure that miner 2 won but couldn't
1960
- // mine during because they tried to fork.
1961
- won_by_miner_1_after_tenureless_miner_2 = true ;
1962
- }
2031
+ // Wait for the block to be broadcasted and processed
2032
+ wait_for ( 30 , || Ok ( test_observer:: get_blocks ( ) . len ( ) > blocks_len) )
2033
+ . expect ( "Timed out waiting for a block to be processed" ) ;
1963
2034
1964
- // even if it was mined by miner 2, their next block commit should be invalid!
1965
- expects_miner_2_to_be_valid = false ;
1966
- } else {
1967
- info ! ( "Sortition without tenure" ; "expects_miner_2_to_be_valid?" => expects_miner_2_to_be_valid) ;
1968
- assert ! ( !nakamoto_headers. contains_key( & sortition_data. consensus_hash) ) ;
1969
- assert ! ( !expects_miner_2_to_be_valid, "If no blocks were produced in the tenure, it should be because miner 2 committed to a fork" ) ;
1970
- won_by_miner_2_but_no_tenure = true ;
1971
- expects_miner_2_to_be_valid = true ;
1972
- }
1973
- }
2035
+ info ! ( "Ensure that RL1 performs an RBF after unblocking block broadcast" ) ;
2036
+ wait_for ( 30 , || {
2037
+ Ok ( commits_submitted_rl1. load ( Ordering :: SeqCst ) > rl1_commits_before)
2038
+ } )
2039
+ . expect ( "Timed out waiting for miner 1 to RBF its old commit op" ) ;
2040
+
2041
+ info ! ( "Mine RL1 Tenure" ) ;
2042
+ signer_test
2043
+ . running_nodes
2044
+ . btc_regtest_controller
2045
+ . build_next_block ( 1 ) ;
2046
+
2047
+ // fetch the current sortition info
2048
+ let sortdb = conf. get_burnchain ( ) . open_sortition_db ( true ) . unwrap ( ) ;
2049
+ let tip = SortitionDB :: get_canonical_burn_chain_tip ( sortdb. conn ( ) ) . unwrap ( ) ;
2050
+ // make sure the tenure was won by RL1
2051
+ assert ! ( tip. sortition, "No sortition was won" ) ;
2052
+ assert_eq ! (
2053
+ tip. miner_pk_hash. unwrap( ) ,
2054
+ mining_pkh_1,
2055
+ "RL1 did not win the sortition"
2056
+ ) ;
2057
+
2058
+ let nakamoto_headers: HashMap < _ , _ > = get_nakamoto_headers ( & conf)
2059
+ . into_iter ( )
2060
+ . map ( |header| {
2061
+ info ! ( "Nakamoto block" ; "height" => header. stacks_block_height, "consensus_hash" => %header. consensus_hash, "last_sortition_hash" => %tip. consensus_hash) ;
2062
+ ( header. consensus_hash , header)
2063
+ } )
2064
+ . collect ( ) ;
2065
+
2066
+ let header_info = nakamoto_headers. get ( & tip. consensus_hash ) . unwrap ( ) ;
2067
+ let header = header_info
2068
+ . anchored_header
2069
+ . as_stacks_nakamoto ( )
2070
+ . unwrap ( )
2071
+ . clone ( ) ;
2072
+
2073
+ mining_pk_1
2074
+ . verify (
2075
+ header. miner_signature_hash ( ) . as_bytes ( ) ,
2076
+ & header. miner_signature ,
2077
+ )
2078
+ . unwrap ( ) ;
2079
+
2080
+ info ! ( "------------------------- Verify Peer Data -------------------------" ) ;
1974
2081
1975
2082
let peer_1_height = get_chain_info ( & conf) . stacks_tip_height ;
1976
2083
let peer_2_height = get_chain_info ( & conf_node_2) . stacks_tip_height ;
0 commit comments