@@ -13502,3 +13502,357 @@ fn test_sip_031_last_phase_out_of_epoch() {
1350213502
1350313503 run_loop_thread. join ( ) . unwrap ( ) ;
1350413504}
13505+
13506+ /// Test SIP-031 last phase per-tenure-mint-and-transfer
13507+ ///
13508+ /// - check epoch 3.2 is active
13509+ /// - check minting event on coinbase and boot contract transfer for the first (and only the first) block of a tenure
13510+ /// - ensure liquidity is updated accordingly to SIP-031
13511+ #[ test]
13512+ #[ ignore]
13513+ #[ serial]
13514+ fn test_sip_031_last_phase_coinbase_matches_activation ( ) {
13515+ if env:: var ( "BITCOIND_TEST" ) != Ok ( "1" . into ( ) ) {
13516+ return ;
13517+ }
13518+
13519+ let ( mut naka_conf, _miner_account) = naka_neon_integration_conf ( None ) ;
13520+ naka_conf. node . pox_sync_sample_secs = 180 ;
13521+ naka_conf. burnchain . max_rbf = 10_000_000 ;
13522+
13523+ let sender_sk = Secp256k1PrivateKey :: random ( ) ;
13524+ let sender_signer_sk = Secp256k1PrivateKey :: random ( ) ;
13525+ let sender_signer_addr = tests:: to_addr ( & sender_signer_sk) ;
13526+ let mut signers = TestSigners :: new ( vec ! [ sender_signer_sk] ) ;
13527+ // let's assume funds for 200 tenures
13528+ let tenure_count = 200 ;
13529+ let inter_blocks_per_tenure = 9 ;
13530+ // setup sender + recipient for some test stx transfers
13531+ // these are necessary for the interim blocks to get mined at all
13532+ let sender_addr = tests:: to_addr ( & sender_sk) ;
13533+ let send_amt = 100 ;
13534+ let send_fee = 180 ;
13535+ naka_conf. add_initial_balance (
13536+ PrincipalData :: from ( sender_addr) . to_string ( ) ,
13537+ ( send_amt + send_fee) * tenure_count * inter_blocks_per_tenure,
13538+ ) ;
13539+ naka_conf. add_initial_balance ( PrincipalData :: from ( sender_signer_addr) . to_string ( ) , 100000 ) ;
13540+ let stacker_sk = setup_stacker ( & mut naka_conf) ;
13541+
13542+ let epoch32_start_height =
13543+ naka_conf. burnchain . epochs . clone ( ) . unwrap ( ) [ StacksEpochId :: Epoch32 ] . start_height ;
13544+
13545+ set_test_sip_031_emission_schedule ( Some ( vec ! [ SIP031EmissionInterval {
13546+ amount: 100_000 ,
13547+ start_height: epoch32_start_height,
13548+ } ] ) ) ;
13549+
13550+ test_observer:: spawn ( ) ;
13551+ test_observer:: register_any ( & mut naka_conf) ;
13552+
13553+ let mut btcd_controller = BitcoinCoreController :: new ( naka_conf. clone ( ) ) ;
13554+ btcd_controller
13555+ . start_bitcoind ( )
13556+ . expect ( "Failed starting bitcoind" ) ;
13557+ let mut btc_regtest_controller = BitcoinRegtestController :: new ( naka_conf. clone ( ) , None ) ;
13558+ btc_regtest_controller. bootstrap_chain ( 201 ) ;
13559+
13560+ let mut run_loop = boot_nakamoto:: BootRunLoop :: new ( naka_conf. clone ( ) ) . unwrap ( ) ;
13561+ let run_loop_stopper = run_loop. get_termination_switch ( ) ;
13562+ let Counters {
13563+ blocks_processed,
13564+ naka_submitted_commits : commits_submitted,
13565+ ..
13566+ } = run_loop. counters ( ) ;
13567+ let counters = run_loop. counters ( ) ;
13568+
13569+ let coord_channel = run_loop. coordinator_channels ( ) ;
13570+
13571+ let run_loop_thread = thread:: Builder :: new ( )
13572+ . name ( "run_loop" . into ( ) )
13573+ . spawn ( move || run_loop. start ( None , 0 ) )
13574+ . unwrap ( ) ;
13575+ wait_for_runloop ( & blocks_processed) ;
13576+ boot_to_epoch_3 (
13577+ & naka_conf,
13578+ & blocks_processed,
13579+ & [ stacker_sk] ,
13580+ & [ sender_signer_sk] ,
13581+ & mut Some ( & mut signers) ,
13582+ & mut btc_regtest_controller,
13583+ ) ;
13584+
13585+ info ! ( "Bootstrapped to Epoch-3.0 boundary, starting nakamoto miner" ) ;
13586+
13587+ let burnchain = naka_conf. get_burnchain ( ) ;
13588+ let sortdb = burnchain. open_sortition_db ( true ) . unwrap ( ) ;
13589+ let ( mut chainstate, _) = StacksChainState :: open (
13590+ naka_conf. is_mainnet ( ) ,
13591+ naka_conf. burnchain . chain_id ,
13592+ & naka_conf. get_chainstate_path_str ( ) ,
13593+ None ,
13594+ )
13595+ . unwrap ( ) ;
13596+
13597+ info ! ( "Nakamoto miner started..." ) ;
13598+ blind_signer ( & naka_conf, & signers, & counters) ;
13599+
13600+ wait_for_first_naka_block_commit ( 60 , & commits_submitted) ;
13601+
13602+ // mine until epoch 3.2 height
13603+ loop {
13604+ let commits_before = commits_submitted. load ( Ordering :: SeqCst ) ;
13605+ next_block_and_process_new_stacks_block ( & mut btc_regtest_controller, 60 , & coord_channel)
13606+ . unwrap ( ) ;
13607+ wait_for ( 20 , || {
13608+ Ok ( commits_submitted. load ( Ordering :: SeqCst ) > commits_before)
13609+ } )
13610+ . unwrap ( ) ;
13611+
13612+ let node_info = get_chain_info_opt ( & naka_conf) . unwrap ( ) ;
13613+ if node_info. burn_block_height >= epoch32_start_height {
13614+ break ;
13615+ }
13616+ }
13617+
13618+ info ! (
13619+ "Nakamoto miner has advanced to bitcoin height {}" ,
13620+ get_chain_info_opt( & naka_conf) . unwrap( ) . burn_block_height
13621+ ) ;
13622+
13623+ let latest_stacks_block_id = get_latest_block_proposal ( & naka_conf, & sortdb)
13624+ . unwrap ( )
13625+ . 0
13626+ . block_id ( ) ;
13627+
13628+ // check if sip-031 boot contract has a balance of 200_000_000 STX + coinbase-mint-and-transfer
13629+ let sip_031_boot_contract_balance = chainstate. with_read_only_clarity_tx (
13630+ & sortdb
13631+ . index_handle_at_block ( & chainstate, & latest_stacks_block_id)
13632+ . unwrap ( ) ,
13633+ & latest_stacks_block_id,
13634+ |conn| {
13635+ conn. with_clarity_db_readonly ( |db| {
13636+ db. get_account_stx_balance ( & PrincipalData :: Contract ( boot_code_id (
13637+ SIP_031_NAME ,
13638+ naka_conf. is_mainnet ( ) ,
13639+ ) ) )
13640+ } )
13641+ } ,
13642+ ) ;
13643+
13644+ assert_eq ! (
13645+ sip_031_boot_contract_balance,
13646+ Some ( Ok ( STXBalance :: Unlocked {
13647+ amount: SIP_031_INITIAL_MINT + 100_000
13648+ } ) )
13649+ ) ;
13650+
13651+ // check the mint event has been attached to the coinbase
13652+ for block in test_observer:: get_blocks ( ) {
13653+ let burn_block_height = block. get ( "burn_block_height" ) . unwrap ( ) . as_u64 ( ) . unwrap ( ) ;
13654+
13655+ if burn_block_height == epoch32_start_height {
13656+ // check for mint event for the SIP-031 coinbase minting events (activation mint and coinbase one)
13657+ let events = block. get ( "events" ) . unwrap ( ) . as_array ( ) . unwrap ( ) ;
13658+ for event in events {
13659+ if let Some ( mint_event) = event. get ( "stx_mint_event" ) {
13660+ if mint_event. get ( "recipient" ) . unwrap ( ) . as_str ( ) . unwrap ( )
13661+ == boot_code_id ( SIP_031_NAME , naka_conf. is_mainnet ( ) ) . to_string ( )
13662+ {
13663+ let minted_amount = mint_event
13664+ . get ( "amount" )
13665+ . unwrap ( )
13666+ . as_str ( )
13667+ . unwrap ( )
13668+ . parse :: < u128 > ( )
13669+ . unwrap ( ) ;
13670+ if minted_amount == SIP_031_INITIAL_MINT {
13671+ let boot_contract_deploy_tx = block
13672+ . get ( "transactions" )
13673+ . unwrap ( )
13674+ . as_array ( )
13675+ . unwrap ( )
13676+ . get ( 0 )
13677+ . unwrap ( )
13678+ . get ( "txid" )
13679+ . unwrap ( )
13680+ . as_str ( )
13681+ . unwrap ( ) ;
13682+
13683+ // check the event txid is mapped to the boot_contract_deploy
13684+ assert_eq ! (
13685+ event. get( "txid" ) . unwrap( ) . as_str( ) . unwrap( ) ,
13686+ boot_contract_deploy_tx
13687+ ) ;
13688+ } else {
13689+ let coinbase_txid = block
13690+ . get ( "transactions" )
13691+ . unwrap ( )
13692+ . as_array ( )
13693+ . unwrap ( )
13694+ . get ( 2 )
13695+ . unwrap ( )
13696+ . get ( "txid" )
13697+ . unwrap ( )
13698+ . as_str ( )
13699+ . unwrap ( ) ;
13700+
13701+ // check the event txid is mapped to the coinbase
13702+ assert_eq ! ( event. get( "txid" ) . unwrap( ) . as_str( ) . unwrap( ) , coinbase_txid) ;
13703+ }
13704+ }
13705+ }
13706+ }
13707+ }
13708+ }
13709+
13710+ // get current liquidity
13711+ let sip_031_current_liquid_ustx_before = chainstate
13712+ . with_read_only_clarity_tx (
13713+ & sortdb
13714+ . index_handle_at_block ( & chainstate, & latest_stacks_block_id)
13715+ . unwrap ( ) ,
13716+ & latest_stacks_block_id,
13717+ |conn| conn. with_clarity_db_readonly ( |db| db. get_total_liquid_ustx ( ) . unwrap ( ) ) ,
13718+ )
13719+ . unwrap ( ) ;
13720+
13721+ assert ! ( sip_031_current_liquid_ustx_before >= SIP_031_INITIAL_MINT + 100_000 ) ;
13722+
13723+ let http_origin = format ! ( "http://{}" , & naka_conf. node. rpc_bind) ;
13724+
13725+ let mut sender_nonce = 0 ;
13726+ // 1 more tenures (with 5 stacks blocks)
13727+ let commits_before = commits_submitted. load ( Ordering :: SeqCst ) ;
13728+ next_block_and_process_new_stacks_blocks (
13729+ & mut btc_regtest_controller,
13730+ 5 ,
13731+ 60 ,
13732+ & coord_channel,
13733+ || {
13734+ let transfer_tx = make_stacks_transfer_serialized (
13735+ & sender_sk,
13736+ sender_nonce,
13737+ send_fee,
13738+ naka_conf. burnchain . chain_id ,
13739+ & PrincipalData :: from ( sender_signer_addr) ,
13740+ send_amt,
13741+ ) ;
13742+ submit_tx ( & http_origin, & transfer_tx) ;
13743+ sender_nonce += 1 ;
13744+ Ok ( ( ) )
13745+ } ,
13746+ )
13747+ . unwrap ( ) ;
13748+ wait_for ( 20 , || {
13749+ Ok ( commits_submitted. load ( Ordering :: SeqCst ) > commits_before)
13750+ } )
13751+ . unwrap ( ) ;
13752+
13753+ let mut total_minted_and_transferred: u128 = 0 ;
13754+
13755+ for block in test_observer:: get_blocks ( ) {
13756+ let burn_block_height = block. get ( "burn_block_height" ) . unwrap ( ) . as_u64 ( ) . unwrap ( ) ;
13757+
13758+ let sip_031_mint_and_transfer_amount =
13759+ SIP031EmissionInterval :: get_sip_031_emission_at_height (
13760+ burn_block_height,
13761+ naka_conf. is_mainnet ( ) ,
13762+ ) ;
13763+
13764+ // check for mint events for the SIP-031 boot contract (excluding the activation one)
13765+ let events = block. get ( "events" ) . unwrap ( ) . as_array ( ) . unwrap ( ) ;
13766+ for event in events {
13767+ if let Some ( mint_event) = event. get ( "stx_mint_event" ) {
13768+ if mint_event. get ( "recipient" ) . unwrap ( ) . as_str ( ) . unwrap ( )
13769+ == boot_code_id ( SIP_031_NAME , naka_conf. is_mainnet ( ) ) . to_string ( )
13770+ && burn_block_height != epoch32_start_height
13771+ {
13772+ let minted_amount = mint_event
13773+ . get ( "amount" )
13774+ . unwrap ( )
13775+ . as_str ( )
13776+ . unwrap ( )
13777+ . parse :: < u128 > ( )
13778+ . unwrap ( ) ;
13779+ assert_eq ! ( sip_031_mint_and_transfer_amount, minted_amount) ;
13780+ total_minted_and_transferred += minted_amount;
13781+
13782+ let coinbase_txid = block
13783+ . get ( "transactions" )
13784+ . unwrap ( )
13785+ . as_array ( )
13786+ . unwrap ( )
13787+ . get ( 1 )
13788+ . unwrap ( )
13789+ . get ( "txid" )
13790+ . unwrap ( )
13791+ . as_str ( )
13792+ . unwrap ( ) ;
13793+
13794+ // check the event txid is mapped to the coinbase
13795+ assert_eq ! ( event. get( "txid" ) . unwrap( ) . as_str( ) . unwrap( ) , coinbase_txid) ;
13796+ }
13797+ }
13798+ }
13799+ }
13800+
13801+ // 100_000
13802+ assert_eq ! ( total_minted_and_transferred, 100_000 ) ;
13803+
13804+ let latest_stacks_block_id = get_latest_block_proposal ( & naka_conf, & sortdb)
13805+ . unwrap ( )
13806+ . 0
13807+ . block_id ( ) ;
13808+
13809+ // get sip-031 boot contract balance (will be checked for 200_000_000 STX + 100_000 + total_minted_and_transferred)
13810+ let sip_031_boot_contract_balance = chainstate. with_read_only_clarity_tx (
13811+ & sortdb
13812+ . index_handle_at_block ( & chainstate, & latest_stacks_block_id)
13813+ . unwrap ( ) ,
13814+ & latest_stacks_block_id,
13815+ |conn| {
13816+ conn. with_clarity_db_readonly ( |db| {
13817+ db. get_account_stx_balance ( & PrincipalData :: Contract ( boot_code_id (
13818+ SIP_031_NAME ,
13819+ naka_conf. is_mainnet ( ) ,
13820+ ) ) )
13821+ } )
13822+ } ,
13823+ ) ;
13824+
13825+ assert_eq ! (
13826+ sip_031_boot_contract_balance,
13827+ Some ( Ok ( STXBalance :: Unlocked {
13828+ amount: SIP_031_INITIAL_MINT + 100_000 + total_minted_and_transferred
13829+ } ) )
13830+ ) ;
13831+
13832+ // get current liquidity
13833+ let sip_031_current_liquid_ustx = chainstate
13834+ . with_read_only_clarity_tx (
13835+ & sortdb
13836+ . index_handle_at_block ( & chainstate, & latest_stacks_block_id)
13837+ . unwrap ( ) ,
13838+ & latest_stacks_block_id,
13839+ |conn| conn. with_clarity_db_readonly ( |db| db. get_total_liquid_ustx ( ) . unwrap ( ) ) ,
13840+ )
13841+ . unwrap ( ) ;
13842+
13843+ // check liquidity has been updated accordingly
13844+ assert ! (
13845+ sip_031_current_liquid_ustx - sip_031_current_liquid_ustx_before
13846+ >= total_minted_and_transferred
13847+ ) ;
13848+
13849+ set_test_sip_031_emission_schedule ( None ) ;
13850+
13851+ coord_channel
13852+ . lock ( )
13853+ . expect ( "Mutex poisoned" )
13854+ . stop_chains_coordinator ( ) ;
13855+ run_loop_stopper. store ( false , Ordering :: SeqCst ) ;
13856+
13857+ run_loop_thread. join ( ) . unwrap ( ) ;
13858+ }
0 commit comments