diff --git a/clarity/src/vm/analysis/mod.rs b/clarity/src/vm/analysis/mod.rs index 19183f5f67..ddbcadb0c3 100644 --- a/clarity/src/vm/analysis/mod.rs +++ b/clarity/src/vm/analysis/mod.rs @@ -152,7 +152,8 @@ pub fn run_analysis( | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => { + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => { TypeChecker2_1::run_pass(&epoch, &mut contract_analysis, db, build_type_map) } StacksEpochId::Epoch10 => { diff --git a/clarity/src/vm/analysis/type_checker/mod.rs b/clarity/src/vm/analysis/type_checker/mod.rs index 68bbe1873e..4e6aec42da 100644 --- a/clarity/src/vm/analysis/type_checker/mod.rs +++ b/clarity/src/vm/analysis/type_checker/mod.rs @@ -45,7 +45,8 @@ impl FunctionType { | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => self.check_args_2_1(accounting, args, clarity_version), + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => self.check_args_2_1(accounting, args, clarity_version), StacksEpochId::Epoch10 => { Err(CheckErrors::Expects("Epoch10 is not supported".into()).into()) } @@ -69,7 +70,8 @@ impl FunctionType { | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => { + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => { self.check_args_by_allowing_trait_cast_2_1(db, clarity_version, func_args) } StacksEpochId::Epoch10 => { diff --git a/clarity/src/vm/costs/mod.rs b/clarity/src/vm/costs/mod.rs index 0b1559795f..f680435479 100644 --- a/clarity/src/vm/costs/mod.rs +++ b/clarity/src/vm/costs/mod.rs @@ -857,7 +857,8 @@ impl LimitedCostTracker { | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => COSTS_3_NAME.to_string(), + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => COSTS_3_NAME.to_string(), }; Ok(result) } diff --git a/clarity/src/vm/functions/mod.rs b/clarity/src/vm/functions/mod.rs index 3eac4fb19e..7c92d9a929 100644 --- a/clarity/src/vm/functions/mod.rs +++ b/clarity/src/vm/functions/mod.rs @@ -56,6 +56,8 @@ macro_rules! switch_on_global_epoch { StacksEpochId::Epoch30 => $Epoch205Version(args, env, context), // Note: We reuse 2.05 for 3.1. StacksEpochId::Epoch31 => $Epoch205Version(args, env, context), + // Note: We reuse 2.05 for 3.2. + StacksEpochId::Epoch32 => $Epoch205Version(args, env, context), } } }; diff --git a/clarity/src/vm/test_util/mod.rs b/clarity/src/vm/test_util/mod.rs index 37a40182eb..f1b354ebc7 100644 --- a/clarity/src/vm/test_util/mod.rs +++ b/clarity/src/vm/test_util/mod.rs @@ -53,7 +53,8 @@ pub fn generate_test_burn_state_db(epoch_id: StacksEpochId) -> UnitTestBurnState | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => UnitTestBurnStateDB { + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => UnitTestBurnStateDB { epoch_id, ast_rules: ASTRules::PrecheckSize, }, diff --git a/clarity/src/vm/tests/mod.rs b/clarity/src/vm/tests/mod.rs index f261733191..7d58fb515e 100644 --- a/clarity/src/vm/tests/mod.rs +++ b/clarity/src/vm/tests/mod.rs @@ -125,6 +125,7 @@ epochs_template! { Epoch25, Epoch30, Epoch31, + Epoch32, } clarity_template! { @@ -146,6 +147,9 @@ clarity_template! { (Epoch31, Clarity1), (Epoch31, Clarity2), (Epoch31, Clarity3), + (Epoch32, Clarity1), + (Epoch32, Clarity2), + (Epoch32, Clarity3), } #[cfg(test)] diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index f41b8ed1a3..19da888621 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -585,7 +585,8 @@ impl TypeSignature { | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => self.admits_type_v2_1(other), + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => self.admits_type_v2_1(other), StacksEpochId::Epoch10 => Err(CheckErrors::Expects("epoch 1.0 not supported".into())), } } @@ -793,7 +794,8 @@ impl TypeSignature { | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => self.canonicalize_v2_1(), + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => self.canonicalize_v2_1(), } } @@ -1152,7 +1154,8 @@ impl TypeSignature { | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => Self::least_supertype_v2_1(a, b), + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => Self::least_supertype_v2_1(a, b), StacksEpochId::Epoch10 => Err(CheckErrors::Expects("epoch 1.0 not supported".into())), } } diff --git a/clarity/src/vm/version.rs b/clarity/src/vm/version.rs index 7050d5dbd9..adc801f3e9 100644 --- a/clarity/src/vm/version.rs +++ b/clarity/src/vm/version.rs @@ -41,6 +41,7 @@ impl ClarityVersion { StacksEpochId::Epoch25 => ClarityVersion::Clarity2, StacksEpochId::Epoch30 => ClarityVersion::Clarity3, StacksEpochId::Epoch31 => ClarityVersion::Clarity3, + StacksEpochId::Epoch32 => ClarityVersion::Clarity3, } } } diff --git a/sample/conf/testnet-signer.toml b/sample/conf/testnet-signer.toml index 2fbff7a235..84e2a66d46 100644 --- a/sample/conf/testnet-signer.toml +++ b/sample/conf/testnet-signer.toml @@ -80,3 +80,7 @@ start_height = 1900 [[burnchain.epochs]] epoch_name = "3.1" start_height = 2000 + +[[burnchain.epochs]] +epoch_name = "3.2" +start_height = 2100 \ No newline at end of file diff --git a/stacks-common/src/libcommon.rs b/stacks-common/src/libcommon.rs index 48f8cd5970..7d9136f20b 100644 --- a/stacks-common/src/libcommon.rs +++ b/stacks-common/src/libcommon.rs @@ -80,6 +80,7 @@ pub mod consts { pub const PEER_VERSION_EPOCH_2_5: u8 = 0x0a; pub const PEER_VERSION_EPOCH_3_0: u8 = 0x0b; pub const PEER_VERSION_EPOCH_3_1: u8 = 0x0c; + pub const PEER_VERSION_EPOCH_3_2: u8 = 0x0d; /// this should be updated to the latest network epoch version supported by /// this node. this will be checked by the `validate_epochs()` method. diff --git a/stacks-common/src/types/mod.rs b/stacks-common/src/types/mod.rs index a4cc64aadc..0ead5475c1 100644 --- a/stacks-common/src/types/mod.rs +++ b/stacks-common/src/types/mod.rs @@ -102,6 +102,7 @@ pub enum StacksEpochId { Epoch25 = 0x0201a, Epoch30 = 0x03000, Epoch31 = 0x03001, + Epoch32 = 0x03002, } #[derive(Debug)] @@ -269,7 +270,7 @@ impl StacksEpochId { | StacksEpochId::Epoch23 | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 => MempoolCollectionBehavior::ByStacksHeight, - StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => { + StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => { MempoolCollectionBehavior::ByReceiveTime } } @@ -286,7 +287,10 @@ impl StacksEpochId { | StacksEpochId::Epoch22 | StacksEpochId::Epoch23 | StacksEpochId::Epoch24 => false, - StacksEpochId::Epoch25 | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => true, + StacksEpochId::Epoch25 + | StacksEpochId::Epoch30 + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => true, } } @@ -303,7 +307,8 @@ impl StacksEpochId { StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => true, + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => true, } } @@ -319,7 +324,7 @@ impl StacksEpochId { | StacksEpochId::Epoch23 | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 => false, - StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => true, + StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => true, } } @@ -335,7 +340,7 @@ impl StacksEpochId { | StacksEpochId::Epoch23 | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 => false, - StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => true, + StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => true, } } @@ -350,7 +355,7 @@ impl StacksEpochId { | StacksEpochId::Epoch23 | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 => false, - StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => true, + StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => true, } } @@ -381,7 +386,9 @@ impl StacksEpochId { | StacksEpochId::Epoch23 | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 => 0, - StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => MINING_COMMITMENT_FREQUENCY_NAKAMOTO, + StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => { + MINING_COMMITMENT_FREQUENCY_NAKAMOTO + } } } @@ -417,7 +424,7 @@ impl StacksEpochId { | StacksEpochId::Epoch23 | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 => false, - StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => { + StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => { cur_reward_cycle > first_epoch30_reward_cycle } } @@ -535,7 +542,7 @@ impl StacksEpochId { | StacksEpochId::Epoch30 => { self.coinbase_reward_pre_sip029(first_burnchain_height, current_burnchain_height) } - StacksEpochId::Epoch31 => self.coinbase_reward_sip029( + StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => self.coinbase_reward_sip029( mainnet, first_burnchain_height, current_burnchain_height, @@ -557,6 +564,7 @@ impl std::fmt::Display for StacksEpochId { StacksEpochId::Epoch25 => write!(f, "2.5"), StacksEpochId::Epoch30 => write!(f, "3.0"), StacksEpochId::Epoch31 => write!(f, "3.1"), + StacksEpochId::Epoch32 => write!(f, "3.2"), } } } @@ -576,6 +584,7 @@ impl TryFrom for StacksEpochId { x if x == StacksEpochId::Epoch25 as u32 => Ok(StacksEpochId::Epoch25), x if x == StacksEpochId::Epoch30 as u32 => Ok(StacksEpochId::Epoch30), x if x == StacksEpochId::Epoch31 as u32 => Ok(StacksEpochId::Epoch31), + x if x == StacksEpochId::Epoch32 as u32 => Ok(StacksEpochId::Epoch32), _ => Err("Invalid epoch"), } } diff --git a/stacks-common/src/types/tests.rs b/stacks-common/src/types/tests.rs index 20676999e7..cf4668b976 100644 --- a/stacks-common/src/types/tests.rs +++ b/stacks-common/src/types/tests.rs @@ -184,66 +184,26 @@ fn test_get_coinbase_at_effective_height() { #[test] fn test_epoch_coinbase_reward() { // new coinbase schedule - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 666050), - 1_000_000_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 666051), - 1_000_000_000 - ); + for epoch in [StacksEpochId::Epoch31, StacksEpochId::Epoch32].iter() { + assert_eq!(epoch.coinbase_reward(true, 666050, 666050), 1_000_000_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 666051), 1_000_000_000); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 944_999), - 1_000_000_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 945_000), - 500_000_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 945_001), - 500_000_000 - ); + assert_eq!(epoch.coinbase_reward(true, 666050, 944_999), 1_000_000_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 945_000), 500_000_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 945_001), 500_000_000); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_049_999), - 500_000_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_050_000), - 250_000_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_050_001), - 250_000_000 - ); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_049_999), 500_000_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_050_000), 250_000_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_050_001), 250_000_000); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_259_999), - 250_000_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_260_000), - 125_000_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_260_001), - 125_000_000 - ); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_259_999), 250_000_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_260_000), 125_000_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_260_001), 125_000_000); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_469_999), - 125_000_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_470_000), - 62_500_000 - ); - assert_eq!( - StacksEpochId::Epoch31.coinbase_reward(true, 666050, 1_470_001), - 62_500_000 - ); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_469_999), 125_000_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_470_000), 62_500_000); + assert_eq!(epoch.coinbase_reward(true, 666050, 1_470_001), 62_500_000); + } // old coinbase schedule for epoch in [ @@ -254,6 +214,7 @@ fn test_epoch_coinbase_reward() { StacksEpochId::Epoch23, StacksEpochId::Epoch24, StacksEpochId::Epoch25, + StacksEpochId::Epoch30, ] .iter() { diff --git a/stacks-node/src/tests/nakamoto_integrations.rs b/stacks-node/src/tests/nakamoto_integrations.rs index 9ad1fa4c8c..6f03ae4f5b 100644 --- a/stacks-node/src/tests/nakamoto_integrations.rs +++ b/stacks-node/src/tests/nakamoto_integrations.rs @@ -74,7 +74,8 @@ use stacks::core::{ EpochList, StacksEpoch, StacksEpochId, BLOCK_LIMIT_MAINNET_10, HELIUM_BLOCK_LIMIT_20, PEER_VERSION_EPOCH_1_0, PEER_VERSION_EPOCH_2_0, PEER_VERSION_EPOCH_2_05, PEER_VERSION_EPOCH_2_1, PEER_VERSION_EPOCH_2_2, PEER_VERSION_EPOCH_2_3, PEER_VERSION_EPOCH_2_4, - PEER_VERSION_EPOCH_2_5, PEER_VERSION_EPOCH_3_0, PEER_VERSION_EPOCH_3_1, PEER_VERSION_TESTNET, + PEER_VERSION_EPOCH_2_5, PEER_VERSION_EPOCH_3_0, PEER_VERSION_EPOCH_3_1, PEER_VERSION_EPOCH_3_2, + PEER_VERSION_TESTNET, }; use stacks::libstackerdb::{SlotMetadata, StackerDBChunkData}; use stacks::net::api::callreadonly::CallReadOnlyRequestBody; @@ -128,8 +129,10 @@ use crate::{tests, BitcoinRegtestController, BurnchainController, Config, Config pub static POX_4_DEFAULT_STACKER_BALANCE: u64 = 100_000_000_000_000; pub static POX_4_DEFAULT_STACKER_STX_AMT: u128 = 99_000_000_000_000; +use crate::clarity::vm::clarity::ClarityConnection; + lazy_static! { - pub static ref NAKAMOTO_INTEGRATION_EPOCHS: [StacksEpoch; 10] = [ + pub static ref NAKAMOTO_INTEGRATION_EPOCHS: [StacksEpoch; 11] = [ StacksEpoch { epoch_id: StacksEpochId::Epoch10, start_height: 0, @@ -196,10 +199,17 @@ lazy_static! { StacksEpoch { epoch_id: StacksEpochId::Epoch31, start_height: 241, - end_height: STACKS_EPOCH_MAX, + end_height: 251, block_limit: HELIUM_BLOCK_LIMIT_20.clone(), network_epoch: PEER_VERSION_EPOCH_3_1 }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch32, + start_height: 251, + end_height: STACKS_EPOCH_MAX, + block_limit: HELIUM_BLOCK_LIMIT_20.clone(), + network_epoch: PEER_VERSION_EPOCH_3_2 + }, ]; } @@ -12621,3 +12631,141 @@ fn write_signer_update( ); } } + +/// Test SIP-031 activation +/// +/// - check epoch 3.2 is active +/// - check sip031 boot contract has a balance of 200_000_000 STX (TODO) +#[test] +#[ignore] +fn test_sip_031_activation() { + if env::var("BITCOIND_TEST") != Ok("1".into()) { + return; + } + + // skip the test til we move to epoch 3.2 + if StacksEpochId::latest() != StacksEpochId::Epoch32 { + return; + } + + let (mut naka_conf, _miner_account) = naka_neon_integration_conf(None); + naka_conf.node.pox_sync_sample_secs = 180; + naka_conf.burnchain.max_rbf = 10_000_000; + + let sender_sk = Secp256k1PrivateKey::random(); + let sender_signer_sk = Secp256k1PrivateKey::random(); + let sender_signer_addr = tests::to_addr(&sender_signer_sk); + let mut signers = TestSigners::new(vec![sender_signer_sk]); + let tenure_count = 5; + let inter_blocks_per_tenure = 9; + // setup sender + recipient for some test stx transfers + // these are necessary for the interim blocks to get mined at all + let sender_addr = tests::to_addr(&sender_sk); + let send_amt = 100; + let send_fee = 180; + naka_conf.add_initial_balance( + PrincipalData::from(sender_addr).to_string(), + (send_amt + send_fee) * tenure_count * inter_blocks_per_tenure, + ); + naka_conf.add_initial_balance(PrincipalData::from(sender_signer_addr).to_string(), 100000); + let stacker_sk = setup_stacker(&mut naka_conf); + + test_observer::spawn(); + test_observer::register_any(&mut naka_conf); + + let mut btcd_controller = BitcoinCoreController::new(naka_conf.clone()); + btcd_controller + .start_bitcoind() + .expect("Failed starting bitcoind"); + let mut btc_regtest_controller = BitcoinRegtestController::new(naka_conf.clone(), None); + btc_regtest_controller.bootstrap_chain(201); + + let mut run_loop = boot_nakamoto::BootRunLoop::new(naka_conf.clone()).unwrap(); + let run_loop_stopper = run_loop.get_termination_switch(); + let Counters { + blocks_processed, + naka_submitted_commits: commits_submitted, + .. + } = run_loop.counters(); + let counters = run_loop.counters(); + + let coord_channel = run_loop.coordinator_channels(); + + let run_loop_thread = thread::Builder::new() + .name("run_loop".into()) + .spawn(move || run_loop.start(None, 0)) + .unwrap(); + wait_for_runloop(&blocks_processed); + boot_to_epoch_3( + &naka_conf, + &blocks_processed, + &[stacker_sk], + &[sender_signer_sk], + &mut Some(&mut signers), + &mut btc_regtest_controller, + ); + + info!("Bootstrapped to Epoch-3.0 boundary, starting nakamoto miner"); + + let burnchain = naka_conf.get_burnchain(); + let sortdb = burnchain.open_sortition_db(true).unwrap(); + let (mut chainstate, _) = StacksChainState::open( + naka_conf.is_mainnet(), + naka_conf.burnchain.chain_id, + &naka_conf.get_chainstate_path_str(), + None, + ) + .unwrap(); + + info!("Nakamoto miner started..."); + blind_signer(&naka_conf, &signers, &counters); + + wait_for_first_naka_block_commit(60, &commits_submitted); + + // mine until epooch 3.2 height + loop { + let commits_before = commits_submitted.load(Ordering::SeqCst); + next_block_and_process_new_stacks_block(&mut btc_regtest_controller, 60, &coord_channel) + .unwrap(); + wait_for(20, || { + Ok(commits_submitted.load(Ordering::SeqCst) > commits_before) + }) + .unwrap(); + + let node_info = get_chain_info_opt(&naka_conf).unwrap(); + if node_info.burn_block_height + >= naka_conf.burnchain.epochs.clone().unwrap()[StacksEpochId::Epoch32].start_height + { + break; + } + } + + info!( + "Nakamoto miner has advanced to bitcoin height {}", + get_chain_info_opt(&naka_conf).unwrap().burn_block_height + ); + + // check for Epoch 3.2 in clarity db + let latest_stacks_block_id = get_latest_block_proposal(&naka_conf, &sortdb) + .unwrap() + .0 + .block_id(); + + let epoch_version = chainstate.with_read_only_clarity_tx( + &sortdb + .index_handle_at_block(&chainstate, &latest_stacks_block_id) + .unwrap(), + &latest_stacks_block_id, + |conn| conn.with_clarity_db_readonly(|db| db.get_clarity_epoch_version().unwrap()), + ); + + assert_eq!(epoch_version, Some(StacksEpochId::Epoch32)); + + coord_channel + .lock() + .expect("Mutex poisoned") + .stop_chains_coordinator(); + run_loop_stopper.store(false, Ordering::SeqCst); + + run_loop_thread.join().unwrap(); +} diff --git a/stackslib/src/chainstate/burn/db/sortdb.rs b/stackslib/src/chainstate/burn/db/sortdb.rs index e5f5bdde96..88fc138a40 100644 --- a/stackslib/src/chainstate/burn/db/sortdb.rs +++ b/stackslib/src/chainstate/burn/db/sortdb.rs @@ -3236,6 +3236,7 @@ impl SortitionDB { StacksEpochId::Epoch25 => version_u32 >= 3, StacksEpochId::Epoch30 => version_u32 >= 3, StacksEpochId::Epoch31 => version_u32 >= 3, + StacksEpochId::Epoch32 => version_u32 >= 3, } } diff --git a/stackslib/src/chainstate/burn/operations/leader_block_commit.rs b/stackslib/src/chainstate/burn/operations/leader_block_commit.rs index 562d409802..abaa31e224 100644 --- a/stackslib/src/chainstate/burn/operations/leader_block_commit.rs +++ b/stackslib/src/chainstate/burn/operations/leader_block_commit.rs @@ -36,7 +36,7 @@ use crate::chainstate::stacks::address::PoxAddress; use crate::core::{ StacksEpochId, STACKS_EPOCH_2_05_MARKER, STACKS_EPOCH_2_1_MARKER, STACKS_EPOCH_2_2_MARKER, STACKS_EPOCH_2_3_MARKER, STACKS_EPOCH_2_4_MARKER, STACKS_EPOCH_2_5_MARKER, - STACKS_EPOCH_3_0_MARKER, STACKS_EPOCH_3_1_MARKER, + STACKS_EPOCH_3_0_MARKER, STACKS_EPOCH_3_1_MARKER, STACKS_EPOCH_3_2_MARKER, }; // return type from parse_data below @@ -877,6 +877,7 @@ impl LeaderBlockCommitOp { StacksEpochId::Epoch25 => self.check_epoch_commit_marker(STACKS_EPOCH_2_5_MARKER), StacksEpochId::Epoch30 => self.check_epoch_commit_marker(STACKS_EPOCH_3_0_MARKER), StacksEpochId::Epoch31 => self.check_epoch_commit_marker(STACKS_EPOCH_3_1_MARKER), + StacksEpochId::Epoch32 => self.check_epoch_commit_marker(STACKS_EPOCH_3_2_MARKER), } } @@ -897,7 +898,8 @@ impl LeaderBlockCommitOp { | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => { + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => { // correct behavior -- uses *sortition height* to find the intended sortition ID let sortition_height = self .block_height diff --git a/stackslib/src/chainstate/coordinator/mod.rs b/stackslib/src/chainstate/coordinator/mod.rs index caf2a90ffb..cc21170543 100644 --- a/stackslib/src/chainstate/coordinator/mod.rs +++ b/stackslib/src/chainstate/coordinator/mod.rs @@ -425,8 +425,11 @@ impl OnChainRewardSetProvider<'_, T> { return Ok(RewardSet::empty()); } } - StacksEpochId::Epoch25 | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => { - // Epoch 2.5, 3.0, and 3.1 compute reward sets, but *only* if PoX-4 is active + StacksEpochId::Epoch25 + | StacksEpochId::Epoch30 + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => { + // Epoch 2.5, 3.0, 3.1 and 3.2 compute reward sets, but *only* if PoX-4 is active if burnchain .pox_constants .active_pox_contract(current_burn_height) diff --git a/stackslib/src/chainstate/stacks/db/blocks.rs b/stackslib/src/chainstate/stacks/db/blocks.rs index 2c35ac1fe7..7fe642ee71 100644 --- a/stackslib/src/chainstate/stacks/db/blocks.rs +++ b/stackslib/src/chainstate/stacks/db/blocks.rs @@ -4092,7 +4092,11 @@ impl StacksChainState { current_epoch = StacksEpochId::Epoch31; } StacksEpochId::Epoch31 => { - panic!("No defined transition from Epoch31 forward") + receipts.append(&mut clarity_tx.block.initialize_epoch_3_2()?); + current_epoch = StacksEpochId::Epoch32; + } + StacksEpochId::Epoch32 => { + panic!("No defined transition from Epoch32 forward") } } @@ -4921,7 +4925,10 @@ impl StacksChainState { )?; Ok((stack_ops, transfer_ops, delegate_ops, vec![])) } - StacksEpochId::Epoch25 | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => { + StacksEpochId::Epoch25 + | StacksEpochId::Epoch30 + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => { StacksChainState::get_stacking_and_transfer_and_delegate_burn_ops_v210( chainstate_tx, parent_index_hash, @@ -5011,13 +5018,14 @@ impl StacksChainState { pox_reward_cycle, pox_start_cycle_info, ), - StacksEpochId::Epoch25 | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => { - Self::handle_pox_cycle_start_pox_4( - clarity_tx, - pox_reward_cycle, - pox_start_cycle_info, - ) - } + StacksEpochId::Epoch25 + | StacksEpochId::Epoch30 + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => Self::handle_pox_cycle_start_pox_4( + clarity_tx, + pox_reward_cycle, + pox_start_cycle_info, + ), } })?; debug!("check_and_handle_reward_start: handled pox cycle start"); diff --git a/stackslib/src/chainstate/stacks/db/mod.rs b/stackslib/src/chainstate/stacks/db/mod.rs index 09064efae2..51b38fd4b8 100644 --- a/stackslib/src/chainstate/stacks/db/mod.rs +++ b/stackslib/src/chainstate/stacks/db/mod.rs @@ -292,6 +292,7 @@ impl DBConfig { StacksEpochId::Epoch25 => version_u32 >= 3 && version_u32 <= 10, StacksEpochId::Epoch30 => version_u32 >= 3 && version_u32 <= 10, StacksEpochId::Epoch31 => version_u32 >= 3 && version_u32 <= 10, + StacksEpochId::Epoch32 => version_u32 >= 3 && version_u32 <= 10, } } } diff --git a/stackslib/src/chainstate/stacks/db/transactions.rs b/stackslib/src/chainstate/stacks/db/transactions.rs index e432ab902f..2df237e8fa 100644 --- a/stackslib/src/chainstate/stacks/db/transactions.rs +++ b/stackslib/src/chainstate/stacks/db/transactions.rs @@ -1658,6 +1658,10 @@ pub mod test { epoch_id: StacksEpochId::Epoch31, ast_rules: ASTRules::PrecheckSize, }; + pub const TestBurnStateDB_32: UnitTestBurnStateDB = UnitTestBurnStateDB { + epoch_id: StacksEpochId::Epoch32, + ast_rules: ASTRules::PrecheckSize, + }; pub const ALL_BURN_DBS: &[&dyn BurnStateDB] = &[ &TestBurnStateDB_20 as &dyn BurnStateDB, @@ -8731,6 +8735,7 @@ pub mod test { StacksEpochId::Epoch25 => self.get_stacks_epoch(6), StacksEpochId::Epoch30 => self.get_stacks_epoch(7), StacksEpochId::Epoch31 => self.get_stacks_epoch(8), + StacksEpochId::Epoch32 => self.get_stacks_epoch(9), } } fn get_pox_payout_addrs( diff --git a/stackslib/src/clarity_vm/clarity.rs b/stackslib/src/clarity_vm/clarity.rs index e9abf82f47..5c465b1a9c 100644 --- a/stackslib/src/clarity_vm/clarity.rs +++ b/stackslib/src/clarity_vm/clarity.rs @@ -1596,6 +1596,34 @@ impl<'a> ClarityBlockConnection<'a, '_> { }) } + pub fn initialize_epoch_3_2(&mut self) -> Result, Error> { + // use the `using!` statement to ensure that the old cost_tracker is placed + // back in all branches after initialization + using!(self.cost_track, "cost tracker", |old_cost_tracker| { + // epoch initialization is *free*. + // NOTE: this also means that cost functions won't be evaluated. + self.cost_track.replace(LimitedCostTracker::new_free()); + self.epoch = StacksEpochId::Epoch32; + self.as_transaction(|tx_conn| { + // bump the epoch in the Clarity DB + tx_conn + .with_clarity_db(|db| { + db.set_clarity_epoch_version(StacksEpochId::Epoch32)?; + Ok(()) + }) + .unwrap(); + + // require 3.2 rules henceforth in this connection as well + tx_conn.epoch = StacksEpochId::Epoch32; + }); + + // TODO: SIP-031 setup (minting and transfer to the boot contract) + + debug!("Epoch 3.2 initialized"); + (old_cost_tracker, Ok(vec![])) + }) + } + pub fn start_transaction_processing(&mut self) -> ClarityTransactionConnection { ClarityTransactionConnection::new( &mut self.datastore, diff --git a/stackslib/src/clarity_vm/tests/large_contract.rs b/stackslib/src/clarity_vm/tests/large_contract.rs index 36e24054d7..1915d3db36 100644 --- a/stackslib/src/clarity_vm/tests/large_contract.rs +++ b/stackslib/src/clarity_vm/tests/large_contract.rs @@ -163,7 +163,8 @@ fn test_simple_token_system(#[case] version: ClarityVersion, #[case] epoch: Stac | StacksEpochId::Epoch24 | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 => { + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 => { let (ast, _analysis) = tx .analyze_smart_contract( &boot_code_id("costs-3", false), diff --git a/stackslib/src/config/mod.rs b/stackslib/src/config/mod.rs index 1c9ffd9879..4f3c03c94f 100644 --- a/stackslib/src/config/mod.rs +++ b/stackslib/src/config/mod.rs @@ -718,6 +718,8 @@ impl Config { Ok(StacksEpochId::Epoch30) } else if epoch_name == EPOCH_CONFIG_3_1_0 { Ok(StacksEpochId::Epoch31) + } else if epoch_name == EPOCH_CONFIG_3_2_0 { + Ok(StacksEpochId::Epoch32) } else { Err(format!("Unknown epoch name specified: {epoch_name}")) }?; @@ -745,6 +747,7 @@ impl Config { StacksEpochId::Epoch25, StacksEpochId::Epoch30, StacksEpochId::Epoch31, + StacksEpochId::Epoch32, ]; for (expected_epoch, configured_epoch) in expected_list .iter() @@ -1726,6 +1729,7 @@ pub const EPOCH_CONFIG_2_4_0: &str = "2.4"; pub const EPOCH_CONFIG_2_5_0: &str = "2.5"; pub const EPOCH_CONFIG_3_0_0: &str = "3.0"; pub const EPOCH_CONFIG_3_1_0: &str = "3.1"; +pub const EPOCH_CONFIG_3_2_0: &str = "3.2"; #[derive(Clone, Deserialize, Default, Debug)] pub struct AffirmationOverride { diff --git a/stackslib/src/core/mod.rs b/stackslib/src/core/mod.rs index 76e194aaff..3661c2504a 100644 --- a/stackslib/src/core/mod.rs +++ b/stackslib/src/core/mod.rs @@ -49,8 +49,8 @@ pub use stacks_common::consts::{ NETWORK_ID_TESTNET, PEER_NETWORK_EPOCH, PEER_VERSION_EPOCH_1_0, PEER_VERSION_EPOCH_2_0, PEER_VERSION_EPOCH_2_05, PEER_VERSION_EPOCH_2_1, PEER_VERSION_EPOCH_2_2, PEER_VERSION_EPOCH_2_3, PEER_VERSION_EPOCH_2_4, PEER_VERSION_EPOCH_2_5, PEER_VERSION_EPOCH_3_0, - PEER_VERSION_EPOCH_3_1, PEER_VERSION_MAINNET, PEER_VERSION_MAINNET_MAJOR, PEER_VERSION_TESTNET, - PEER_VERSION_TESTNET_MAJOR, STACKS_EPOCH_MAX, + PEER_VERSION_EPOCH_3_1, PEER_VERSION_EPOCH_3_2, PEER_VERSION_MAINNET, + PEER_VERSION_MAINNET_MAJOR, PEER_VERSION_TESTNET, PEER_VERSION_TESTNET_MAJOR, STACKS_EPOCH_MAX, }; // default port @@ -104,6 +104,8 @@ pub const BITCOIN_MAINNET_STACKS_25_BURN_HEIGHT: u64 = 840_360; pub const BITCOIN_MAINNET_STACKS_30_BURN_HEIGHT: u64 = 867_867; /// This is Epoch-3.1, activation height proposed in SIP-029 pub const BITCOIN_MAINNET_STACKS_31_BURN_HEIGHT: u64 = 875_000; +/// This is Epoch-3.2, activation height proposed in SIP-031 (placeholder for now) +pub const BITCOIN_MAINNET_STACKS_32_BURN_HEIGHT: u64 = u64::MAX; /// Bitcoin mainline testnet3 activation heights. /// TODO: No longer used since testnet3 is dead, so remove. @@ -119,6 +121,7 @@ pub const BITCOIN_TESTNET_STACKS_24_BURN_HEIGHT: u64 = 2_432_545; pub const BITCOIN_TESTNET_STACKS_25_BURN_HEIGHT: u64 = 2_583_893; pub const BITCOIN_TESTNET_STACKS_30_BURN_HEIGHT: u64 = 30_000_000; pub const BITCOIN_TESTNET_STACKS_31_BURN_HEIGHT: u64 = 30_000_001; +pub const BITCOIN_TESTNET_STACKS_32_BURN_HEIGHT: u64 = 30_000_002; /// This constant sets the approximate testnet bitcoin height at which 2.5 Xenon /// was reorged back to 2.5 instantiation. This is only used to calculate the @@ -311,10 +314,17 @@ lazy_static! { StacksEpoch { epoch_id: StacksEpochId::Epoch31, start_height: BITCOIN_MAINNET_STACKS_31_BURN_HEIGHT, - end_height: STACKS_EPOCH_MAX, + end_height: BITCOIN_MAINNET_STACKS_32_BURN_HEIGHT, block_limit: BLOCK_LIMIT_MAINNET_21.clone(), network_epoch: PEER_VERSION_EPOCH_3_1 }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch32, + start_height: BITCOIN_MAINNET_STACKS_32_BURN_HEIGHT, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_2 + }, ]); } @@ -386,10 +396,17 @@ lazy_static! { StacksEpoch { epoch_id: StacksEpochId::Epoch31, start_height: BITCOIN_TESTNET_STACKS_31_BURN_HEIGHT, - end_height: STACKS_EPOCH_MAX, + end_height: BITCOIN_TESTNET_STACKS_32_BURN_HEIGHT, block_limit: BLOCK_LIMIT_MAINNET_21.clone(), network_epoch: PEER_VERSION_EPOCH_3_1 }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch32, + start_height: BITCOIN_TESTNET_STACKS_32_BURN_HEIGHT, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_2 + }, ]); } @@ -503,6 +520,10 @@ pub static STACKS_EPOCH_3_0_MARKER: u8 = 0x0b; /// running it prior to 3.1 activation. pub static STACKS_EPOCH_3_1_MARKER: u8 = 0x0d; +/// Stacks 3.0 epoch marker. All block-commits in 3.2 must have a memo bitfield with this value +/// *or greater*. +pub static STACKS_EPOCH_3_2_MARKER: u8 = 0x0e; + #[test] fn test_ord_for_stacks_epoch() { let epochs = &*STACKS_EPOCHS_MAINNET; @@ -783,6 +804,8 @@ pub trait StacksEpochExtension { #[cfg(test)] fn unit_test_3_1(epoch_2_0_block_height: u64) -> EpochList; #[cfg(test)] + fn unit_test_3_2(epoch_2_0_block_height: u64) -> EpochList; + #[cfg(test)] fn unit_test_2_1_only(epoch_2_0_block_height: u64) -> EpochList; #[cfg(test)] fn unit_test_3_0_only(first_burnchain_height: u64) -> EpochList; @@ -1551,6 +1574,148 @@ impl StacksEpochExtension for StacksEpoch { ]) } + #[cfg(test)] + fn unit_test_3_2(first_burnchain_height: u64) -> EpochList { + info!( + "StacksEpoch unit_test_3_2 first_burn_height = {}", + first_burnchain_height + ); + + EpochList::new(&[ + StacksEpoch { + epoch_id: StacksEpochId::Epoch10, + start_height: 0, + end_height: first_burnchain_height, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_1_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch20, + start_height: first_burnchain_height, + end_height: first_burnchain_height + 4, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_2_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch2_05, + start_height: first_burnchain_height + 4, + end_height: first_burnchain_height + 8, + block_limit: ExecutionCost { + write_length: 205205, + write_count: 205205, + read_length: 205205, + read_count: 205205, + runtime: 205205, + }, + network_epoch: PEER_VERSION_EPOCH_2_05, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch21, + start_height: first_burnchain_height + 8, + end_height: first_burnchain_height + 12, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_2_1, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch22, + start_height: first_burnchain_height + 12, + end_height: first_burnchain_height + 16, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_2_2, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch23, + start_height: first_burnchain_height + 16, + end_height: first_burnchain_height + 20, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_2_3, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch24, + start_height: first_burnchain_height + 20, + end_height: first_burnchain_height + 24, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_2_4, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch25, + start_height: first_burnchain_height + 24, + end_height: first_burnchain_height + 28, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_2_5, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch30, + start_height: first_burnchain_height + 28, + end_height: first_burnchain_height + 32, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_3_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch31, + start_height: first_burnchain_height + 32, + end_height: first_burnchain_height + 36, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_3_1, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch32, + start_height: first_burnchain_height + 36, + end_height: STACKS_EPOCH_MAX, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_3_2, + }, + ]) + } + #[cfg(test)] fn unit_test_2_1_only(first_burnchain_height: u64) -> EpochList { info!( @@ -1690,6 +1855,7 @@ impl StacksEpochExtension for StacksEpoch { StacksEpochId::Epoch25 => StacksEpoch::unit_test_2_5(first_burnchain_height), StacksEpochId::Epoch30 => StacksEpoch::unit_test_3_0(first_burnchain_height), StacksEpochId::Epoch31 => StacksEpoch::unit_test_3_1(first_burnchain_height), + StacksEpochId::Epoch32 => StacksEpoch::unit_test_3_2(first_burnchain_height), } } diff --git a/stackslib/src/cost_estimates/pessimistic.rs b/stackslib/src/cost_estimates/pessimistic.rs index 997fe8e8cb..314cbdc6aa 100644 --- a/stackslib/src/cost_estimates/pessimistic.rs +++ b/stackslib/src/cost_estimates/pessimistic.rs @@ -222,6 +222,8 @@ impl PessimisticEstimator { StacksEpochId::Epoch30 => ":2.1", // reuse cost estimates in Epoch31 StacksEpochId::Epoch31 => ":2.1", + // reuse cost estimates in Epoch32 + StacksEpochId::Epoch32 => ":2.1", }; format!( "cc{}:{}:{}.{}",