diff --git a/stackslib/src/chainstate/tests/consensus.rs b/stackslib/src/chainstate/tests/consensus.rs index 8da0339e4b..6d5371ac88 100644 --- a/stackslib/src/chainstate/tests/consensus.rs +++ b/stackslib/src/chainstate/tests/consensus.rs @@ -1021,6 +1021,7 @@ impl ContractConsensusTest<'_> { /// * `contract_code` - Clarity source code of the contract /// * `function_name` - Contract function to test /// * `function_args` - Arguments passed to `function_name` on every call + /// * `exclude_clarity_versions` - List of Clarity versions to exclude from testing. For each epoch to test, at least a clarity version must available. /// * `setup_contracts` - Contracts that must be deployed before epoch-specific logic runs /// /// # Panics @@ -1037,12 +1038,22 @@ impl ContractConsensusTest<'_> { contract_code: &str, function_name: &str, function_args: &[ClarityValue], + exclude_clarity_versions: &[ClarityVersion], setup_contracts: &[SetupContract], ) -> Self { assert!( !deploy_epochs.is_empty(), "At least one deploy epoch is required" ); + for epoch in deploy_epochs { + let supported_versions = clarity_versions_for_epoch(*epoch); + assert!( + supported_versions + .iter() + .any(|version| !exclude_clarity_versions.contains(version)), + "Epoch {epoch} does not have any Clarity versions available after applying exclusions", + ); + } let min_deploy_epoch = deploy_epochs.iter().min().unwrap(); assert!( call_epochs.iter().all(|e| e >= min_deploy_epoch), @@ -1054,6 +1065,7 @@ impl ContractConsensusTest<'_> { .all(|c| c.deploy_epoch.is_none() || c.deploy_epoch.unwrap() >= *min_deploy_epoch), "All setup contracts must have a deploy epoch >= the minimum deploy epoch" ); + // Build epoch_blocks map based on deploy and call epochs let mut num_blocks_per_epoch: HashMap = HashMap::new(); let mut contract_deploys_per_epoch: HashMap> = @@ -1103,7 +1115,12 @@ impl ContractConsensusTest<'_> { } if deploy_epochs.contains(epoch) { - let clarity_versions = clarity_versions_for_epoch(*epoch); + let clarity_versions_per_epoch = clarity_versions_for_epoch(*epoch); + // Exclude the clarity versions that are in the exclude_clarity_versions list. + let clarity_versions = clarity_versions_per_epoch + .iter() + .filter(|v| !exclude_clarity_versions.contains(v)); + let epoch_name = format!("Epoch{}", epoch.to_string().replace('.', "_")); // Each deployment is a seperate TestBlock @@ -1568,6 +1585,7 @@ impl TestTxFactory { /// * `function_args` — Function arguments, provided as a slice of [`ClarityValue`]. /// * `deploy_epochs` — *(optional)* Epochs in which to deploy the contract. Defaults to all epochs ≥ 2.0. /// * `call_epochs` — *(optional)* Epochs in which to call the function. Defaults to [`EPOCHS_TO_TEST`]. +/// * `clarity_versions` — *(optional)* Clarity versions to test. For each epoch to test, at least one of the clarity versions must be supported. Defaults to all Clarity versions. /// * `setup_contracts` — *(optional)* Slice of [`SetupContract`] values to deploy once before the main contract logic. /// /// # Example @@ -1597,6 +1615,7 @@ macro_rules! contract_call_consensus_test { function_args: $function_args:expr, $(deploy_epochs: $deploy_epochs:expr,)? $(call_epochs: $call_epochs:expr,)? + $(exclude_clarity_versions: $exclude_clarity_versions:expr,)? $(setup_contracts: $setup_contracts:expr,)? ) => { { @@ -1609,6 +1628,8 @@ macro_rules! contract_call_consensus_test { $(let call_epochs = $call_epochs;)? let setup_contracts: &[$crate::chainstate::tests::consensus::SetupContract] = &[]; $(let setup_contracts = $setup_contracts;)? + let exclude_clarity_versions: &[clarity::vm::ClarityVersion] = &[]; + $(let exclude_clarity_versions = $exclude_clarity_versions;)? let contract_test = $crate::chainstate::tests::consensus::ContractConsensusTest::new( function_name!(), vec![], @@ -1618,6 +1639,7 @@ macro_rules! contract_call_consensus_test { $contract_code, $function_name, $function_args, + exclude_clarity_versions, setup_contracts, ); let result = contract_test.run(); @@ -1645,6 +1667,7 @@ pub(crate) use contract_call_consensus_test; /// * `contract_name` — Name of the contract being tested. /// * `contract_code` — The Clarity source code of the contract. /// * `deploy_epochs` — *(optional)* Epochs in which to deploy the contract. Defaults to [`EPOCHS_TO_TEST`]. +/// * `clarity_versions` — *(optional)* Clarity versions to test. For each epoch to test, at least one of the clarity versions must be supported. Defaults to all Clarity versions. /// * `setup_contracts` — *(optional)* Slice of [`SetupContract`] values to deploy before the main contract. /// /// # Example @@ -1664,6 +1687,7 @@ macro_rules! contract_deploy_consensus_test { contract_name: $contract_name:expr, contract_code: $contract_code:expr, $(deploy_epochs: $deploy_epochs:expr,)? + $(exclude_clarity_versions: $exclude_clarity_versions:expr,)? $(setup_contracts: $setup_contracts:expr,)? ) => { { @@ -1676,6 +1700,7 @@ macro_rules! contract_deploy_consensus_test { function_args: &[], // No function calls, just deploys deploy_epochs: deploy_epochs, call_epochs: &[], // No function calls, just deploys + $(exclude_clarity_versions: $exclude_clarity_versions,)? $(setup_contracts: $setup_contracts,)? ); } diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_serialization_type.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_serialization_type.snap index 83c2fecb9f..c750aef4ac 100644 --- a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_serialization_type.snap +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_serialization_type.snap @@ -6,36 +6,6 @@ expression: result Success(ExpectedBlockOutput( marf_hash: "b3b9782ccbe1bf3a66f1c34fe50c83c418fd9d6265761b0a82ffe9950dc8e30f", evaluated_epoch: Epoch33, - transactions: [ - ExpectedTransactionOutput( - tx: "SmartContract(name: serialization-type-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", - vm_error: "Some(:0:0: use of unresolved function \'to-consensus-buff?\') [NON-CONSENSUS BREAKING]", - return_type: Response(ResponseData( - committed: false, - data: Optional(OptionalData( - data: None, - )), - )), - cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 0, - read_count: 0, - runtime: 7374, - ), - ), - ], - total_block_cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 0, - read_count: 0, - runtime: 7374, - ), - )), - Success(ExpectedBlockOutput( - marf_hash: "32e8a7c15c537c7cbffb74e28705816f8c607bd37d5b2fe9db78f24c697d506f", - evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( tx: "SmartContract(name: serialization-type-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", @@ -64,7 +34,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "a9b3550d29aff9a7a271ee1cb981e4bb3e1948d49026511cc8183fbe2aaeb8af", + marf_hash: "000052458b68bb6d4184aee0daf39736b0799c96514237aa8377e7c10f00fd61", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -94,7 +64,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "a390adec582f30b5d9b8cb0dec54acb082db7823cd7d55a11992fda3f5f96479", + marf_hash: "322b1c89f517b9a55c2487d6f900057dadab0c93034bd5120be87fd7dc7fe86f", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unknown_type_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unknown_type_name.snap index 1b07f47cf1..37bb457dd8 100644 --- a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unknown_type_name.snap +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unknown_type_name.snap @@ -6,36 +6,6 @@ expression: result Success(ExpectedBlockOutput( marf_hash: "8d004a3557c0396f4fc38d9ce6bf700be2d07f6afab03f03ff4e97ab98fe0f01", evaluated_epoch: Epoch33, - transactions: [ - ExpectedTransactionOutput( - tx: "SmartContract(name: unknown-type-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", - vm_error: "Some(:0:0: use of unresolved function \'from-consensus-buff?\') [NON-CONSENSUS BREAKING]", - return_type: Response(ResponseData( - committed: false, - data: Optional(OptionalData( - data: None, - )), - )), - cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 0, - read_count: 0, - runtime: 2394, - ), - ), - ], - total_block_cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 0, - read_count: 0, - runtime: 2394, - ), - )), - Success(ExpectedBlockOutput( - marf_hash: "eb4d4eb367b43b2b4bc7d93341c6bca0a24204c2a0a30706a8a18b5dcaf146e3", - evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( tx: "SmartContract(name: unknown-type-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", @@ -64,7 +34,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "e34776337382364c9cad419d37cd265c7c9c62c36e404641a942ee13f6566562", + marf_hash: "cbe12e1fc1ac7d7c8e51a5017f252d5194eae8f9954bda1db5ff63919ecaea6b", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -94,7 +64,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "33484e3c68f4d42586a392be72eaf557996936ebd7cd002151817474bd409aee", + marf_hash: "461b19fae1c2c4c055386fe3500aca96406c7b4438828249ec0a1d89939348a5", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( diff --git a/stackslib/src/chainstate/tests/static_analysis_tests.rs b/stackslib/src/chainstate/tests/static_analysis_tests.rs index e31ea58ccc..22887dd365 100644 --- a/stackslib/src/chainstate/tests/static_analysis_tests.rs +++ b/stackslib/src/chainstate/tests/static_analysis_tests.rs @@ -18,6 +18,7 @@ #[allow(unused_imports)] use clarity::vm::analysis::CheckErrorKind; use clarity::vm::types::MAX_TYPE_DEPTH; +use clarity::vm::ClarityVersion; use crate::chainstate::tests::consensus::{contract_deploy_consensus_test, SetupContract}; use crate::core::BLOCK_LIMIT_MAINNET_21; @@ -206,7 +207,7 @@ fn static_check_error_expected_optional_type() { ); } -/// StaticCheckErrorKind: [`StaticCheckErrorKind::BadTraitImplementation`] +/// CheckErrorKind: [`CheckErrorKind::BadTraitImplementation`] /// Caused by: trying to implement a trait with a bad implementation. /// Outcome: block accepted. #[test] @@ -357,6 +358,7 @@ fn static_check_error_unknown_type_name() { contract_code: " (define-public (trigger) (ok (from-consensus-buff? foo 0x00)))", + exclude_clarity_versions: &[ClarityVersion::Clarity1], ); } @@ -430,6 +432,7 @@ fn static_check_error_could_not_determine_serialization_type() { (define-trait trait-b ((pong () (response bool bool)))) (define-public (trigger (first ) (second )) (ok (to-consensus-buff? (list first second))))", + exclude_clarity_versions: &[ClarityVersion::Clarity1], ); }