From 159e798e7d6111f29bbe104b65d5bbc925f0721f Mon Sep 17 00:00:00 2001 From: Francesco Leacche Date: Wed, 19 Nov 2025 10:52:49 +0000 Subject: [PATCH 1/5] add setup_contracts to contract consensus_test macros --- stackslib/src/chainstate/tests/consensus.rs | 161 +++++++++++++++++--- 1 file changed, 137 insertions(+), 24 deletions(-) diff --git a/stackslib/src/chainstate/tests/consensus.rs b/stackslib/src/chainstate/tests/consensus.rs index 19d01da92a..774c9f21ed 100644 --- a/stackslib/src/chainstate/tests/consensus.rs +++ b/stackslib/src/chainstate/tests/consensus.rs @@ -984,6 +984,8 @@ pub struct ContractConsensusTest<'a> { chain: ConsensusChain<'a>, /// Address of the contract deployer (the test faucet). contract_addr: StacksAddress, + /// Mapping of epoch → list of prerequisite contracts to deploy. + setup_contracts_per_epoch: HashMap>, /// Mapping of epoch → list of `(contract_name, ClarityVersion)` deployed in that epoch. /// Multiple versions may exist per epoch (e.g., Clarity 1, 2, 3 in Epoch 3.0). contract_deploys_per_epoch: HashMap>, @@ -1019,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 + /// * `setup_contracts` - Contracts that must be deployed before epoch-specific logic runs /// /// # Panics /// @@ -1034,6 +1037,7 @@ impl ContractConsensusTest<'_> { contract_code: &str, function_name: &str, function_args: &[ClarityValue], + setup_contracts: &[SetupContract], ) -> Self { assert!( !deploy_epochs.is_empty(), @@ -1051,15 +1055,48 @@ impl ContractConsensusTest<'_> { HashMap::new(); let mut contract_calls_per_epoch: HashMap> = HashMap::new(); let mut contract_names = vec![]; + let mut setup_contracts_per_epoch: HashMap> = + HashMap::new(); + + let mut epoch_candidates: BTreeSet = deploy_epochs.iter().copied().collect(); + epoch_candidates.extend(call_epochs.iter().copied()); + let default_setup_epoch = *epoch_candidates + .iter() + .next() + .expect("deploy_epochs guarantees at least one epoch"); + + for contract in setup_contracts { + // Deploy the setup contracts in the first epoch if not specified. + let deploy_epoch = contract.deploy_epoch.unwrap_or(default_setup_epoch); + // Get the default Clarity version for the epoch of the contract if not specified. + let clarity_version = contract.clarity_version.or_else(|| { + if deploy_epoch < StacksEpochId::Epoch21 { + None + } else { + Some(ClarityVersion::default_for_epoch(deploy_epoch)) + } + }); + let mut contract = contract.clone(); + contract.deploy_epoch = Some(deploy_epoch); + contract.clarity_version = clarity_version; + setup_contracts_per_epoch + .entry(deploy_epoch) + .or_default() + .push(contract); + } // Combine and sort unique epochs - let all_epochs: BTreeSet = - deploy_epochs.iter().chain(call_epochs).cloned().collect(); + let mut all_epochs: BTreeSet = epoch_candidates; + all_epochs.extend(setup_contracts_per_epoch.keys().copied()); // Precompute contract names and block counts for epoch in &all_epochs { let mut num_blocks = 0; + if let Some(contracts) = setup_contracts_per_epoch.get(epoch) { + num_blocks += contracts.len() as u64; + } + if deploy_epochs.contains(epoch) { let clarity_versions = clarity_versions_for_epoch(*epoch); let epoch_name = format!("Epoch{}", epoch.to_string().replace('.', "_")); @@ -1102,6 +1139,7 @@ impl ContractConsensusTest<'_> { contract_code: contract_code.to_string(), function_name: function_name.to_string(), function_args: function_args.to_vec(), + setup_contracts_per_epoch, all_epochs, } } @@ -1134,6 +1172,30 @@ impl ContractConsensusTest<'_> { result } + /// Deploys prerequisite contracts scheduled for the given epoch. + fn deploy_setup_contracts(&mut self, epoch: StacksEpochId) -> Vec { + let Some(contracts) = self.setup_contracts_per_epoch.get(&epoch).cloned() else { + return vec![]; + }; + + let is_naka_block = epoch.uses_nakamoto_blocks(); + contracts + .into_iter() + .map(|contract| { + self.chain.consume_pre_naka_prepare_phase(); + self.append_tx_block( + &TestTxSpec::ContractDeploy { + sender: &FAUCET_PRIV_KEY, + name: &contract.name, + code: &contract.code, + clarity_version: contract.clarity_version, + }, + is_naka_block, + ) + }) + .collect() + } + /// Deploys all contract versions scheduled for the given epoch. /// /// For each Clarity version supported in the epoch: @@ -1251,6 +1313,7 @@ impl ContractConsensusTest<'_> { .test_chainstate .advance_into_epoch(&private_key, epoch); + results.extend(self.deploy_setup_contracts(epoch)); results.extend(self.deploy_contracts(epoch)); results.extend(self.call_contracts(epoch)); } @@ -1464,8 +1527,9 @@ impl TestTxFactory { /// * `contract_code` — The Clarity source code for the contract. /// * `function_name` — The public function to call. /// * `function_args` — Function arguments, provided as a slice of [`ClarityValue`]. -/// * `deploy_epochs` — *(optional)* Epochs in which to deploy the contract. Defaults to all epochs ≥ 3.0. +/// * `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`]. +/// * `setup_contracts` — *(optional)* Slice of [`SetupContract`] values to deploy once before the main contract logic. /// /// # Example /// @@ -1474,9 +1538,15 @@ impl TestTxFactory { /// fn test_my_contract_call_consensus() { /// contract_call_consensus_test!( /// contract_name: "my-contract", -/// contract_code: "(define-public (get-message) (ok \"hello\"))", +/// contract_code: " +/// (define-public (get-message) +/// (contract-call? .dependency.foo))", /// function_name: "get-message", /// function_args: &[], +/// setup_contracts: &[SetupContract::new( +/// "dependency", +/// "(define-public (foo) (ok \"hello\"))", +/// )], /// ); /// } /// ``` @@ -1488,6 +1558,7 @@ macro_rules! contract_call_consensus_test { function_args: $function_args:expr, $(deploy_epochs: $deploy_epochs:expr,)? $(call_epochs: $call_epochs:expr,)? + $(setup_contracts: $setup_contracts:expr,)? ) => { { // Handle deploy_epochs parameter (default to all epochs >= 2.0 if not provided) @@ -1497,6 +1568,8 @@ macro_rules! contract_call_consensus_test { // Handle call_epochs parameter (default to EPOCHS_TO_TEST if not provided) let call_epochs = $crate::chainstate::tests::consensus::EPOCHS_TO_TEST; $(let call_epochs = $call_epochs;)? + let setup_contracts: &[$crate::chainstate::tests::consensus::SetupContract] = &[]; + $(let setup_contracts = $setup_contracts;)? let contract_test = $crate::chainstate::tests::consensus::ContractConsensusTest::new( function_name!(), vec![], @@ -1506,6 +1579,7 @@ macro_rules! contract_call_consensus_test { $contract_code, $function_name, $function_args, + setup_contracts, ); let result = contract_test.run(); insta::assert_ron_snapshot!(result); @@ -1532,6 +1606,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`]. +/// * `setup_contracts` — *(optional)* Slice of [`SetupContract`] values to deploy before the main contract. /// /// # Example /// @@ -1546,34 +1621,72 @@ pub(crate) use contract_call_consensus_test; /// } /// ``` macro_rules! contract_deploy_consensus_test { - // Handle the case where deploy_epochs is not provided ( contract_name: $contract_name:expr, contract_code: $contract_code:expr, + $(deploy_epochs: $deploy_epochs:expr,)? + $(setup_contracts: $setup_contracts:expr,)? ) => { - contract_deploy_consensus_test!( - contract_name: $contract_name, - contract_code: $contract_code, - deploy_epochs: $crate::chainstate::tests::consensus::EPOCHS_TO_TEST, - ); - }; - ( - contract_name: $contract_name:expr, - contract_code: $contract_code:expr, - deploy_epochs: $deploy_epochs:expr, - ) => { - $crate::chainstate::tests::consensus::contract_call_consensus_test!( - contract_name: $contract_name, - contract_code: $contract_code, - function_name: "", // No function calls, just deploys - function_args: &[], // No function calls, just deploys - deploy_epochs: $deploy_epochs, - call_epochs: &[], // No function calls, just deploys - ); + { + let deploy_epochs = $crate::chainstate::tests::consensus::EPOCHS_TO_TEST; + $(let deploy_epochs = $deploy_epochs;)? + $crate::chainstate::tests::consensus::contract_call_consensus_test!( + contract_name: $contract_name, + contract_code: $contract_code, + function_name: "", // No function calls, just deploys + function_args: &[], // No function calls, just deploys + deploy_epochs: deploy_epochs, + call_epochs: &[], // No function calls, just deploys + $(setup_contracts: $setup_contracts,)? + ); + } }; } pub(crate) use contract_deploy_consensus_test; +/// Contract deployment that must occur before `contract_call_consensus_test!` or `contract_deploy_consensus_test!` runs its own logic. +/// +/// These setups are useful when the primary contract references other contracts (traits, functions, etc.) +/// that need to exist ahead of time with deterministic names and versions. +#[derive(Clone, Debug)] +pub struct SetupContract { + /// Contract name that should be deployed (no macro suffixes applied). + pub name: String, + /// Source code for the supporting contract. + pub code: String, + /// Optional Clarity version for this contract. + pub clarity_version: Option, + /// Optional epoch for this contract. + pub deploy_epoch: Option, +} + +impl SetupContract { + /// Creates a new SetupContract with default deployment settings. + /// + /// By default, the contract will deploy in the first epoch used by the test and with the + /// default Clarity version for that epoch. + pub fn new(name: impl Into, code: impl Into) -> Self { + Self { + name: name.into(), + code: code.into(), + clarity_version: None, + deploy_epoch: None, + } + } + + /// Override the epoch where this setup contract should deploy. + pub fn with_epoch(mut self, epoch: StacksEpochId) -> Self { + self.deploy_epoch = Some(epoch); + self + } + + /// Override the Clarity version used to deploy this setup contract. + pub fn with_clarity_version(mut self, version: ClarityVersion) -> Self { + self.clarity_version = Some(version); + self + } +} + // Just a namespace for utilities for writing consensus tests pub struct ConsensusUtils; From 883ad6113c1a1c517507a515612598281e62b5b8 Mon Sep 17 00:00:00 2001 From: Francesco Leacche Date: Wed, 19 Nov 2025 11:59:28 +0000 Subject: [PATCH 2/5] add static_check_error_bad_trait_implementation --- ..._check_error_bad_trait_implementation.snap | 154 ++++++++++++++++++ .../chainstate/tests/static_analysis_tests.rs | 22 ++- 2 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap new file mode 100644 index 0000000000..fecbb5daa2 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap @@ -0,0 +1,154 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ea4bd6655c60fab8f7361d5dadafe85828880fe8eedfcd1ee1009089d080c69a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-contract, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 87, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 10190, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 87, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 10190, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3e216b0c84ceed92b873d280c01a1541de4bc3fc8dea66968cd7af59387080e5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(invalid signature for method \'get-1\' regarding trait\'s specification ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3373, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3373, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "53c830893cccd63de3eba2d50e763cf0e31166f51a97761352201aca2607caee", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(invalid signature for method \'get-1\' regarding trait\'s specification ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3373, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3373, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fa6cc1f8cd406b2dc50bb654268085d7c62d89e775f756bec97cbcc3e70df447", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(invalid signature for method \'get-1\' regarding trait\'s specification ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3373, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3373, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b559f59ceb3fcd78971206e63bac42f5c3c7bd29ab001c21e1431d4fea0377fe", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(invalid signature for method \'get-1\' regarding trait\'s specification ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3373, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3373, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/static_analysis_tests.rs b/stackslib/src/chainstate/tests/static_analysis_tests.rs index c08b09d37e..b4daaf6f41 100644 --- a/stackslib/src/chainstate/tests/static_analysis_tests.rs +++ b/stackslib/src/chainstate/tests/static_analysis_tests.rs @@ -18,7 +18,7 @@ #[allow(unused_imports)] use clarity::vm::analysis::CheckErrorKind; -use crate::chainstate::tests::consensus::contract_deploy_consensus_test; +use crate::chainstate::tests::consensus::{contract_deploy_consensus_test, SetupContract}; use crate::core::BLOCK_LIMIT_MAINNET_21; use crate::util_lib::boot::boot_code_test_addr; @@ -204,3 +204,23 @@ fn static_check_error_expected_optional_type() { contract_code: "(default-to 3 5)", ); } + +/// StaticCheckErrorKind: [`StaticCheckErrorKind::BadTraitImplementation`] +/// Caused by: trying to implement a trait with a bad implementation. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_trait_implementation() { + let setup_contract = SetupContract::new( + "trait-contract", + "(define-trait trait-1 ((get-1 ((list 10 uint)) (response uint uint))))", + ); + + contract_deploy_consensus_test!( + contract_name: "contract-name", + contract_code: &format!(" + (impl-trait .trait-contract.trait-1) + (define-public (get-1 (x (list 5 uint))) (ok u1))", + ), + setup_contracts: &[setup_contract], + ); +} From d35184eb04e42022e2ed526a2286219af045792b Mon Sep 17 00:00:00 2001 From: Francesco Leacche Date: Thu, 20 Nov 2025 14:43:52 +0000 Subject: [PATCH 3/5] remove setup contracts from snapshot --- stackslib/src/chainstate/tests/consensus.rs | 48 +++++++++++-------- ..._check_error_bad_trait_implementation.snap | 28 ----------- 2 files changed, 29 insertions(+), 47 deletions(-) diff --git a/stackslib/src/chainstate/tests/consensus.rs b/stackslib/src/chainstate/tests/consensus.rs index 774c9f21ed..6895935711 100644 --- a/stackslib/src/chainstate/tests/consensus.rs +++ b/stackslib/src/chainstate/tests/consensus.rs @@ -1048,7 +1048,12 @@ impl ContractConsensusTest<'_> { call_epochs.iter().all(|e| e >= min_deploy_epoch), "All call epochs must be >= the minimum deploy epoch" ); - + assert!( + setup_contracts + .iter() + .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> = @@ -1173,27 +1178,30 @@ impl ContractConsensusTest<'_> { } /// Deploys prerequisite contracts scheduled for the given epoch. - fn deploy_setup_contracts(&mut self, epoch: StacksEpochId) -> Vec { + /// Panics if the deployment fails. + fn deploy_setup_contracts(&mut self, epoch: StacksEpochId) { let Some(contracts) = self.setup_contracts_per_epoch.get(&epoch).cloned() else { - return vec![]; + return; }; let is_naka_block = epoch.uses_nakamoto_blocks(); - contracts - .into_iter() - .map(|contract| { - self.chain.consume_pre_naka_prepare_phase(); - self.append_tx_block( - &TestTxSpec::ContractDeploy { - sender: &FAUCET_PRIV_KEY, - name: &contract.name, - code: &contract.code, - clarity_version: contract.clarity_version, - }, - is_naka_block, - ) - }) - .collect() + contracts.into_iter().for_each(|contract| { + self.chain.consume_pre_naka_prepare_phase(); + let result = self.append_tx_block( + &TestTxSpec::ContractDeploy { + sender: &FAUCET_PRIV_KEY, + name: &contract.name, + code: &contract.code, + clarity_version: contract.clarity_version, + }, + is_naka_block, + ); + assert!( + matches!(result, ExpectedResult::Success(_)), + "Expected success for setup contract {}: {result:?}", + contract.name, + ); + }); } /// Deploys all contract versions scheduled for the given epoch. @@ -1313,7 +1321,9 @@ impl ContractConsensusTest<'_> { .test_chainstate .advance_into_epoch(&private_key, epoch); - results.extend(self.deploy_setup_contracts(epoch)); + // Differently from the deploy_contracts and call_contracts functions, setup contracts are expected to succeed. + // Their receipt is not relevant to the test. + self.deploy_setup_contracts(epoch); results.extend(self.deploy_contracts(epoch)); results.extend(self.call_contracts(epoch)); } diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap index fecbb5daa2..db88fa8c4d 100644 --- a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap @@ -3,34 +3,6 @@ source: stackslib/src/chainstate/tests/static_analysis_tests.rs expression: result --- [ - Success(ExpectedBlockOutput( - marf_hash: "ea4bd6655c60fab8f7361d5dadafe85828880fe8eedfcd1ee1009089d080c69a", - evaluated_epoch: Epoch33, - transactions: [ - ExpectedTransactionOutput( - tx: "SmartContract(name: trait-contract, code_body: [..], clarity_version: Some(Clarity4))", - vm_error: "None [NON-CONSENSUS BREAKING]", - return_type: Response(ResponseData( - committed: true, - data: Bool(true), - )), - cost: ExecutionCost( - write_length: 87, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 10190, - ), - ), - ], - total_block_cost: ExecutionCost( - write_length: 87, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 10190, - ), - )), Success(ExpectedBlockOutput( marf_hash: "3e216b0c84ceed92b873d280c01a1541de4bc3fc8dea66968cd7af59387080e5", evaluated_epoch: Epoch33, From f4a7ff145d482d35a3ee498798a05eaef2fef9cd Mon Sep 17 00:00:00 2001 From: Francesco Leacche Date: Fri, 21 Nov 2025 14:34:46 +0000 Subject: [PATCH 4/5] fail on valid, but failed setup contract deploy --- stackslib/src/chainstate/tests/consensus.rs | 41 ++++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/stackslib/src/chainstate/tests/consensus.rs b/stackslib/src/chainstate/tests/consensus.rs index 6895935711..8da0339e4b 100644 --- a/stackslib/src/chainstate/tests/consensus.rs +++ b/stackslib/src/chainstate/tests/consensus.rs @@ -23,7 +23,7 @@ use clarity::types::{EpochList, StacksEpoch, StacksEpochId}; use clarity::util::hash::{Hash160, MerkleTree, Sha512Trunc256Sum}; use clarity::util::secp256k1::MessageSignature; use clarity::vm::costs::ExecutionCost; -use clarity::vm::types::PrincipalData; +use clarity::vm::types::{PrincipalData, ResponseData}; use clarity::vm::{ClarityVersion, Value as ClarityValue}; use serde::{Deserialize, Serialize, Serializer}; use stacks_common::bitvec::BitVec; @@ -1196,11 +1196,40 @@ impl ContractConsensusTest<'_> { }, is_naka_block, ); - assert!( - matches!(result, ExpectedResult::Success(_)), - "Expected success for setup contract {}: {result:?}", - contract.name, - ); + match result { + ExpectedResult::Success(ref output) => { + assert_eq!( + output.transactions.len(), + 1, + "Expected 1 transaction for setup contract {}, got {}", + contract.name, + output.transactions.len() + ); + let tx_output = &output.transactions.first().unwrap(); + assert_eq!( + tx_output.return_type, + ClarityValue::Response(ResponseData { + committed: true, + data: Box::new(ClarityValue::Bool(true)), + }), + "Setup contract {} failed to deploy: got {:?}", + contract.name, + tx_output + ); + assert!( + tx_output.vm_error.is_none(), + "Expected no VM error for setup contract {}, got {:?}", + contract.name, + tx_output.vm_error + ); + } + ExpectedResult::Failure(error) => { + panic!( + "Setup contract {} deployment failed: {error:?}", + contract.name + ); + } + } }); } From c8553e73c6bd11f774abb99ba3a01decca9a1fa9 Mon Sep 17 00:00:00 2001 From: Francesco Leacche Date: Fri, 21 Nov 2025 14:47:42 +0000 Subject: [PATCH 5/5] remove useless format! --- ..._check_error_bad_trait_implementation.snap | 24 +++++++++---------- .../chainstate/tests/static_analysis_tests.rs | 7 +++--- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap index db88fa8c4d..5cc9021b88 100644 --- a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_trait_implementation.snap @@ -4,7 +4,7 @@ expression: result --- [ Success(ExpectedBlockOutput( - marf_hash: "3e216b0c84ceed92b873d280c01a1541de4bc3fc8dea66968cd7af59387080e5", + marf_hash: "12d33d45dd2d1e1b69dc051295249fbea64a8c3fd09448e3997f6d9441724448", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -21,7 +21,7 @@ expression: result write_count: 1, read_length: 1, read_count: 1, - runtime: 3373, + runtime: 3157, ), ), ], @@ -30,11 +30,11 @@ expression: result write_count: 1, read_length: 1, read_count: 1, - runtime: 3373, + runtime: 3157, ), )), Success(ExpectedBlockOutput( - marf_hash: "53c830893cccd63de3eba2d50e763cf0e31166f51a97761352201aca2607caee", + marf_hash: "8ccaf85453bc27e815e4b127745b61c0e3ab40bf22e73fc7b8c74f5ac8c458f3", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -51,7 +51,7 @@ expression: result write_count: 1, read_length: 1, read_count: 1, - runtime: 3373, + runtime: 3157, ), ), ], @@ -60,11 +60,11 @@ expression: result write_count: 1, read_length: 1, read_count: 1, - runtime: 3373, + runtime: 3157, ), )), Success(ExpectedBlockOutput( - marf_hash: "fa6cc1f8cd406b2dc50bb654268085d7c62d89e775f756bec97cbcc3e70df447", + marf_hash: "111496a7fc28efe5966db421eb0ecd0b736d5435ff490585ba801f1f5093b339", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -81,7 +81,7 @@ expression: result write_count: 1, read_length: 1, read_count: 1, - runtime: 3373, + runtime: 3157, ), ), ], @@ -90,11 +90,11 @@ expression: result write_count: 1, read_length: 1, read_count: 1, - runtime: 3373, + runtime: 3157, ), )), Success(ExpectedBlockOutput( - marf_hash: "b559f59ceb3fcd78971206e63bac42f5c3c7bd29ab001c21e1431d4fea0377fe", + marf_hash: "f4274bba15e471d656212d8e0b57f2386074437a263e743a0423715ea32d3f40", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -111,7 +111,7 @@ expression: result write_count: 1, read_length: 1, read_count: 1, - runtime: 3373, + runtime: 3157, ), ), ], @@ -120,7 +120,7 @@ expression: result write_count: 1, read_length: 1, read_count: 1, - runtime: 3373, + runtime: 3157, ), )), ] diff --git a/stackslib/src/chainstate/tests/static_analysis_tests.rs b/stackslib/src/chainstate/tests/static_analysis_tests.rs index 85676c4b6e..fe70bc1768 100644 --- a/stackslib/src/chainstate/tests/static_analysis_tests.rs +++ b/stackslib/src/chainstate/tests/static_analysis_tests.rs @@ -218,10 +218,9 @@ fn static_check_error_bad_trait_implementation() { contract_deploy_consensus_test!( contract_name: "contract-name", - contract_code: &format!(" - (impl-trait .trait-contract.trait-1) - (define-public (get-1 (x (list 5 uint))) (ok u1))", - ), + contract_code: " + (impl-trait .trait-contract.trait-1) + (define-public (get-1 (x (list 5 uint))) (ok u1))", setup_contracts: &[setup_contract], ); }