@@ -94,7 +94,7 @@ use stacks_signer::signerdb::{BlockInfo, BlockState, ExtraBlockInfo, SignerDb};
94
94
use super :: bitcoin_regtest:: BitcoinCoreController ;
95
95
use crate :: config:: { EventKeyType , EventObserverConfig , InitialBalance } ;
96
96
use crate :: nakamoto_node:: miner:: {
97
- TEST_BLOCK_ANNOUNCE_STALL , TEST_BROADCAST_STALL , TEST_MINE_STALL ,
97
+ TEST_BLOCK_ANNOUNCE_STALL , TEST_BROADCAST_STALL , TEST_MINE_STALL , TEST_SKIP_P2P_BROADCAST ,
98
98
} ;
99
99
use crate :: neon:: { Counters , RunLoopCounter } ;
100
100
use crate :: operations:: BurnchainOpSigner ;
@@ -8926,3 +8926,201 @@ fn v3_signer_api_endpoint() {
8926
8926
8927
8927
run_loop_thread. join ( ) . unwrap ( ) ;
8928
8928
}
8929
+
8930
+ #[ test]
8931
+ #[ ignore]
8932
+ /// This test spins up a nakamoto-neon node.
8933
+ /// It starts in Epoch 2.0, mines with `neon_node` to Epoch 3.0, and then switches
8934
+ /// to Nakamoto operation (activating pox-4 by submitting a stack-stx tx). The BootLoop
8935
+ /// struct handles the epoch-2/3 tear-down and spin-up.
8936
+ /// This test asserts that a long running transaction doesn't get mined,
8937
+ /// but that the stacks-node continues to make progress
8938
+ fn skip_mining_long_tx ( ) {
8939
+ if env:: var ( "BITCOIND_TEST" ) != Ok ( "1" . into ( ) ) {
8940
+ return ;
8941
+ }
8942
+
8943
+ let ( mut naka_conf, _miner_account) = naka_neon_integration_conf ( None ) ;
8944
+ let prom_bind = format ! ( "{}:{}" , "127.0.0.1" , 6000 ) ;
8945
+ naka_conf. node . prometheus_bind = Some ( prom_bind. clone ( ) ) ;
8946
+ naka_conf. miner . wait_on_interim_blocks = Duration :: from_secs ( 1 ) ;
8947
+ naka_conf. miner . nakamoto_attempt_time_ms = 5_000 ;
8948
+ let sender_1_sk = Secp256k1PrivateKey :: from_seed ( & [ 30 ] ) ;
8949
+ let sender_2_sk = Secp256k1PrivateKey :: from_seed ( & [ 31 ] ) ;
8950
+ // setup sender + recipient for a test stx transfer
8951
+ let sender_1_addr = tests:: to_addr ( & sender_1_sk) ;
8952
+ let sender_2_addr = tests:: to_addr ( & sender_2_sk) ;
8953
+ let send_amt = 1000 ;
8954
+ let send_fee = 180 ;
8955
+ naka_conf. add_initial_balance (
8956
+ PrincipalData :: from ( sender_1_addr. clone ( ) ) . to_string ( ) ,
8957
+ send_amt * 15 + send_fee * 15 ,
8958
+ ) ;
8959
+ naka_conf. add_initial_balance (
8960
+ PrincipalData :: from ( sender_2_addr. clone ( ) ) . to_string ( ) ,
8961
+ 10000 ,
8962
+ ) ;
8963
+ let sender_signer_sk = Secp256k1PrivateKey :: new ( ) ;
8964
+ let sender_signer_addr = tests:: to_addr ( & sender_signer_sk) ;
8965
+ let mut signers = TestSigners :: new ( vec ! [ sender_signer_sk. clone( ) ] ) ;
8966
+ naka_conf. add_initial_balance (
8967
+ PrincipalData :: from ( sender_signer_addr. clone ( ) ) . to_string ( ) ,
8968
+ 100000 ,
8969
+ ) ;
8970
+ let recipient = PrincipalData :: from ( StacksAddress :: burn_address ( false ) ) ;
8971
+ let stacker_sk = setup_stacker ( & mut naka_conf) ;
8972
+ let http_origin = format ! ( "http://{}" , & naka_conf. node. rpc_bind) ;
8973
+
8974
+ test_observer:: spawn ( ) ;
8975
+ let observer_port = test_observer:: EVENT_OBSERVER_PORT ;
8976
+ naka_conf. events_observers . insert ( EventObserverConfig {
8977
+ endpoint : format ! ( "localhost:{observer_port}" ) ,
8978
+ events_keys : vec ! [ EventKeyType :: AnyEvent ] ,
8979
+ } ) ;
8980
+
8981
+ let mut btcd_controller = BitcoinCoreController :: new ( naka_conf. clone ( ) ) ;
8982
+ btcd_controller
8983
+ . start_bitcoind ( )
8984
+ . expect ( "Failed starting bitcoind" ) ;
8985
+ let mut btc_regtest_controller = BitcoinRegtestController :: new ( naka_conf. clone ( ) , None ) ;
8986
+ btc_regtest_controller. bootstrap_chain ( 201 ) ;
8987
+
8988
+ let mut run_loop = boot_nakamoto:: BootRunLoop :: new ( naka_conf. clone ( ) ) . unwrap ( ) ;
8989
+ let run_loop_stopper = run_loop. get_termination_switch ( ) ;
8990
+ let Counters {
8991
+ blocks_processed,
8992
+ naka_submitted_commits : commits_submitted,
8993
+ naka_proposed_blocks : proposals_submitted,
8994
+ naka_mined_blocks : mined_naka_blocks,
8995
+ ..
8996
+ } = run_loop. counters ( ) ;
8997
+
8998
+ let coord_channel = run_loop. coordinator_channels ( ) ;
8999
+
9000
+ let run_loop_thread = thread:: spawn ( move || run_loop. start ( None , 0 ) ) ;
9001
+ wait_for_runloop ( & blocks_processed) ;
9002
+ boot_to_epoch_3 (
9003
+ & naka_conf,
9004
+ & blocks_processed,
9005
+ & [ stacker_sk] ,
9006
+ & [ sender_signer_sk] ,
9007
+ & mut Some ( & mut signers) ,
9008
+ & mut btc_regtest_controller,
9009
+ ) ;
9010
+
9011
+ info ! ( "Bootstrapped to Epoch-3.0 boundary, starting nakamoto miner" ) ;
9012
+
9013
+ let burnchain = naka_conf. get_burnchain ( ) ;
9014
+ let sortdb = burnchain. open_sortition_db ( true ) . unwrap ( ) ;
9015
+ let ( chainstate, _) = StacksChainState :: open (
9016
+ naka_conf. is_mainnet ( ) ,
9017
+ naka_conf. burnchain . chain_id ,
9018
+ & naka_conf. get_chainstate_path_str ( ) ,
9019
+ None ,
9020
+ )
9021
+ . unwrap ( ) ;
9022
+
9023
+ info ! ( "Nakamoto miner started..." ) ;
9024
+ blind_signer ( & naka_conf, & signers, proposals_submitted) ;
9025
+
9026
+ wait_for_first_naka_block_commit ( 60 , & commits_submitted) ;
9027
+
9028
+ // submit a long running TX and the transfer TX
9029
+ let input_list: Vec < _ > = ( 1 ..100u64 ) . into_iter ( ) . map ( |x| x. to_string ( ) ) . collect ( ) ;
9030
+ let input_list = input_list. join ( " " ) ;
9031
+
9032
+ // Mine a few nakamoto tenures with some interim blocks in them
9033
+ for i in 0 ..5 {
9034
+ let mined_before = mined_naka_blocks. load ( Ordering :: SeqCst ) ;
9035
+ next_block_and_mine_commit (
9036
+ & mut btc_regtest_controller,
9037
+ 60 ,
9038
+ & coord_channel,
9039
+ & commits_submitted,
9040
+ )
9041
+ . unwrap ( ) ;
9042
+
9043
+ if i == 0 {
9044
+ // we trigger the nakamoto miner to evaluate the long running transaction,
9045
+ // but we disable the block broadcast, so the tx doesn't end up included in a
9046
+ // confirmed block, even though its been evaluated.
9047
+ // once we've seen the miner increment the mined counter, we allow it to start
9048
+ // broadcasting (because at this point, any future blocks produced will skip the long
9049
+ // running tx because they have an estimate).
9050
+ wait_for ( 30 , || {
9051
+ Ok ( mined_naka_blocks. load ( Ordering :: SeqCst ) > mined_before)
9052
+ } )
9053
+ . unwrap ( ) ;
9054
+
9055
+ TEST_SKIP_P2P_BROADCAST . lock ( ) . unwrap ( ) . replace ( true ) ;
9056
+ let tx = make_contract_publish (
9057
+ & sender_2_sk,
9058
+ 0 ,
9059
+ 9_000 ,
9060
+ "large_contract" ,
9061
+ & format ! (
9062
+ "(define-constant INP_LIST (list {input_list}))
9063
+ (define-private (mapping-fn (input int))
9064
+ (begin (sha256 (sha256 (sha256 (sha256 (sha256 (sha256 (sha256 (sha256 (sha256 input)))))))))
9065
+ 0))
9066
+
9067
+ (define-private (mapping-fn-2 (input int))
9068
+ (begin (map mapping-fn INP_LIST) (map mapping-fn INP_LIST) (map mapping-fn INP_LIST) (map mapping-fn INP_LIST) 0))
9069
+
9070
+ (begin
9071
+ (map mapping-fn-2 INP_LIST))"
9072
+ ) ,
9073
+ ) ;
9074
+ submit_tx ( & http_origin, & tx) ;
9075
+
9076
+ wait_for ( 90 , || {
9077
+ Ok ( mined_naka_blocks. load ( Ordering :: SeqCst ) > mined_before + 1 )
9078
+ } )
9079
+ . unwrap ( ) ;
9080
+
9081
+ TEST_SKIP_P2P_BROADCAST . lock ( ) . unwrap ( ) . replace ( false ) ;
9082
+ } else {
9083
+ let transfer_tx =
9084
+ make_stacks_transfer ( & sender_1_sk, i - 1 , send_fee, & recipient, send_amt) ;
9085
+ submit_tx ( & http_origin, & transfer_tx) ;
9086
+
9087
+ wait_for ( 30 , || {
9088
+ let cur_sender_nonce = get_account ( & http_origin, & sender_1_addr) . nonce ;
9089
+ Ok ( cur_sender_nonce >= i)
9090
+ } )
9091
+ . unwrap ( ) ;
9092
+ }
9093
+ }
9094
+
9095
+ let sender_1_nonce = get_account ( & http_origin, & sender_1_addr) . nonce ;
9096
+ let sender_2_nonce = get_account ( & http_origin, & sender_2_addr) . nonce ;
9097
+
9098
+ // load the chain tip, and assert that it is a nakamoto block and at least 30 blocks have advanced in epoch 3
9099
+ let tip = NakamotoChainState :: get_canonical_block_header ( chainstate. db ( ) , & sortdb)
9100
+ . unwrap ( )
9101
+ . unwrap ( ) ;
9102
+ info ! (
9103
+ "Latest tip" ;
9104
+ "height" => tip. stacks_block_height,
9105
+ "is_nakamoto" => tip. anchored_header. as_stacks_nakamoto( ) . is_some( ) ,
9106
+ "sender_1_nonce" => sender_1_nonce,
9107
+ "sender_2_nonce" => sender_2_nonce,
9108
+ ) ;
9109
+
9110
+ assert_eq ! ( sender_2_nonce, 0 ) ;
9111
+ assert_eq ! ( sender_1_nonce, 4 ) ;
9112
+
9113
+ // Check that we aren't missing burn blocks
9114
+ let bhh = u64:: from ( tip. burn_header_height ) ;
9115
+ test_observer:: contains_burn_block_range ( 220 ..=bhh) . unwrap ( ) ;
9116
+
9117
+ check_nakamoto_empty_block_heuristics ( ) ;
9118
+
9119
+ coord_channel
9120
+ . lock ( )
9121
+ . expect ( "Mutex poisoned" )
9122
+ . stop_chains_coordinator ( ) ;
9123
+ run_loop_stopper. store ( false , Ordering :: SeqCst ) ;
9124
+
9125
+ run_loop_thread. join ( ) . unwrap ( ) ;
9126
+ }
0 commit comments