From 6a8c1d5cbdb7199c698c9b7b20bc0761f992baad Mon Sep 17 00:00:00 2001 From: Brice Dobry <232827048+brice-stacks@users.noreply.github.com> Date: Fri, 9 Jan 2026 17:16:41 -0500 Subject: [PATCH] feat: add epoch 3.4 and Clarity5 --- clarity-types/src/types/signatures.rs | 9 +- clarity/src/vm/analysis/mod.rs | 3 +- clarity/src/vm/analysis/type_checker/mod.rs | 10 +- .../vm/analysis/type_checker/v2_1/contexts.rs | 13 +- .../type_checker/v2_1/tests/contracts.rs | 10 +- clarity/src/vm/ast/mod.rs | 26 +- clarity/src/vm/costs/mod.rs | 2 +- clarity/src/vm/functions/mod.rs | 2 + clarity/src/vm/test_util/mod.rs | 18 +- clarity/src/vm/tests/conversions.rs | 6 +- clarity/src/vm/tests/crypto.rs | 84 ++--- clarity/src/vm/tests/mod.rs | 17 + clarity/src/vm/tests/post_conditions.rs | 20 +- clarity/src/vm/tests/proptest_utils.rs | 4 +- clarity/src/vm/tests/variables.rs | 4 +- clarity/src/vm/version.rs | 8 +- stacks-common/src/libcommon.rs | 1 + stacks-common/src/types/mod.rs | 53 ++- .../src/tests/nakamoto_integrations.rs | 19 +- stacks-node/src/tests/signer/v0.rs | 2 + stackslib/src/chainstate/burn/db/sortdb.rs | 1 + .../burn/operations/leader_block_commit.rs | 3 +- stackslib/src/chainstate/coordinator/mod.rs | 5 +- .../chainstate/nakamoto/coordinator/tests.rs | 3 +- stackslib/src/chainstate/stacks/db/blocks.rs | 12 +- stackslib/src/chainstate/stacks/db/mod.rs | 3 +- .../src/chainstate/stacks/db/transactions.rs | 6 + .../src/chainstate/stacks/tests/reward_set.rs | 2 +- .../src/chainstate/stacks/transaction.rs | 2 + stackslib/src/chainstate/tests/consensus.rs | 16 +- stackslib/src/chainstate/tests/mod.rs | 27 +- .../tests/runtime_analysis_tests.rs | 7 +- .../chainstate/tests/static_analysis_tests.rs | 6 +- stackslib/src/clarity_vm/clarity.rs | 26 ++ .../src/clarity_vm/tests/large_contract.rs | 2 +- stackslib/src/config/mod.rs | 4 + stackslib/src/core/mod.rs | 320 +++++++++++++++++- stackslib/src/cost_estimates/pessimistic.rs | 2 + stackslib/src/net/tests/relay/epoch2x.rs | 1 + 39 files changed, 603 insertions(+), 156 deletions(-) diff --git a/clarity-types/src/types/signatures.rs b/clarity-types/src/types/signatures.rs index 13ce2becc0a..e1cc07cdabf 100644 --- a/clarity-types/src/types/signatures.rs +++ b/clarity-types/src/types/signatures.rs @@ -457,7 +457,8 @@ impl TypeSignature { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => self.admits_type_v2_1(other), + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => self.admits_type_v2_1(other), StacksEpochId::Epoch10 => Err(CommonCheckErrorKind::Expects( "epoch 1.0 not supported".into(), )), @@ -669,7 +670,8 @@ impl TypeSignature { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => self.canonicalize_v2_1(), + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => self.canonicalize_v2_1(), } } @@ -1008,7 +1010,8 @@ impl TypeSignature { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => Self::least_supertype_v2_1(a, b), + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => Self::least_supertype_v2_1(a, b), StacksEpochId::Epoch10 => Err(CommonCheckErrorKind::Expects( "epoch 1.0 not supported".into(), )), diff --git a/clarity/src/vm/analysis/mod.rs b/clarity/src/vm/analysis/mod.rs index fac0cce6e73..2b376911881 100644 --- a/clarity/src/vm/analysis/mod.rs +++ b/clarity/src/vm/analysis/mod.rs @@ -148,7 +148,8 @@ pub fn run_analysis( | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => { + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => { 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 30db2e931ff..418b5327ad9 100644 --- a/clarity/src/vm/analysis/type_checker/mod.rs +++ b/clarity/src/vm/analysis/type_checker/mod.rs @@ -47,7 +47,8 @@ impl FunctionType { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => self.check_args_2_1(accounting, args, clarity_version), + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => self.check_args_2_1(accounting, args, clarity_version), StacksEpochId::Epoch10 => { Err(StaticCheckErrorKind::Expects("Epoch10 is not supported".into()).into()) } @@ -73,7 +74,8 @@ impl FunctionType { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => { + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => { self.check_args_by_allowing_trait_cast_2_1(db, clarity_version, func_args) } StacksEpochId::Epoch10 => { @@ -94,6 +96,8 @@ fn is_reserved_word_v3(word: &str) -> bool { pub fn is_reserved_word(word: &str, version: ClarityVersion) -> bool { match version { ClarityVersion::Clarity1 | ClarityVersion::Clarity2 => false, - ClarityVersion::Clarity3 | ClarityVersion::Clarity4 => is_reserved_word_v3(word), + ClarityVersion::Clarity3 | ClarityVersion::Clarity4 | ClarityVersion::Clarity5 => { + is_reserved_word_v3(word) + } } } diff --git a/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs b/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs index c8998b90190..422d0b5e0d9 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs @@ -40,12 +40,13 @@ impl TraitContext { pub fn new(clarity_version: ClarityVersion) -> TraitContext { match clarity_version { ClarityVersion::Clarity1 => Self::Clarity1(HashMap::new()), - ClarityVersion::Clarity2 | ClarityVersion::Clarity3 | ClarityVersion::Clarity4 => { - Self::Clarity2 { - defined: HashSet::new(), - all: HashMap::new(), - } - } + ClarityVersion::Clarity2 + | ClarityVersion::Clarity3 + | ClarityVersion::Clarity4 + | ClarityVersion::Clarity5 => Self::Clarity2 { + defined: HashSet::new(), + all: HashMap::new(), + }, } } diff --git a/clarity/src/vm/analysis/type_checker/v2_1/tests/contracts.rs b/clarity/src/vm/analysis/type_checker/v2_1/tests/contracts.rs index 8ce09650793..4073e8da7ba 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/tests/contracts.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/tests/contracts.rs @@ -2547,7 +2547,10 @@ fn clarity_trait_experiments_downcast_literal_2( }) .unwrap_err(); match version { - ClarityVersion::Clarity2 | ClarityVersion::Clarity3 | ClarityVersion::Clarity4 => { + ClarityVersion::Clarity2 + | ClarityVersion::Clarity3 + | ClarityVersion::Clarity4 + | ClarityVersion::Clarity5 => { assert!(err.starts_with("ExpectedCallableType(PrincipalType)")) } ClarityVersion::Clarity1 => { @@ -2749,7 +2752,10 @@ fn clarity_trait_experiments_trait_cast_incompatible( assert!(err.starts_with("TypeError(CallableType(Trait(TraitIdentifier")) } } - ClarityVersion::Clarity2 | ClarityVersion::Clarity3 | ClarityVersion::Clarity4 => { + ClarityVersion::Clarity2 + | ClarityVersion::Clarity3 + | ClarityVersion::Clarity4 + | ClarityVersion::Clarity5 => { assert!(err.starts_with("IncompatibleTrait")) } } diff --git a/clarity/src/vm/ast/mod.rs b/clarity/src/vm/ast/mod.rs index b09de172e6d..7316ee66425 100644 --- a/clarity/src/vm/ast/mod.rs +++ b/clarity/src/vm/ast/mod.rs @@ -458,14 +458,14 @@ mod test { write_length: u64::MAX, runtime: 1, }; - let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::Epoch33, limit); + let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::latest(), limit); let err = build_ast( &QualifiedContractIdentifier::transient(), "(define-constant my-const u1)", &mut tracker, - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), ) .unwrap_err(); @@ -488,14 +488,14 @@ mod test { write_length: u64::MAX, runtime: expected_ast_parse_cost, }; - let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::Epoch33, limit); + let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::latest(), limit); let err = build_ast( &QualifiedContractIdentifier::transient(), "(define-constant a 0)(define-constant b 1)", // no dependency = 0 graph edge &mut tracker, - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), ) .expect_err("Expected parse error, but found success!"); @@ -520,14 +520,14 @@ mod test { write_length: u64::MAX, runtime: expected_ast_parse_cost, }; - let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::Epoch33, limit); + let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::latest(), limit); let err = build_ast( &QualifiedContractIdentifier::transient(), "(define-constant a 0)(define-constant b a)", // 1 dependency = 1 graph edge &mut tracker, - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), ) .expect_err("Expected parse error, but found success!"); @@ -553,8 +553,8 @@ mod test { &QualifiedContractIdentifier::transient(), &contract, &mut (), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), ) .expect_err("Expected parse error, but found success!"); @@ -575,8 +575,8 @@ mod test { &QualifiedContractIdentifier::transient(), &contract, &mut (), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), ) .expect_err("Expected parse error, but found success!"); diff --git a/clarity/src/vm/costs/mod.rs b/clarity/src/vm/costs/mod.rs index 4e006c890c1..6cb6e13670a 100644 --- a/clarity/src/vm/costs/mod.rs +++ b/clarity/src/vm/costs/mod.rs @@ -849,7 +849,7 @@ impl LimitedCostTracker { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => COSTS_3_NAME.to_string(), - StacksEpochId::Epoch33 => COSTS_4_NAME.to_string(), + StacksEpochId::Epoch33 | StacksEpochId::Epoch34 => COSTS_4_NAME.to_string(), }; Ok(result) } diff --git a/clarity/src/vm/functions/mod.rs b/clarity/src/vm/functions/mod.rs index 71d405313e3..001297bf53a 100644 --- a/clarity/src/vm/functions/mod.rs +++ b/clarity/src/vm/functions/mod.rs @@ -61,6 +61,8 @@ macro_rules! switch_on_global_epoch { StacksEpochId::Epoch32 => $Epoch205Version(args, env, context), // Note: We reuse 2.05 for 3.3. StacksEpochId::Epoch33 => $Epoch205Version(args, env, context), + // Note: We reuse 2.05 for 3.4. + StacksEpochId::Epoch34 => $Epoch205Version(args, env, context), } } }; diff --git a/clarity/src/vm/test_util/mod.rs b/clarity/src/vm/test_util/mod.rs index ff11cc9b3aa..53ea9e7319c 100644 --- a/clarity/src/vm/test_util/mod.rs +++ b/clarity/src/vm/test_util/mod.rs @@ -33,22 +33,10 @@ pub const TEST_BURN_STATE_DB_21: UnitTestBurnStateDB = UnitTestBurnStateDB { }; pub fn generate_test_burn_state_db(epoch_id: StacksEpochId) -> UnitTestBurnStateDB { - match epoch_id { - StacksEpochId::Epoch10 => { - panic!("Epoch 1.0 not testable"); - } - StacksEpochId::Epoch20 - | StacksEpochId::Epoch2_05 - | StacksEpochId::Epoch21 - | StacksEpochId::Epoch22 - | StacksEpochId::Epoch23 - | StacksEpochId::Epoch24 - | StacksEpochId::Epoch25 - | StacksEpochId::Epoch30 - | StacksEpochId::Epoch31 - | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => UnitTestBurnStateDB { epoch_id }, + if matches!(epoch_id, StacksEpochId::Epoch10) { + panic!("Epoch 1.0 not testable"); } + UnitTestBurnStateDB { epoch_id } } pub fn execute(s: &str) -> Value { diff --git a/clarity/src/vm/tests/conversions.rs b/clarity/src/vm/tests/conversions.rs index d26e4fd613a..7da816240a2 100644 --- a/clarity/src/vm/tests/conversions.rs +++ b/clarity/src/vm/tests/conversions.rs @@ -597,7 +597,7 @@ fn test_to_ascii(version: ClarityVersion, epoch: StacksEpochId) { } fn evaluate_to_ascii(snippet: &str) -> Value { - execute_versioned(snippet, ClarityVersion::Clarity4) + execute_versioned(snippet, ClarityVersion::latest()) .unwrap_or_else(|e| panic!("Execution failed for snippet `{snippet}`: {e:?}")) .unwrap_or_else(|| panic!("Execution returned no value for snippet `{snippet}`")) } @@ -690,7 +690,7 @@ proptest! { let evaluation = evaluate_to_ascii(&snippet); let ascii_snippet = &utf8_string[1..]; // Remove the u prefix - let expected_inner = execute_versioned(ascii_snippet, ClarityVersion::Clarity4) + let expected_inner = execute_versioned(ascii_snippet, ClarityVersion::latest()) .unwrap_or_else(|e| panic!("Execution failed for `{ascii_snippet}`: {e:?}")) .unwrap_or_else(|| panic!("Execution returned no value for `{ascii_snippet}`")); let expected = Value::okay(expected_inner).expect("response wrapping should succeed"); @@ -703,7 +703,7 @@ proptest! { let snippet = format!("(to-ascii? {utf8_string})"); let evaluation = evaluate_to_ascii(&snippet); - let literal_value = execute_versioned(&utf8_string, ClarityVersion::Clarity4) + let literal_value = execute_versioned(&utf8_string, ClarityVersion::latest()) .unwrap_or_else(|e| panic!("Execution failed for literal `{utf8_string}`: {e:?}")) .unwrap_or_else(|| panic!("Execution returned no value for literal `{utf8_string}`")); diff --git a/clarity/src/vm/tests/crypto.rs b/clarity/src/vm/tests/crypto.rs index 05d94603208..a54f117679f 100644 --- a/clarity/src/vm/tests/crypto.rs +++ b/clarity/src/vm/tests/crypto.rs @@ -64,8 +64,8 @@ fn test_secp256r1_verify_valid_signature_returns_true() { Value::Bool(true), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -85,8 +85,8 @@ fn test_secp256r1_verify_valid_high_s_signature_returns_true() { Value::Bool(true), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -110,8 +110,8 @@ fn test_secp256r1_verify_invalid_signature_returns_false() { Value::Bool(false), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -135,8 +135,8 @@ fn test_secp256r1_verify_signature_too_short_returns_false() { Value::Bool(false), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -158,8 +158,8 @@ fn test_secp256r1_verify_signature_too_long_errors() { let err = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .unwrap_err(); @@ -187,8 +187,8 @@ fn test_secp256k1_verify_valid_signature_returns_true() { Value::Bool(true), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -208,8 +208,8 @@ fn test_secp256k1_verify_valid_high_s_signature_returns_false() { Value::Bool(false), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -233,8 +233,8 @@ fn test_secp256k1_verify_invalid_signature_returns_false() { Value::Bool(false), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -258,8 +258,8 @@ fn test_secp256k1_verify_signature_too_short_returns_false() { Value::Bool(false), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -285,8 +285,8 @@ fn test_secp256k1_verify_recovery_id_out_of_range_returns_false() { Value::Bool(false), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -308,8 +308,8 @@ fn test_secp256k1_verify_signature_too_long_errors() { let err = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .unwrap_err(); @@ -337,8 +337,8 @@ fn test_secp256k1_recover_returns_expected_public_key() { Value::Bool(true), execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false ) .expect("execution should succeed") @@ -359,8 +359,8 @@ fn test_secp256k1_recover_invalid_signature_returns_err_code() { match execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .expect("execution should succeed") @@ -394,8 +394,8 @@ proptest! { let result = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .expect("execution should succeed") @@ -424,8 +424,8 @@ proptest! { let result = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .expect("execution should succeed") @@ -453,8 +453,8 @@ proptest! { let result = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .expect("execution should succeed") @@ -486,7 +486,7 @@ proptest! { buff_literal(&pubkey_bytes) ); let result = execute_with_parameters( - &program, ClarityVersion::Clarity4, StacksEpochId::Epoch33, false + &program, ClarityVersion::latest(), StacksEpochId::latest(), false ).unwrap().unwrap(); prop_assert_eq!(Value::Bool(false), result); @@ -516,8 +516,8 @@ proptest! { let result = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .expect("execution should succeed") @@ -551,8 +551,8 @@ proptest! { let result = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .expect("execution should succeed") @@ -583,7 +583,7 @@ proptest! { buff_literal(&pub_b_bytes) ); let result = execute_with_parameters( - &program, ClarityVersion::Clarity4, StacksEpochId::Epoch33, false + &program, ClarityVersion::latest(), StacksEpochId::latest(), false ).unwrap().unwrap(); prop_assert_eq!(Value::Bool(false), result); @@ -612,8 +612,8 @@ proptest! { let result = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .expect("execution should succeed") @@ -644,8 +644,8 @@ proptest! { let result = execute_with_parameters( program.as_str(), - ClarityVersion::Clarity4, - StacksEpochId::Epoch33, + ClarityVersion::latest(), + StacksEpochId::latest(), false, ) .expect("execution should succeed") diff --git a/clarity/src/vm/tests/mod.rs b/clarity/src/vm/tests/mod.rs index 3d4408abec3..e1becedd19a 100644 --- a/clarity/src/vm/tests/mod.rs +++ b/clarity/src/vm/tests/mod.rs @@ -127,6 +127,17 @@ macro_rules! clarity_template { (StacksEpochId::Epoch30, ClarityVersion::Clarity4) => (), (StacksEpochId::Epoch31, ClarityVersion::Clarity4) => (), (StacksEpochId::Epoch32, ClarityVersion::Clarity4) => (), + (StacksEpochId::Epoch20, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch2_05, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch21, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch22, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch23, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch24, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch25, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch30, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch31, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch32, ClarityVersion::Clarity5) => (), + (StacksEpochId::Epoch33, ClarityVersion::Clarity5) => (), // this will lead to a compile time failure if a pair is left out // of the clarity_template! macro list $((StacksEpochId::$epoch, ClarityVersion::$clarity))|* => (), @@ -154,6 +165,7 @@ epochs_template! { Epoch31, Epoch32, Epoch33, + Epoch34, } clarity_template! { @@ -182,6 +194,11 @@ clarity_template! { Epoch33_Clarity2: (Epoch33, Clarity2), Epoch33_Clarity3: (Epoch33, Clarity3), Epoch33_Clarity4: (Epoch33, Clarity4), + Epoch34_Clarity1: (Epoch34, Clarity1), + Epoch34_Clarity2: (Epoch34, Clarity2), + Epoch34_Clarity3: (Epoch34, Clarity3), + Epoch34_Clarity4: (Epoch34, Clarity4), + Epoch34_Clarity5: (Epoch34, Clarity5), } #[fixture] diff --git a/clarity/src/vm/tests/post_conditions.rs b/clarity/src/vm/tests/post_conditions.rs index 13fe9bcddf5..2788d7d92ad 100644 --- a/clarity/src/vm/tests/post_conditions.rs +++ b/clarity/src/vm/tests/post_conditions.rs @@ -1911,8 +1911,8 @@ proptest! { let snippet = format!("(restrict-assets? tx-sender () {body})"); let sender_principal = sender.clone().into(); assert_results_match( - (body.as_str(), ClarityVersion::Clarity4), - (snippet.as_str(), ClarityVersion::Clarity4), + (body.as_str(), ClarityVersion::latest()), + (snippet.as_str(), ClarityVersion::latest()), sender, |unrestricted_assets, restricted_assets| { let stx_moved = unrestricted_assets.get_stx(&sender_principal).unwrap_or(0); @@ -1952,8 +1952,8 @@ proptest! { }; assert_results_match( - (body_program.as_str(), ClarityVersion::Clarity4), - (wrapper_program.as_str(), ClarityVersion::Clarity4), + (body_program.as_str(), ClarityVersion::latest()), + (wrapper_program.as_str(), ClarityVersion::latest()), sender, move |unrestricted_assets, restricted_assets| { let moved = unrestricted_assets @@ -1995,8 +1995,8 @@ proptest! { }; assert_results_match( - (body_program.as_str(), ClarityVersion::Clarity4), - (wrapper_program.as_str(), ClarityVersion::Clarity4), + (body_program.as_str(), ClarityVersion::latest()), + (wrapper_program.as_str(), ClarityVersion::latest()), sender, move |unrestricted_assets, restricted_assets| { let moved = unrestricted_assets @@ -2062,7 +2062,7 @@ proptest! { let contract = PrincipalData::Contract(contract_id); assert_results_match( (c3_snippet.as_str(), ClarityVersion::Clarity3), - (snippet.as_str(), ClarityVersion::Clarity4), + (snippet.as_str(), ClarityVersion::latest()), sender, |unrestricted_assets, restricted_assets| { let stx_moved = unrestricted_assets.get_stx(&contract).unwrap_or(0); @@ -2088,7 +2088,7 @@ proptest! { let c3_snippet = format!("(as-contract {body})"); assert_results_match( (c3_snippet.as_str(), ClarityVersion::Clarity3), - (snippet.as_str(), ClarityVersion::Clarity4), + (snippet.as_str(), ClarityVersion::latest()), sender, |unrestricted_assets, restricted_assets| { prop_assert_eq!(unrestricted_assets, restricted_assets); @@ -2113,7 +2113,7 @@ proptest! { format!("{TOKEN_DEFINITIONS}(as-contract (begin {ft_mint} {nft_mint} {body}))"); assert_results_match( (c3_snippet.as_str(), ClarityVersion::Clarity3), - (snippet.as_str(), ClarityVersion::Clarity4), + (snippet.as_str(), ClarityVersion::latest()), sender, |unrestricted_assets, restricted_assets| { prop_assert_eq!(unrestricted_assets, restricted_assets); @@ -2136,7 +2136,7 @@ proptest! { let simple_snippet = format!("{TOKEN_DEFINITIONS}(begin {ft_mint} {nft_mint} {body})"); assert_results_match( (simple_snippet.as_str(), ClarityVersion::Clarity3), - (snippet.as_str(), ClarityVersion::Clarity4), + (snippet.as_str(), ClarityVersion::latest()), sender, |unrestricted_assets, restricted_assets| { prop_assert_eq!(unrestricted_assets, restricted_assets); diff --git a/clarity/src/vm/tests/proptest_utils.rs b/clarity/src/vm/tests/proptest_utils.rs index c4ccfee7876..a1677b8ded6 100644 --- a/clarity/src/vm/tests/proptest_utils.rs +++ b/clarity/src/vm/tests/proptest_utils.rs @@ -41,8 +41,8 @@ use crate::vm::contexts::GlobalContext; use crate::vm::database::STXBalance; use crate::vm::{execute_with_parameters_and_call_in_global_context, ClarityVersion}; -const DEFAULT_EPOCH: StacksEpochId = StacksEpochId::Epoch33; -const DEFAULT_CLARITY_VERSION: ClarityVersion = ClarityVersion::Clarity4; +const DEFAULT_EPOCH: StacksEpochId = StacksEpochId::Epoch34; +const DEFAULT_CLARITY_VERSION: ClarityVersion = ClarityVersion::Clarity5; const INITIAL_BALANCE: u128 = 1_000_000_000; const UTF8_SNIPPET_MAX_SEGMENTS: usize = 16; const UTF8_SIMPLE_ESCAPES: [&str; 6] = ["\\\"", "\\\\", "\\n", "\\t", "\\r", "\\0"]; diff --git a/clarity/src/vm/tests/variables.rs b/clarity/src/vm/tests/variables.rs index cbace07f7c0..14c36823acf 100644 --- a/clarity/src/vm/tests/variables.rs +++ b/clarity/src/vm/tests/variables.rs @@ -1216,8 +1216,8 @@ fn test_block_time( #[test] fn test_block_time_in_expressions() { - let version = ClarityVersion::Clarity4; - let epoch = StacksEpochId::Epoch33; + let version = ClarityVersion::latest(); + let epoch = StacksEpochId::latest(); let mut tl_env_factory = tl_env_factory(); let contract = r#" diff --git a/clarity/src/vm/version.rs b/clarity/src/vm/version.rs index 8b38563c41d..311658481a9 100644 --- a/clarity/src/vm/version.rs +++ b/clarity/src/vm/version.rs @@ -9,6 +9,7 @@ pub enum ClarityVersion { Clarity2, Clarity3, Clarity4, + Clarity5, } impl fmt::Display for ClarityVersion { @@ -18,6 +19,7 @@ impl fmt::Display for ClarityVersion { ClarityVersion::Clarity2 => write!(f, "Clarity 2"), ClarityVersion::Clarity3 => write!(f, "Clarity 3"), ClarityVersion::Clarity4 => write!(f, "Clarity 4"), + ClarityVersion::Clarity5 => write!(f, "Clarity 5"), } } } @@ -32,6 +34,7 @@ impl ClarityVersion { ClarityVersion::Clarity2, ClarityVersion::Clarity3, ClarityVersion::Clarity4, + ClarityVersion::Clarity5, ]; pub fn default_for_epoch(epoch_id: StacksEpochId) -> ClarityVersion { @@ -51,6 +54,7 @@ impl ClarityVersion { StacksEpochId::Epoch31 => ClarityVersion::Clarity3, StacksEpochId::Epoch32 => ClarityVersion::Clarity3, StacksEpochId::Epoch33 => ClarityVersion::Clarity4, + StacksEpochId::Epoch34 => ClarityVersion::Clarity5, } } } @@ -68,8 +72,10 @@ impl FromStr for ClarityVersion { Ok(ClarityVersion::Clarity3) } else if s == "clarity4" { Ok(ClarityVersion::Clarity4) + } else if s == "clarity5" { + Ok(ClarityVersion::Clarity5) } else { - Err("Invalid clarity version. Valid versions are: Clarity1, Clarity2, Clarity3, Clarity4.") + Err("Invalid clarity version. Valid versions are: Clarity1, Clarity2, Clarity3, Clarity4, Clarity5.") } } } diff --git a/stacks-common/src/libcommon.rs b/stacks-common/src/libcommon.rs index 5555c502417..5b4caf8ead5 100644 --- a/stacks-common/src/libcommon.rs +++ b/stacks-common/src/libcommon.rs @@ -88,6 +88,7 @@ pub mod consts { pub const PEER_VERSION_EPOCH_3_1: u8 = 0x0c; pub const PEER_VERSION_EPOCH_3_2: u8 = 0x0d; pub const PEER_VERSION_EPOCH_3_3: u8 = 0x0e; + pub const PEER_VERSION_EPOCH_3_4: u8 = 0x0f; /// 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 26fa440e3ff..6805f8fff43 100644 --- a/stacks-common/src/types/mod.rs +++ b/stacks-common/src/types/mod.rs @@ -33,7 +33,7 @@ use crate::consts::{ MICROSTACKS_PER_STACKS, 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_EPOCH_3_2, PEER_VERSION_EPOCH_3_3, + PEER_VERSION_EPOCH_3_1, PEER_VERSION_EPOCH_3_2, PEER_VERSION_EPOCH_3_3, PEER_VERSION_EPOCH_3_4, }; use crate::types::chainstate::{StacksAddress, StacksPublicKey}; use crate::util::hash::Hash160; @@ -130,6 +130,7 @@ define_stacks_epochs! { Epoch31 = 0x03001, Epoch32 = 0x03002, Epoch33 = 0x03003, + Epoch34 = 0x03004, } #[derive(Debug)] @@ -464,7 +465,7 @@ impl StacksEpochId { #[cfg(not(any(test, feature = "testing")))] pub const fn latest() -> StacksEpochId { - StacksEpochId::Epoch33 + StacksEpochId::Epoch34 } /// In this epoch, how should the mempool perform garbage collection? @@ -481,7 +482,8 @@ impl StacksEpochId { StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => MempoolCollectionBehavior::ByReceiveTime, + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => MempoolCollectionBehavior::ByReceiveTime, } } @@ -500,7 +502,8 @@ impl StacksEpochId { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => true, + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => true, } } @@ -519,7 +522,8 @@ impl StacksEpochId { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => true, + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => true, } } @@ -536,7 +540,7 @@ impl StacksEpochId { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => false, - StacksEpochId::Epoch33 => true, + StacksEpochId::Epoch33 | StacksEpochId::Epoch34 => true, } } @@ -555,7 +559,8 @@ impl StacksEpochId { StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => true, + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => true, } } @@ -574,7 +579,8 @@ impl StacksEpochId { StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => true, + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => true, } } @@ -592,7 +598,8 @@ impl StacksEpochId { StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => true, + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => true, } } @@ -626,7 +633,8 @@ impl StacksEpochId { StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => MINING_COMMITMENT_FREQUENCY_NAKAMOTO, + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => MINING_COMMITMENT_FREQUENCY_NAKAMOTO, } } @@ -665,7 +673,8 @@ impl StacksEpochId { StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => cur_reward_cycle > first_epoch30_reward_cycle, + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => cur_reward_cycle > first_epoch30_reward_cycle, } } @@ -781,8 +790,14 @@ impl StacksEpochId { | StacksEpochId::Epoch30 => { self.coinbase_reward_pre_sip029(first_burnchain_height, current_burnchain_height) } - StacksEpochId::Epoch31 | StacksEpochId::Epoch32 | StacksEpochId::Epoch33 => self - .coinbase_reward_sip029(mainnet, first_burnchain_height, current_burnchain_height), + StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => self.coinbase_reward_sip029( + mainnet, + first_burnchain_height, + current_burnchain_height, + ), } } @@ -799,7 +814,7 @@ impl StacksEpochId { | StacksEpochId::Epoch25 | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 => false, - StacksEpochId::Epoch32 | StacksEpochId::Epoch33 => true, + StacksEpochId::Epoch32 | StacksEpochId::Epoch33 | StacksEpochId::Epoch34 => true, } } @@ -816,7 +831,7 @@ impl StacksEpochId { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => false, - StacksEpochId::Epoch33 => true, + StacksEpochId::Epoch33 | StacksEpochId::Epoch34 => true, } } @@ -837,7 +852,7 @@ impl StacksEpochId { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => false, - StacksEpochId::Epoch33 => true, + StacksEpochId::Epoch33 | StacksEpochId::Epoch34 => true, } } @@ -856,7 +871,7 @@ impl StacksEpochId { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => false, - StacksEpochId::Epoch33 => true, + StacksEpochId::Epoch33 | StacksEpochId::Epoch34 => true, } } @@ -875,6 +890,7 @@ impl StacksEpochId { StacksEpochId::Epoch31 => PEER_VERSION_EPOCH_3_1, StacksEpochId::Epoch32 => PEER_VERSION_EPOCH_3_2, StacksEpochId::Epoch33 => PEER_VERSION_EPOCH_3_3, + StacksEpochId::Epoch34 => PEER_VERSION_EPOCH_3_4, } } @@ -904,6 +920,7 @@ impl std::fmt::Display for StacksEpochId { StacksEpochId::Epoch31 => write!(f, "3.1"), StacksEpochId::Epoch32 => write!(f, "3.2"), StacksEpochId::Epoch33 => write!(f, "3.3"), + StacksEpochId::Epoch34 => write!(f, "3.4"), } } } @@ -925,6 +942,7 @@ impl FromStr for StacksEpochId { "3.1" => Ok(StacksEpochId::Epoch31), "3.2" => Ok(StacksEpochId::Epoch32), "3.3" => Ok(StacksEpochId::Epoch33), + "3.4" => Ok(StacksEpochId::Epoch34), _ => Err("Invalid epoch string"), } } @@ -947,6 +965,7 @@ impl TryFrom for StacksEpochId { x if x == StacksEpochId::Epoch31 as u32 => Ok(StacksEpochId::Epoch31), x if x == StacksEpochId::Epoch32 as u32 => Ok(StacksEpochId::Epoch32), x if x == StacksEpochId::Epoch33 as u32 => Ok(StacksEpochId::Epoch33), + x if x == StacksEpochId::Epoch34 as u32 => Ok(StacksEpochId::Epoch34), _ => Err("Invalid epoch"), } } diff --git a/stacks-node/src/tests/nakamoto_integrations.rs b/stacks-node/src/tests/nakamoto_integrations.rs index 475054b0e45..07644534250 100644 --- a/stacks-node/src/tests/nakamoto_integrations.rs +++ b/stacks-node/src/tests/nakamoto_integrations.rs @@ -147,7 +147,7 @@ use stacks::config::DEFAULT_MAX_TENURE_BYTES; use crate::clarity::vm::clarity::ClarityConnection; lazy_static! { - pub static ref NAKAMOTO_INTEGRATION_EPOCHS: [StacksEpoch; 12] = [ + pub static ref NAKAMOTO_INTEGRATION_EPOCHS: [StacksEpoch; 13] = [ StacksEpoch { epoch_id: StacksEpochId::Epoch10, start_height: 0, @@ -228,6 +228,13 @@ lazy_static! { StacksEpoch { epoch_id: StacksEpochId::Epoch33, start_height: 252, + end_height: 253, + block_limit: HELIUM_BLOCK_LIMIT_20, + network_epoch: PEER_VERSION_EPOCH_3_2 + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch34, + start_height: 253, end_height: STACKS_EPOCH_MAX, block_limit: HELIUM_BLOCK_LIMIT_20, network_epoch: PEER_VERSION_EPOCH_3_2 @@ -15134,7 +15141,7 @@ fn check_block_time_keyword() { naka_conf.burnchain.chain_id, contract_name, contract, - Some(ClarityVersion::Clarity4), + Some(ClarityVersion::latest()), ); sender_nonce += 1; submit_tx(&http_origin, &contract_tx); @@ -15428,7 +15435,7 @@ fn check_with_stacking_allowances_delegate_stx() { naka_conf.burnchain.chain_id, contract_name, &contract, - Some(ClarityVersion::Clarity4), + Some(ClarityVersion::latest()), ); sender_nonce += 1; let deploy_txid = submit_tx(&http_origin, &contract_tx); @@ -15843,7 +15850,7 @@ fn check_with_stacking_allowances_stack_stx() { naka_conf.burnchain.chain_id, contract_name, &contract, - Some(ClarityVersion::Clarity4), + Some(ClarityVersion::latest()), ); sender_nonce += 1; let deploy_txid = submit_tx(&http_origin, &contract_tx); @@ -16521,7 +16528,7 @@ fn check_restrict_assets_rollback() { naka_conf.burnchain.chain_id, contract_name, &contract, - Some(ClarityVersion::Clarity4), + Some(ClarityVersion::latest()), ); sender_nonce += 1; let deploy_txid = submit_tx(&http_origin, &contract_tx); @@ -17237,7 +17244,7 @@ fn check_as_contract_rollback() { naka_conf.burnchain.chain_id, contract_name, &contract, - Some(ClarityVersion::Clarity4), + Some(ClarityVersion::latest()), ); sender_nonce += 1; let deploy_txid = submit_tx(&http_origin, &contract_tx); diff --git a/stacks-node/src/tests/signer/v0.rs b/stacks-node/src/tests/signer/v0.rs index 9b6f50e5da5..e5e0b15ec36 100644 --- a/stacks-node/src/tests/signer/v0.rs +++ b/stacks-node/src/tests/signer/v0.rs @@ -3142,6 +3142,8 @@ fn bitcoind_forking_test() { epochs[StacksEpochId::Epoch32].start_height = 3_055; epochs[StacksEpochId::Epoch32].end_height = 3_065; epochs[StacksEpochId::Epoch33].start_height = 3_065; + epochs[StacksEpochId::Epoch33].end_height = 3_075; + epochs[StacksEpochId::Epoch34].start_height = 3_075; }, None, None, diff --git a/stackslib/src/chainstate/burn/db/sortdb.rs b/stackslib/src/chainstate/burn/db/sortdb.rs index 9bb99f7afc3..b593a604a47 100644 --- a/stackslib/src/chainstate/burn/db/sortdb.rs +++ b/stackslib/src/chainstate/burn/db/sortdb.rs @@ -3097,6 +3097,7 @@ impl SortitionDB { StacksEpochId::Epoch31 => version >= 3, StacksEpochId::Epoch32 => version >= 3, StacksEpochId::Epoch33 => version >= 3, + StacksEpochId::Epoch34 => version >= 3, } } diff --git a/stackslib/src/chainstate/burn/operations/leader_block_commit.rs b/stackslib/src/chainstate/burn/operations/leader_block_commit.rs index 61852b64d0d..74994df687b 100644 --- a/stackslib/src/chainstate/burn/operations/leader_block_commit.rs +++ b/stackslib/src/chainstate/burn/operations/leader_block_commit.rs @@ -869,7 +869,8 @@ impl LeaderBlockCommitOp { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => { + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => { // 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 26f22dab0dd..e7651db84be 100644 --- a/stackslib/src/chainstate/coordinator/mod.rs +++ b/stackslib/src/chainstate/coordinator/mod.rs @@ -405,8 +405,9 @@ impl OnChainRewardSetProvider<'_, T> { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => { - // Epoch 2.5, 3.0, 3.1 and 3.2 compute reward sets, but *only* if PoX-4 is active + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => { + // Epoch 2.5 and up 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/nakamoto/coordinator/tests.rs b/stackslib/src/chainstate/nakamoto/coordinator/tests.rs index 9ba2ba59a2f..ecb8e628d9e 100644 --- a/stackslib/src/chainstate/nakamoto/coordinator/tests.rs +++ b/stackslib/src/chainstate/nakamoto/coordinator/tests.rs @@ -1073,6 +1073,7 @@ fn block_info_tests(use_primary_testnet: bool) { ClarityVersion::Clarity2 => panic!("Clarity2 not supported in this test"), ClarityVersion::Clarity3 => &clar3_contract_id, ClarityVersion::Clarity4 => &clar4_contract_id, + ClarityVersion::Clarity5 => panic!("Clarity5 not supported in this test"), }; peer.with_db_state(|sortdb, chainstate, _, _| { let sortdb_handle = sortdb.index_handle_at_tip(); @@ -3387,7 +3388,7 @@ pub fn simple_nakamoto_coordinator_sip034_tenure_extensions( &format!("test-{contract_count}"), smart_contract, &private_key, - ClarityVersion::Clarity4, + ClarityVersion::latest(), account.nonce, u64::try_from(smart_contract.len() * 2).unwrap(), ); diff --git a/stackslib/src/chainstate/stacks/db/blocks.rs b/stackslib/src/chainstate/stacks/db/blocks.rs index d81bd28d802..4bdd15d12b6 100644 --- a/stackslib/src/chainstate/stacks/db/blocks.rs +++ b/stackslib/src/chainstate/stacks/db/blocks.rs @@ -4022,7 +4022,11 @@ impl StacksChainState { current_epoch = StacksEpochId::Epoch33; } StacksEpochId::Epoch33 => { - panic!("No defined transition from Epoch33 forward") + receipts.append(&mut clarity_tx.block.initialize_epoch_3_4()?); + current_epoch = StacksEpochId::Epoch34; + } + StacksEpochId::Epoch34 => { + panic!("No defined transition from Epoch34 forward") } } @@ -4863,7 +4867,8 @@ impl StacksChainState { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => { + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => { StacksChainState::get_stacking_and_transfer_and_delegate_burn_ops_v210( chainstate_tx, parent_index_hash, @@ -4957,7 +4962,8 @@ impl StacksChainState { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => Self::handle_pox_cycle_start_pox_4( + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => Self::handle_pox_cycle_start_pox_4( clarity_tx, pox_reward_cycle, pox_start_cycle_info, diff --git a/stackslib/src/chainstate/stacks/db/mod.rs b/stackslib/src/chainstate/stacks/db/mod.rs index dae996501c1..f2012772da2 100644 --- a/stackslib/src/chainstate/stacks/db/mod.rs +++ b/stackslib/src/chainstate/stacks/db/mod.rs @@ -296,7 +296,8 @@ impl DBConfig { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => (3..=CHAINSTATE_VERSION_NUMBER).contains(&version_u32), + | StacksEpochId::Epoch33 + | StacksEpochId::Epoch34 => (3..=CHAINSTATE_VERSION_NUMBER).contains(&version_u32), } } } diff --git a/stackslib/src/chainstate/stacks/db/transactions.rs b/stackslib/src/chainstate/stacks/db/transactions.rs index fb587c6876d..e5173e4a0ac 100644 --- a/stackslib/src/chainstate/stacks/db/transactions.rs +++ b/stackslib/src/chainstate/stacks/db/transactions.rs @@ -1702,6 +1702,9 @@ pub mod test { pub const TestBurnStateDB_33: UnitTestBurnStateDB = UnitTestBurnStateDB { epoch_id: StacksEpochId::Epoch33, }; + pub const TestBurnStateDB_34: UnitTestBurnStateDB = UnitTestBurnStateDB { + epoch_id: StacksEpochId::Epoch34, + }; pub const ALL_BURN_DBS: &[&dyn BurnStateDB] = &[ &TestBurnStateDB_20 as &dyn BurnStateDB, @@ -1711,6 +1714,7 @@ pub mod test { &TestBurnStateDB_31 as &dyn BurnStateDB, &TestBurnStateDB_32 as &dyn BurnStateDB, &TestBurnStateDB_33 as &dyn BurnStateDB, + &TestBurnStateDB_34 as &dyn BurnStateDB, ]; pub const PRE_33_DBS: &[&dyn BurnStateDB] = &[ @@ -1732,6 +1736,7 @@ pub mod test { &TestBurnStateDB_31 as &dyn BurnStateDB, &TestBurnStateDB_32 as &dyn BurnStateDB, &TestBurnStateDB_33 as &dyn BurnStateDB, + &TestBurnStateDB_34 as &dyn BurnStateDB, ]; #[test] @@ -8564,6 +8569,7 @@ pub mod test { StacksEpochId::Epoch31 => self.get_stacks_epoch(8), StacksEpochId::Epoch32 => self.get_stacks_epoch(9), StacksEpochId::Epoch33 => self.get_stacks_epoch(10), + StacksEpochId::Epoch34 => self.get_stacks_epoch(11), } } fn get_pox_payout_addrs( diff --git a/stackslib/src/chainstate/stacks/tests/reward_set.rs b/stackslib/src/chainstate/stacks/tests/reward_set.rs index 15d1ab1ec5f..b1cbf0f163d 100644 --- a/stackslib/src/chainstate/stacks/tests/reward_set.rs +++ b/stackslib/src/chainstate/stacks/tests/reward_set.rs @@ -53,7 +53,7 @@ pub fn check_make_reward_set( prop_assume!(threshold > 0); let reward_set = - StacksChainState::make_reward_set(threshold, addresses.to_vec(), StacksEpochId::Epoch33); + StacksChainState::make_reward_set(threshold, addresses.to_vec(), StacksEpochId::latest()); prop_assert_eq!(Some(threshold), reward_set.pox_ustx_threshold); diff --git a/stackslib/src/chainstate/stacks/transaction.rs b/stackslib/src/chainstate/stacks/transaction.rs index 304e4ad5546..186a71b05c8 100644 --- a/stackslib/src/chainstate/stacks/transaction.rs +++ b/stackslib/src/chainstate/stacks/transaction.rs @@ -114,6 +114,7 @@ fn ClarityVersion_consensus_serialize( ClarityVersion::Clarity2 => write_next(fd, &2u8)?, ClarityVersion::Clarity3 => write_next(fd, &3u8)?, ClarityVersion::Clarity4 => write_next(fd, &4u8)?, + ClarityVersion::Clarity5 => write_next(fd, &5u8)?, } Ok(()) } @@ -127,6 +128,7 @@ fn ClarityVersion_consensus_deserialize( 2u8 => Ok(ClarityVersion::Clarity2), 3u8 => Ok(ClarityVersion::Clarity3), 4u8 => Ok(ClarityVersion::Clarity4), + 5u8 => Ok(ClarityVersion::Clarity5), _ => Err(codec_error::DeserializeError(format!( "Unrecognized ClarityVersion byte {}", &version_byte diff --git a/stackslib/src/chainstate/tests/consensus.rs b/stackslib/src/chainstate/tests/consensus.rs index 8959247085a..ef010481e8c 100644 --- a/stackslib/src/chainstate/tests/consensus.rs +++ b/stackslib/src/chainstate/tests/consensus.rs @@ -52,7 +52,7 @@ use crate::net::tests::NakamotoBootPlan; /// The epochs to test for consensus are the current and upcoming epochs. /// This constant must be changed when new epochs are introduced. /// Note that contract deploys MUST be done in each epoch >= 2.0. -pub const EPOCHS_TO_TEST: &[StacksEpochId] = &[StacksEpochId::Epoch33]; +pub const EPOCHS_TO_TEST: &[StacksEpochId] = &[StacksEpochId::Epoch33, StacksEpochId::Epoch34]; pub const SK_1: &str = "a1289f6438855da7decf9b61b852c882c398cff1446b2a0f823538aa2ebef92e01"; pub const SK_2: &str = "4ce9a8f7539ea93753a36405b16e8b57e15a552430410709c2b6d65dca5c02e201"; @@ -91,6 +91,13 @@ pub const fn clarity_versions_for_epoch(epoch: StacksEpochId) -> &'static [Clari ClarityVersion::Clarity3, ClarityVersion::Clarity4, ], + StacksEpochId::Epoch34 => &[ + ClarityVersion::Clarity1, + ClarityVersion::Clarity2, + ClarityVersion::Clarity3, + ClarityVersion::Clarity4, + ClarityVersion::Clarity5, + ], } } @@ -371,7 +378,10 @@ impl ConsensusChain<'_> { let num_blocks = num_blocks_per_epoch.get(epoch_id).copied().unwrap_or(0) + 1; place_blocks_avoiding_prepare(start_height, num_blocks) + 1 } - StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 => { + StacksEpochId::Epoch30 + | StacksEpochId::Epoch31 + | StacksEpochId::Epoch32 + | StacksEpochId::Epoch33 => { // Only need 1 block per Epoch if num_blocks_per_epoch.contains_key(epoch_id) { start_height + 1 @@ -382,7 +392,7 @@ impl ConsensusChain<'_> { } } // The last Epoch height never ends - StacksEpochId::Epoch33 => STACKS_EPOCH_MAX, + StacksEpochId::Epoch34 => STACKS_EPOCH_MAX, }; // Special case the Epoch 2.5 -> Epoch 3.0 transition diff --git a/stackslib/src/chainstate/tests/mod.rs b/stackslib/src/chainstate/tests/mod.rs index 57fc8de894d..aef09ef0820 100644 --- a/stackslib/src/chainstate/tests/mod.rs +++ b/stackslib/src/chainstate/tests/mod.rs @@ -25,7 +25,7 @@ use clarity::consts::{ 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_EPOCH_3_2, - PEER_VERSION_EPOCH_3_3, STACKS_EPOCH_MAX, + PEER_VERSION_EPOCH_3_3, PEER_VERSION_EPOCH_3_4, STACKS_EPOCH_MAX, }; use clarity::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, StacksAddress, StacksBlockId, @@ -1752,10 +1752,17 @@ impl<'a> TestChainstate<'a> { StacksEpoch { epoch_id: StacksEpochId::Epoch33, start_height: first_burnchain_height + 3, - end_height: STACKS_EPOCH_MAX, + end_height: first_burnchain_height + 4, block_limit: BLOCK_LIMIT_MAINNET_21.clone(), network_epoch: PEER_VERSION_EPOCH_3_3, }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch34, + start_height: first_burnchain_height + 4, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_4, + }, ]) } @@ -1847,9 +1854,16 @@ impl<'a> TestChainstate<'a> { StacksEpoch { epoch_id: StacksEpochId::Epoch33, start_height: first_burnchain_height + 25, + end_height: first_burnchain_height + 26, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_3, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch34, + start_height: first_burnchain_height + 26, end_height: STACKS_EPOCH_MAX, block_limit: BLOCK_LIMIT_MAINNET_21.clone(), - network_epoch: PEER_VERSION_EPOCH_3_2, + network_epoch: PEER_VERSION_EPOCH_3_4, }, ]) } @@ -1889,6 +1903,7 @@ fn advance_through_all_epochs() { StacksEpochId::Epoch31, StacksEpochId::Epoch32, StacksEpochId::Epoch33, + StacksEpochId::Epoch34, ] { chainstate.advance_to_epoch_boundary(&privk, target_epoch); let burn_block_height = chainstate.get_burn_block_height(); @@ -1955,18 +1970,18 @@ fn advance_through_nakamoto_bootstrapped() { boot_plan = boot_plan.with_epochs(epochs); let mut chainstate = boot_plan.to_chainstate(None, Some(activation_height.into())); // Make sure we can advance through every single epoch. - chainstate.advance_to_epoch_boundary(&privk, StacksEpochId::Epoch33); + chainstate.advance_to_epoch_boundary(&privk, StacksEpochId::Epoch34); let burn_block_height = chainstate.get_burn_block_height(); let current_epoch = SortitionDB::get_stacks_epoch(chainstate.sortdb().conn(), burn_block_height) .unwrap() .unwrap() .epoch_id; - assert_eq!(current_epoch, StacksEpochId::Epoch32); + assert_eq!(current_epoch, StacksEpochId::Epoch33); let next_epoch = SortitionDB::get_stacks_epoch(chainstate.sortdb().conn(), burn_block_height + 1) .unwrap() .unwrap() .epoch_id; - assert_eq!(next_epoch, StacksEpochId::Epoch33); + assert_eq!(next_epoch, StacksEpochId::Epoch34); } diff --git a/stackslib/src/chainstate/tests/runtime_analysis_tests.rs b/stackslib/src/chainstate/tests/runtime_analysis_tests.rs index 22a688127ca..9228ae4b891 100644 --- a/stackslib/src/chainstate/tests/runtime_analysis_tests.rs +++ b/stackslib/src/chainstate/tests/runtime_analysis_tests.rs @@ -1185,7 +1185,12 @@ fn check_error_kind_could_not_determine_type_ccall() { function_args: &[], deploy_epochs: &[StacksEpochId::Epoch23], call_epochs: &StacksEpochId::since(StacksEpochId::Epoch24), - exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity3, ClarityVersion::Clarity4], + exclude_clarity_versions: &[ + ClarityVersion::Clarity1, + ClarityVersion::Clarity3, + ClarityVersion::Clarity4, + ClarityVersion::Clarity5 + ], setup_contracts: &[trait_contract, trait_impl], ); } diff --git a/stackslib/src/chainstate/tests/static_analysis_tests.rs b/stackslib/src/chainstate/tests/static_analysis_tests.rs index 1b918fd2945..3049f11d17a 100644 --- a/stackslib/src/chainstate/tests/static_analysis_tests.rs +++ b/stackslib/src/chainstate/tests/static_analysis_tests.rs @@ -1099,7 +1099,11 @@ fn static_check_error_get_block_info_expect_property_name() { contract_deploy_consensus_test!( contract_name: "info-exp-prop-name", contract_code: "(get-block-info? u1 u0)", - exclude_clarity_versions: &[ClarityVersion::Clarity3, ClarityVersion::Clarity4], + exclude_clarity_versions: &[ + ClarityVersion::Clarity3, + ClarityVersion::Clarity4, + ClarityVersion::Clarity5 + ], ); } diff --git a/stackslib/src/clarity_vm/clarity.rs b/stackslib/src/clarity_vm/clarity.rs index b563bbbc959..dd7600aefa2 100644 --- a/stackslib/src/clarity_vm/clarity.rs +++ b/stackslib/src/clarity_vm/clarity.rs @@ -1922,6 +1922,32 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } + pub fn initialize_epoch_3_4(&mut self) -> Result, ClarityError> { + // 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::Epoch34; + self.as_transaction(|tx_conn| { + // bump the epoch in the Clarity DB + tx_conn + .with_clarity_db(|db| { + db.set_clarity_epoch_version(StacksEpochId::Epoch34)?; + Ok(()) + }) + .unwrap(); + + // require 3.4 rules henceforth in this connection as well + tx_conn.epoch = StacksEpochId::Epoch34; + }); + + debug!("Epoch 3.4 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 949b522077c..777e3fdac89 100644 --- a/stackslib/src/clarity_vm/tests/large_contract.rs +++ b/stackslib/src/clarity_vm/tests/large_contract.rs @@ -195,7 +195,7 @@ fn test_simple_token_system(#[case] version: ClarityVersion, #[case] epoch: Stac ) .unwrap(); } - StacksEpochId::Epoch33 => { + StacksEpochId::Epoch33 | StacksEpochId::Epoch34 => { let (ast, _analysis) = tx .analyze_smart_contract( &boot_code_id("costs-4", false), diff --git a/stackslib/src/config/mod.rs b/stackslib/src/config/mod.rs index 4305a1bcc89..48f98f5cefe 100644 --- a/stackslib/src/config/mod.rs +++ b/stackslib/src/config/mod.rs @@ -720,6 +720,8 @@ impl Config { Ok(StacksEpochId::Epoch32) } else if epoch_name == EPOCH_CONFIG_3_3_0 { Ok(StacksEpochId::Epoch33) + } else if epoch_name == EPOCH_CONFIG_3_4_0 { + Ok(StacksEpochId::Epoch34) } else { Err(format!("Unknown epoch name specified: {epoch_name}")) }?; @@ -749,6 +751,7 @@ impl Config { StacksEpochId::Epoch31, StacksEpochId::Epoch32, StacksEpochId::Epoch33, + StacksEpochId::Epoch34, ]; for (expected_epoch, configured_epoch) in expected_list .iter() @@ -1712,6 +1715,7 @@ 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"; pub const EPOCH_CONFIG_3_3_0: &str = "3.3"; +pub const EPOCH_CONFIG_3_4_0: &str = "3.4"; #[derive(Clone, Deserialize, Default, Debug)] #[serde(deny_unknown_fields)] diff --git a/stackslib/src/core/mod.rs b/stackslib/src/core/mod.rs index f32a4d7ffd1..a5372d12174 100644 --- a/stackslib/src/core/mod.rs +++ b/stackslib/src/core/mod.rs @@ -18,7 +18,6 @@ use std::cmp::Ordering; use std::collections::HashSet; -use clarity::consts::PEER_VERSION_EPOCH_3_3; use clarity::vm::costs::ExecutionCost; use lazy_static::lazy_static; pub use stacks_common::consts::MICROSTACKS_PER_STACKS; @@ -51,8 +50,9 @@ 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_EPOCH_3_2, 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_EPOCH_3_3, PEER_VERSION_EPOCH_3_4, + PEER_VERSION_MAINNET, PEER_VERSION_MAINNET_MAJOR, PEER_VERSION_TESTNET, + PEER_VERSION_TESTNET_MAJOR, STACKS_EPOCH_MAX, }; // default port @@ -110,6 +110,8 @@ pub const BITCOIN_MAINNET_STACKS_31_BURN_HEIGHT: u64 = 875_000; pub const BITCOIN_MAINNET_STACKS_32_BURN_HEIGHT: u64 = 907_740; /// This is Epoch-3.3, activation timing proposed in SIP-033 pub const BITCOIN_MAINNET_STACKS_33_BURN_HEIGHT: u64 = 923_222; +/// This is Epoch-3.4, activation timing will be proposed in a future SIP +pub const BITCOIN_MAINNET_STACKS_34_BURN_HEIGHT: u64 = 3_400_000; /// Bitcoin mainline testnet3 activation heights. /// TODO: No longer used since testnet3 is dead, so remove. @@ -127,6 +129,7 @@ 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; pub const BITCOIN_TESTNET_STACKS_33_BURN_HEIGHT: u64 = 30_000_003; +pub const BITCOIN_TESTNET_STACKS_34_BURN_HEIGHT: u64 = 30_000_004; pub const BITCOIN_REGTEST_FIRST_BLOCK_HEIGHT: u64 = 0; pub const BITCOIN_REGTEST_FIRST_BLOCK_TIMESTAMP: u32 = 0; @@ -325,10 +328,17 @@ lazy_static! { StacksEpoch { epoch_id: StacksEpochId::Epoch33, start_height: BITCOIN_MAINNET_STACKS_33_BURN_HEIGHT, - end_height: STACKS_EPOCH_MAX, + end_height: BITCOIN_MAINNET_STACKS_34_BURN_HEIGHT, block_limit: BLOCK_LIMIT_MAINNET_21, network_epoch: PEER_VERSION_EPOCH_3_3 }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch34, + start_height: BITCOIN_MAINNET_STACKS_34_BURN_HEIGHT, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21, + network_epoch: PEER_VERSION_EPOCH_3_4 + }, ]); } @@ -414,10 +424,17 @@ lazy_static! { StacksEpoch { epoch_id: StacksEpochId::Epoch33, start_height: BITCOIN_TESTNET_STACKS_33_BURN_HEIGHT, - end_height: STACKS_EPOCH_MAX, + end_height: BITCOIN_TESTNET_STACKS_34_BURN_HEIGHT, block_limit: BLOCK_LIMIT_MAINNET_21, network_epoch: PEER_VERSION_EPOCH_3_3 }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch34, + start_height: BITCOIN_TESTNET_STACKS_34_BURN_HEIGHT, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21, + network_epoch: PEER_VERSION_EPOCH_3_4 + }, ]); } @@ -503,10 +520,17 @@ lazy_static! { StacksEpoch { epoch_id: StacksEpochId::Epoch33, start_height: 10001, - end_height: STACKS_EPOCH_MAX, + end_height: 11001, block_limit: BLOCK_LIMIT_MAINNET_21, network_epoch: PEER_VERSION_EPOCH_3_3 }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch34, + start_height: 11001, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21, + network_epoch: PEER_VERSION_EPOCH_3_4 + }, ]); } @@ -553,6 +577,10 @@ pub static STACKS_EPOCH_3_2_MARKER: u8 = 0x0e; /// *or greater*. pub static STACKS_EPOCH_3_3_MARKER: u8 = 0x0f; +/// Stacks 3.4 epoch marker. All block-commits in 3.4 must have a memo bitfield with this value +/// *or greater*. +pub static STACKS_EPOCH_3_4_MARKER: u8 = 0x10; + /// Latest Stacks epoch marker. Automatically uses the marker for the highest supported epoch. pub static STACKS_EPOCH_LATEST_MARKER: u8 = marker_for_epoch(StacksEpochId::latest()).expect("Latest epoch should always have a marker"); @@ -571,6 +599,7 @@ pub const fn marker_for_epoch(epoch_id: StacksEpochId) -> Option { StacksEpochId::Epoch31 => Some(STACKS_EPOCH_3_1_MARKER), StacksEpochId::Epoch32 => Some(STACKS_EPOCH_3_2_MARKER), StacksEpochId::Epoch33 => Some(STACKS_EPOCH_3_3_MARKER), + StacksEpochId::Epoch34 => Some(STACKS_EPOCH_3_4_MARKER), } } @@ -859,6 +888,8 @@ pub trait StacksEpochExtension { #[cfg(test)] fn unit_test_3_3(epoch_2_0_block_height: u64) -> EpochList; #[cfg(test)] + fn unit_test_3_4(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; @@ -866,6 +897,8 @@ pub trait StacksEpochExtension { fn unit_test_3_2_only(first_burnchain_height: u64) -> EpochList; #[cfg(test)] fn unit_test_3_3_only(first_burnchain_height: u64) -> EpochList; + #[cfg(test)] + fn unit_test_3_4_only(first_burnchain_height: u64) -> EpochList; fn all( epoch_2_0_block_height: u64, epoch_2_05_block_height: u64, @@ -1926,8 +1959,176 @@ impl StacksEpochExtension for StacksEpoch { read_count: 210210, runtime: 210210, }, + network_epoch: PEER_VERSION_EPOCH_3_3, + }, + ]) + } + + #[cfg(test)] + fn unit_test_3_4(first_burnchain_height: u64) -> EpochList { + info!( + "StacksEpoch unit_test_3_4 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: first_burnchain_height + 40, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, network_epoch: PEER_VERSION_EPOCH_3_2, }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch33, + start_height: first_burnchain_height + 40, + end_height: first_burnchain_height + 44, + block_limit: ExecutionCost { + write_length: 210210, + write_count: 210210, + read_length: 210210, + read_count: 210210, + runtime: 210210, + }, + network_epoch: PEER_VERSION_EPOCH_3_3, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch34, + start_height: first_burnchain_height + 44, + 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_4, + }, ]) } @@ -2239,6 +2440,108 @@ impl StacksEpochExtension for StacksEpoch { ]) } + #[cfg(test)] + fn unit_test_3_4_only(first_burnchain_height: u64) -> EpochList { + info!( + "StacksEpoch unit_test first_burn_height = {}", + first_burnchain_height + ); + + EpochList::new(&[ + StacksEpoch { + epoch_id: StacksEpochId::Epoch10, + start_height: 0, + end_height: 0, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_1_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch20, + start_height: 0, + end_height: 0, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_2_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch2_05, + start_height: 0, + end_height: 0, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_2_05, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch21, + start_height: 0, + end_height: 0, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_2_1, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch22, + start_height: 0, + end_height: 0, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_2_2, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch23, + start_height: 0, + end_height: 0, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_2_3, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch24, + start_height: 0, + end_height: 0, + block_limit: ExecutionCost::max_value(), + network_epoch: PEER_VERSION_EPOCH_2_4, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch25, + start_height: 0, + end_height: first_burnchain_height, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_2_4, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch30, + start_height: first_burnchain_height, + end_height: first_burnchain_height, + block_limit: BLOCK_LIMIT_MAINNET_21, + network_epoch: PEER_VERSION_EPOCH_3_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch31, + start_height: first_burnchain_height, + end_height: first_burnchain_height, + block_limit: BLOCK_LIMIT_MAINNET_21, + network_epoch: PEER_VERSION_EPOCH_3_1, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch32, + start_height: first_burnchain_height, + end_height: first_burnchain_height, + block_limit: BLOCK_LIMIT_MAINNET_21, + network_epoch: PEER_VERSION_EPOCH_3_2, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch33, + start_height: first_burnchain_height, + end_height: first_burnchain_height, + block_limit: BLOCK_LIMIT_MAINNET_21, + network_epoch: PEER_VERSION_EPOCH_3_3, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch34, + start_height: first_burnchain_height, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21, + network_epoch: PEER_VERSION_EPOCH_3_4, + }, + ]) + } + #[cfg(test)] fn unit_test(stacks_epoch_id: StacksEpochId, first_burnchain_height: u64) -> EpochList { match stacks_epoch_id { @@ -2255,6 +2558,7 @@ impl StacksEpochExtension for StacksEpoch { StacksEpochId::Epoch31 => StacksEpoch::unit_test_3_1(first_burnchain_height), StacksEpochId::Epoch32 => StacksEpoch::unit_test_3_2(first_burnchain_height), StacksEpochId::Epoch33 => StacksEpoch::unit_test_3_3(first_burnchain_height), + StacksEpochId::Epoch34 => StacksEpoch::unit_test_3_4(first_burnchain_height), } } @@ -2320,8 +2624,8 @@ impl StacksEpochExtension for StacksEpoch { // Allow epochs up to one version ahead of latest() for development purposes assert!(StacksEpochId::latest() >= max_epoch.epoch_id - || (StacksEpochId::latest() == StacksEpochId::Epoch32 - && max_epoch.epoch_id == StacksEpochId::Epoch33), + || (StacksEpochId::latest() == StacksEpochId::Epoch33 + && max_epoch.epoch_id == StacksEpochId::Epoch34), "StacksEpochId::latest() should be greater than or equal to any epoch defined in the node (except for development epochs)" ); diff --git a/stackslib/src/cost_estimates/pessimistic.rs b/stackslib/src/cost_estimates/pessimistic.rs index b2b42a79414..73e66a24466 100644 --- a/stackslib/src/cost_estimates/pessimistic.rs +++ b/stackslib/src/cost_estimates/pessimistic.rs @@ -226,6 +226,8 @@ impl PessimisticEstimator { StacksEpochId::Epoch32 => ":2.1", // reuse cost estimates in Epoch33 StacksEpochId::Epoch33 => ":2.1", + // reuse cost estimates in Epoch34 + StacksEpochId::Epoch34 => ":2.1", }; format!( "cc{}:{}:{}.{}", diff --git a/stackslib/src/net/tests/relay/epoch2x.rs b/stackslib/src/net/tests/relay/epoch2x.rs index 64db7bd6d05..a7546f730b5 100644 --- a/stackslib/src/net/tests/relay/epoch2x.rs +++ b/stackslib/src/net/tests/relay/epoch2x.rs @@ -2692,6 +2692,7 @@ fn static_problematic_txs_pre_epoch21(#[case] epoch_id: StacksEpochId) { #[case::epoch_31(StacksEpochId::Epoch31)] #[case::epoch_32(StacksEpochId::Epoch32)] #[case::epoch_33(StacksEpochId::Epoch33)] +#[case::epoch_34(StacksEpochId::Epoch34)] fn static_problematic_txs_post_epoch21(#[case] epoch_id: StacksEpochId) { let DeepTransactions { tx_high,