diff --git a/.cargo/config.toml b/.cargo/config.toml index d277b56a032..440c785d471 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,7 +1,7 @@ [alias] stacks-node = "run --package stacks-node --" fmt-stacks = "fmt -- --config group_imports=StdExternalCrate,imports_granularity=Module" -clippy-stacks = "clippy -p stx-genesis -p libstackerdb -p stacks-signer -p pox-locking -p clarity-types -p clarity -p libsigner -p stacks-common --no-deps --tests --all-features -- -D warnings" +clippy-stacks = "clippy -p stx-genesis -p libstackerdb -p stacks-signer -p pox-locking -p clarity-types -p clarity -p libsigner -p stacks-common -p clarity-cli -p stacks-cli -p stacks-inspect --no-deps --tests --all-features -- -D warnings" clippy-stackslib = "clippy -p stackslib --no-deps -- -Aclippy::all -Wclippy::indexing_slicing -Wclippy::nonminimal_bool -Wclippy::clone_on_copy" # Uncomment to improve performance slightly, at the cost of portability diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index ee3b156d30f..00000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,10 +0,0 @@ -# These owners will be the default owners for everything in -# the repo. Unless a later match takes precedence, -# -# require both blockchain-team-codeowners and blockchain-team-reviewers to review all PR's not specifically matched below -* @stacks-network/blockchain-team-codeowners @stacks-network/blockchain-team-reviewers - -# CI workflows -# require both blockchain-team-ci and blockchain-team-reviewers teams to review PR's modifying CI workflows -/.github/workflows/ @stacks-network/blockchain-team-ci @stacks-network/blockchain-team-reviewers -/.github/actions/ @stacks-network/blockchain-team-ci @stacks-network/blockchain-team-reviewers diff --git a/.github/workflows/bitcoin-tests.yml b/.github/workflows/bitcoin-tests.yml index d85ef0291b9..9571af8ed3c 100644 --- a/.github/workflows/bitcoin-tests.yml +++ b/.github/workflows/bitcoin-tests.yml @@ -1,4 +1,4 @@ -## Github workflow to run bitcoin tests +## Github workflow to run bitcoin tests in multiple github matrices name: Tests::Bitcoin @@ -13,16 +13,17 @@ env: TEST_TIMEOUT: 30 concurrency: - group: bitcoin-tests-${{ github.head_ref || github.ref || github.run_id}} + group: bitcoin-tests-${{ github.head_ref || github.ref || github.run_id }} ## Only cancel in progress if this is for a PR cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: generate-tests: - name: Generate JSON of tests to run + name: Generate balanced test matrix runs-on: ubuntu-latest outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} + matrix1: ${{ steps.set-matrix.outputs.matrix1 }} + matrix2: ${{ steps.set-matrix.outputs.matrix2 }} steps: ## Setup test environment - name: Setup Test Environment @@ -30,83 +31,142 @@ jobs: uses: stacks-network/actions/stacks-core/testenv@main with: btc-version: "25.0" - - name: Generate tests JSON - id: generate_tests_json - # List all of the tests using the nextest archive (so we don't need to do another build task) - # Filter them such that we only select tests from `--bin stacks-node` which are marked `ignored` - # Transform the output JSON into something that can be used as the matrix input + + - name: Build Test Archive run: | - cargo nextest list --archive-file ~/test_archive.tar.zst -Tjson | \ - jq -c '.["rust-suites"]["stacks-node::bin/stacks-node"]["testcases"] | map_values(select(.["ignored"] == true)) | keys' > ./tests.json - - id: set-matrix + set -euo pipefail + cargo nextest archive --archive-file ~/test_archive.tar.zst --bin stacks-node + + - name: List ignored tests + id: list run: | - json_obj=`cat ./tests.json` - echo "matrix=$json_obj" >> $GITHUB_OUTPUT + set -euo pipefail + cargo nextest list --archive-file ~/test_archive.tar.zst -Tjson > nextest_output.json - # Bitcoin integration tests with code coverage - integration-tests: - needs: generate-tests - name: Integration Tests - runs-on: ubuntu-latest - strategy: - ## Continue with the test matrix even if we've had a failure - fail-fast: false - ## Run a maximum of 32 concurrent tests from the test matrix - max-parallel: 32 - matrix: - test-name: ${{fromJson(needs.generate-tests.outputs.matrix)}} - exclude: + jq -c ' + .["rust-suites"]["stacks-node::bin/stacks-node"]["testcases"] + | [to_entries[] | select(.value.ignored) | .key] + ' nextest_output.json > ignored_tests.json + + echo "Ignored tests count: $(jq 'length' ignored_tests.json)" + + # The following tests are excluded from CI runs. Some of these may be + # worth investigating adding back into the CI + - name: Excluded tests + id: exclude + run: | + cat << 'EOF' > raw_exclude.txt # The following tests are excluded from CI runs. Some of these may be # worth investigating adding back into the CI - - test-name: tests::nakamoto_integrations::consensus_hash_event_dispatcher - - test-name: tests::neon_integrations::atlas_integration_test - - test-name: tests::neon_integrations::atlas_stress_integration_test - - test-name: tests::neon_integrations::bitcoind_resubmission_test - - test-name: tests::neon_integrations::block_replay_integration_test - - test-name: tests::neon_integrations::deep_contract - - test-name: tests::neon_integrations::filter_txs_by_origin - - test-name: tests::neon_integrations::filter_txs_by_type - - test-name: tests::neon_integrations::lockup_integration - - test-name: tests::neon_integrations::most_recent_utxo_integration_test - - test-name: tests::neon_integrations::run_with_custom_wallet - - test-name: tests::neon_integrations::test_competing_miners_build_anchor_blocks_on_same_chain_without_rbf - - test-name: tests::neon_integrations::test_one_miner_build_anchor_blocks_on_same_chain_without_rbf - - test-name: tests::signer::v0::tenure_extend_after_2_bad_commits - - test-name: tests::stackerdb::test_stackerdb_event_observer - - test-name: tests::stackerdb::test_stackerdb_load_store + tests::nakamoto_integrations::consensus_hash_event_dispatcher + tests::neon_integrations::atlas_integration_test + tests::neon_integrations::atlas_stress_integration_test + tests::neon_integrations::bitcoind_resubmission_test + tests::neon_integrations::block_replay_integration_test + tests::neon_integrations::deep_contract + tests::neon_integrations::filter_txs_by_origin + tests::neon_integrations::filter_txs_by_type + tests::neon_integrations::lockup_integration + tests::neon_integrations::most_recent_utxo_integration_test + tests::neon_integrations::run_with_custom_wallet + tests::neon_integrations::test_competing_miners_build_anchor_blocks_on_same_chain_without_rbf + tests::neon_integrations::test_one_miner_build_anchor_blocks_on_same_chain_without_rbf + tests::signer::v0::tenure_extend_after_2_bad_commits + tests::stackerdb::test_stackerdb_event_observer + tests::stackerdb::test_stackerdb_load_store # Epoch tests are covered by the epoch-tests CI workflow, and don't need to run # on every PR (for older epochs) - - test-name: tests::epoch_205::test_cost_limit_switch_version205 - - test-name: tests::epoch_205::test_dynamic_db_method_costs - - test-name: tests::epoch_205::test_exact_block_costs - - test-name: tests::epoch_205::transition_empty_blocks - - test-name: tests::epoch_21::test_sortition_divergence_pre_21 - - test-name: tests::epoch_21::test_v1_unlock_height_with_current_stackers - - test-name: tests::epoch_21::test_v1_unlock_height_with_delay_and_current_stackers - - test-name: tests::epoch_21::trait_invocation_cross_epoch - - test-name: tests::epoch_21::transition_adds_burn_block_height - - test-name: tests::epoch_21::transition_adds_get_pox_addr_recipients - - test-name: tests::epoch_21::transition_adds_mining_from_segwit - - test-name: tests::epoch_21::transition_adds_pay_to_alt_recipient_contract - - test-name: tests::epoch_21::transition_adds_pay_to_alt_recipient_principal - - test-name: tests::epoch_21::transition_empty_blocks - - test-name: tests::epoch_21::transition_fixes_bitcoin_rigidity - - test-name: tests::epoch_21::transition_removes_pox_sunset - - test-name: tests::epoch_22::disable_pox - - test-name: tests::epoch_22::pox_2_unlock_all - - test-name: tests::epoch_23::trait_invocation_behavior - - test-name: tests::epoch_24::fix_to_pox_contract - - test-name: tests::epoch_24::verify_auto_unlock_behavior + tests::epoch_205::test_cost_limit_switch_version205 + tests::epoch_205::test_dynamic_db_method_costs + tests::epoch_205::test_exact_block_costs + tests::epoch_205::transition_empty_blocks + tests::epoch_21::test_sortition_divergence_pre_21 + tests::epoch_21::test_v1_unlock_height_with_current_stackers + tests::epoch_21::test_v1_unlock_height_with_delay_and_current_stackers + tests::epoch_21::trait_invocation_cross_epoch + tests::epoch_21::transition_adds_burn_block_height + tests::epoch_21::transition_adds_get_pox_addr_recipients + tests::epoch_21::transition_adds_mining_from_segwit + tests::epoch_21::transition_adds_pay_to_alt_recipient_contract + tests::epoch_21::transition_adds_pay_to_alt_recipient_principal + tests::epoch_21::transition_empty_blocks + tests::epoch_21::transition_fixes_bitcoin_rigidity + tests::epoch_21::transition_removes_pox_sunset + tests::epoch_22::disable_pox + tests::epoch_22::pox_2_unlock_all + tests::epoch_23::trait_invocation_behavior + tests::epoch_24::fix_to_pox_contract + tests::epoch_24::verify_auto_unlock_behavior # Disable this flaky test. We don't need continue testing Epoch 2 -> 3 transition - - test-name: tests::nakamoto_integrations::flash_blocks_on_epoch_3_FLAKY + tests::nakamoto_integrations::flash_blocks_on_epoch_3_FLAKY # These mempool tests take a long time to run, and are meant to be run manually - - test-name: tests::nakamoto_integrations::large_mempool_original_constant_fee - - test-name: tests::nakamoto_integrations::large_mempool_original_random_fee - - test-name: tests::nakamoto_integrations::large_mempool_next_constant_fee - - test-name: tests::nakamoto_integrations::large_mempool_next_random_fee - - test-name: tests::nakamoto_integrations::larger_mempool - - test-name: tests::signer::v0::larger_mempool + tests::nakamoto_integrations::large_mempool_original_constant_fee + tests::nakamoto_integrations::large_mempool_original_random_fee + tests::nakamoto_integrations::large_mempool_next_constant_fee + tests::nakamoto_integrations::large_mempool_next_random_fee + tests::nakamoto_integrations::larger_mempool + tests::signer::v0::larger_mempool + EOF + + # Clean: remove empty lines and comments + grep -v '^\s*$' raw_exclude.txt | grep -v '^\s*#' > clean_exclude.txt + + # Convert to proper JSON array + jq -R . clean_exclude.txt | jq -s . > exclude.json + + echo "Excluded tests count: $(jq length exclude.json)" + + - name: Filter out excluded tests + run: | + set -euo pipefail + # Validate inputs + jq -e 'type == "array"' ignored_tests.json > /dev/null + jq -e 'type == "array"' exclude.json > /dev/null + + # Keep only ignored tests NOT in exclude list + # First sort the inputs to use comm -23 + jq -r '.[]' ignored_tests.json | sort > ignored_sorted.txt + jq -r '.[]' exclude.json | sort > exclude_sorted.txt + + comm -23 ignored_sorted.txt exclude_sorted.txt > filtered.txt + + echo "Final test count: $(wc -l < filtered.txt)" + + - name: Split into two balanced matrices + id: set-matrix + run: | + set -euo pipefail + mapfile -t tests < filtered.txt + total=${#tests[@]} + echo "Total filtered tests: $total" + + if (( total > 512 )); then + echo "ERROR: $total tests exceed 512 limit (2 × 256)" + echo "Split into 3+ jobs required." + exit 1 + fi + + base=$(( total / 2 )) + remainder=$(( total % 2 )) + size1=$(( base + remainder )) + + # Compact JSON output for fromJSON() + matrix1=$(printf '%s\n' "${tests[@]:0:$size1}" | jq -R . | jq -s -c .) + matrix2=$(printf '%s\n' "${tests[@]:$size1}" | jq -R . | jq -s -c .) + + echo "matrix1=$matrix1" >> "$GITHUB_OUTPUT" + echo "matrix2=$matrix2" >> "$GITHUB_OUTPUT" + + integration-tests-1: + needs: generate-tests + runs-on: ubuntu-latest + if: ${{ needs.generate-tests.outputs.matrix1 != '[]' }} + strategy: + fail-fast: false + max-parallel: 32 + matrix: + test-name: ${{ fromJSON(needs.generate-tests.outputs.matrix1) }} steps: ## Setup test environment - name: Setup Test Environment @@ -130,9 +190,40 @@ jobs: test-name: ${{ matrix.test-name }} threads: 1 - ## Create and upload code coverage file - name: Code Coverage - id: codecov + uses: stacks-network/actions/codecov@main + with: + test-name: ${{ matrix.test-name }} + + integration-tests-2: + needs: generate-tests + runs-on: ubuntu-latest + if: ${{ needs.generate-tests.outputs.matrix2 != '[]' }} + strategy: + fail-fast: false + max-parallel: 32 + matrix: + test-name: ${{ fromJSON(needs.generate-tests.outputs.matrix2) }} + steps: + - name: Setup Test Environment + uses: stacks-network/actions/stacks-core/testenv@main + with: + btc-version: "25.0" + + ## Increase open file descriptors limit + - name: Increase Open File Descriptors + run: | + sudo prlimit --nofile=4096:4096 + + - name: Run Test + id: run_tests + timeout-minutes: ${{ fromJSON(env.TEST_TIMEOUT) }} + uses: stacks-network/actions/stacks-core/run-tests@main + with: + test-name: ${{ matrix.test-name }} + threads: 1 + + - name: Code Coverage uses: stacks-network/actions/codecov@main with: test-name: ${{ matrix.test-name }} @@ -142,7 +233,8 @@ jobs: runs-on: ubuntu-latest if: always() needs: - - integration-tests + - integration-tests-1 + - integration-tests-2 steps: - name: Check Tests Status id: check_tests_status diff --git a/CHANGELOG.md b/CHANGELOG.md index 3860037ca58..3c611c0724b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to the versioning scheme outlined in the [README.md](README.md). +## [3.3.0.0.2] + +### Added + +- Fixed an issue where `event.committed` was always equal to `true` in the block replay RPC endpoint +- Added `result_hex` and `post_condition_aborted` to the block replay RPC endpoint +- Added `--epoch ` flag to `clarity-cli` commands to specify the epoch context for evaluation. +- Added miner support for generating read-count tenure extends + - Added `read_count_extend_cost_threshold` config option (in the miner config) which specifies the percentage of the block budget that must be used before attempting a time-based tenure extend. Defaults to 25%. + +### Fixed + +- Correctly produce the receipt for the `costs-4` contract, which was deployed on epoch 3.3 activation. Users who consume node events and want to fill in the missing receipt (e.g. the Hiro API) will need to revert their chainstate to before the 3.3 activation and then resume sync to receive the previously missing event. + ## [3.3.0.0.1] - Add indexes to `nakamoto_block_headers` to fix a performance regression. Node may take a few minutes to restart during the upgrade while the new indexes are created. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 613e8c973ee..4c346bdf781 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -498,10 +498,10 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { /// /// # Errors /// - /// - Returns CheckErrors::WriteAttemptedInReadOnly if there is a read-only + /// - Returns CheckErrorKind::WriteAttemptedInReadOnly if there is a read-only /// violation, i.e. if some function marked read-only attempts to modify /// the chainstate. - pub fn run(&mut self, contract_analysis: &ContractAnalysis) -> Result<(), CheckError> + pub fn run(&mut self, contract_analysis: &ContractAnalysis) -> Result<(), StaticCheckError> ``` This comment is considered positive because it explains the contract of the function in pseudo-code. Someone who understands the constructs mentioned could, e.g., write a test for this method from this description. diff --git a/Cargo.lock b/Cargo.lock index 5f619f40914..42ad15007e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -383,12 +383,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" - [[package]] name = "base16ct" version = "0.2.0" @@ -590,7 +584,7 @@ name = "clarity" version = "0.0.1" dependencies = [ "assert-json-diff 1.1.0", - "clarity-types", + "clarity-types 0.0.1", "integer-sqrt", "lazy_static", "mutants", @@ -610,13 +604,11 @@ dependencies = [ [[package]] name = "clarity" version = "0.0.1" -source = "git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2#8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2" +source = "git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5#b3efa588571e168d2d154790e1c57d9e3e64adc5" dependencies = [ - "hashbrown 0.15.2", + "clarity-types 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "integer-sqrt", "lazy_static", - "rand 0.8.5", - "rand_chacha 0.3.1", "regex", "rstest", "rstest_reuse", @@ -626,8 +618,23 @@ dependencies = [ "serde_json", "serde_stacker", "slog", - "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", - "time 0.2.27", + "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", +] + +[[package]] +name = "clarity-cli" +version = "0.1.0" +dependencies = [ + "clarity 0.0.1", + "lazy_static", + "rand 0.8.5", + "rusqlite", + "serde", + "serde_derive", + "serde_json", + "slog", + "stacks-common 0.0.1", + "stackslib 0.0.1", ] [[package]] @@ -646,6 +653,21 @@ dependencies = [ "stacks-common 0.0.1", ] +[[package]] +name = "clarity-types" +version = "0.0.1" +source = "git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5#b3efa588571e168d2d154790e1c57d9e3e64adc5" +dependencies = [ + "lazy_static", + "regex", + "rusqlite", + "serde", + "serde_derive", + "serde_json", + "slog", + "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", +] + [[package]] name = "colorchoice" version = "1.0.0" @@ -689,12 +711,6 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" -[[package]] -name = "const_fn" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f8a2ca5ac02d09563609681103aada9e1777d54fc57a5acd7a41404f9c93b6e" - [[package]] name = "core-foundation" version = "0.9.4" @@ -784,10 +800,9 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version", "serde", "subtle", - "zeroize", ] [[package]] @@ -868,12 +883,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "ecdsa" version = "0.16.9" @@ -895,8 +904,6 @@ version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "pkcs8", - "serde", "signature", ] @@ -908,11 +915,8 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", - "rand_core 0.6.4", - "serde", "sha2 0.10.8", "subtle", - "zeroize", ] [[package]] @@ -1373,7 +1377,7 @@ dependencies = [ "http 0.2.11", "httpdate", "mime", - "sha1 0.10.6", + "sha1", ] [[package]] @@ -1864,19 +1868,19 @@ dependencies = [ [[package]] name = "libsigner" version = "0.0.1" -source = "git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2#8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2" +source = "git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5#b3efa588571e168d2d154790e1c57d9e3e64adc5" dependencies = [ - "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "hashbrown 0.15.2", "lazy_static", "libc", - "libstackerdb 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "libstackerdb 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "serde", "serde_json", "sha2 0.10.8", "slog", - "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", - "stackslib 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", + "stackslib 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "thiserror", "tiny_http", ] @@ -1905,13 +1909,12 @@ dependencies = [ [[package]] name = "libstackerdb" version = "0.0.1" -source = "git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2#8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2" +source = "git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5#b3efa588571e168d2d154790e1c57d9e3e64adc5" dependencies = [ - "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", - "secp256k1", + "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "serde", "sha2 0.10.8", - "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", ] [[package]] @@ -2368,11 +2371,11 @@ dependencies = [ [[package]] name = "pox-locking" version = "2.4.0" -source = "git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2#8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2" +source = "git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5#b3efa588571e168d2d154790e1c57d9e3e64adc5" dependencies = [ - "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "slog", - "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", ] [[package]] @@ -2415,12 +2418,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.78" @@ -2756,7 +2753,7 @@ dependencies = [ "futures", "futures-timer", "rstest_macros", - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -2768,7 +2765,7 @@ dependencies = [ "cfg-if 1.0.0", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn 1.0.109", "unicode-ident", ] @@ -2781,7 +2778,7 @@ checksum = "45f80dcc84beab3a327bbe161f77db25f336a1452428176787c8c79ac79d7073" dependencies = [ "quote", "rand 0.8.5", - "rustc_version 0.4.0", + "rustc_version", "syn 1.0.109", ] @@ -2806,22 +2803,13 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.21", + "semver", ] [[package]] @@ -2977,27 +2965,12 @@ dependencies = [ "cc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.196" @@ -3097,15 +3070,6 @@ dependencies = [ "syn 2.0.58", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - [[package]] name = "sha1" version = "0.10.6" @@ -3117,12 +3081,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - [[package]] name = "sha2" version = "0.9.9" @@ -3222,7 +3180,7 @@ dependencies = [ "serde", "serde_json", "slog", - "time 0.3.41", + "time", ] [[package]] @@ -3235,7 +3193,7 @@ dependencies = [ "slog", "term", "thread_local", - "time 0.3.41", + "time", ] [[package]] @@ -3304,6 +3262,7 @@ name = "stacks-cli" version = "0.1.0" dependencies = [ "clarity 0.0.1", + "clarity-cli", "serde_json", "stacks-common 0.0.1", "stackslib 0.0.1", @@ -3344,7 +3303,7 @@ dependencies = [ [[package]] name = "stacks-common" version = "0.0.1" -source = "git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2#8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2" +source = "git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5#b3efa588571e168d2d154790e1c57d9e3e64adc5" dependencies = [ "chrono", "curve25519-dalek", @@ -3353,6 +3312,7 @@ dependencies = [ "lazy_static", "libsecp256k1", "nix", + "p256", "rand 0.8.5", "ripemd", "rusqlite", @@ -3364,7 +3324,7 @@ dependencies = [ "sha3", "slog", "slog-term", - "time 0.2.27", + "thiserror", "toml", "winapi 0.3.9", ] @@ -3374,6 +3334,7 @@ name = "stacks-inspect" version = "0.1.0" dependencies = [ "clarity 0.0.1", + "clarity-cli", "libstackerdb 0.0.1", "mutants", "regex", @@ -3400,7 +3361,7 @@ dependencies = [ "lazy_static", "libc", "libsigner 0.0.1", - "libsigner 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "libsigner 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "madhouse", "mockito", "mutants", @@ -3417,12 +3378,12 @@ dependencies = [ "serial_test", "slog", "stacks-common 0.0.1", - "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "stacks-inspect", "stacks-signer 0.0.1", - "stacks-signer 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "stacks-signer 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "stackslib 0.0.1", - "stackslib 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "stackslib 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "stdext", "stx-genesis", "tempfile", @@ -3472,26 +3433,25 @@ dependencies = [ [[package]] name = "stacks-signer" version = "0.0.1" -source = "git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2#8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2" +source = "git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5#b3efa588571e168d2d154790e1c57d9e3e64adc5" dependencies = [ "backoff", "clap", - "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "hashbrown 0.15.2", "lazy_static", - "libsigner 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", - "libstackerdb 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "libsigner 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", + "libstackerdb 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "rand 0.8.5", "rand_core 0.6.4", "reqwest", "rusqlite", - "secp256k1", "serde", "serde_json", "slog", "slog-term", - "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", - "stackslib 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", + "stackslib 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "thiserror", "toml", "tracing", @@ -3536,7 +3496,7 @@ dependencies = [ "stdext", "stx-genesis", "tempfile", - "time 0.3.41", + "time", "toml", "url", "winapi 0.3.9", @@ -3545,103 +3505,42 @@ dependencies = [ [[package]] name = "stackslib" version = "0.0.1" -source = "git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2#8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2" +source = "git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5#b3efa588571e168d2d154790e1c57d9e3e64adc5" dependencies = [ "chrono", - "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "clarity 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "ed25519-dalek", - "hashbrown 0.15.2", "lazy_static", - "libstackerdb 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "libstackerdb 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "mio 0.6.23", "nix", "percent-encoding", - "pox-locking 2.4.0 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", + "pox-locking 2.4.0 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", "rand 0.8.5", "rand_chacha 0.3.1", "rand_core 0.6.4", "regex", "ripemd", "rusqlite", - "secp256k1", "serde", "serde_derive", "serde_json", "sha2 0.10.8", "siphasher", "slog", - "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2)", - "tikv-jemallocator", - "time 0.2.27", + "stacks-common 0.0.1 (git+https://github.com/stacks-network/stacks-core.git?rev=b3efa588571e168d2d154790e1c57d9e3e64adc5)", + "time", "toml", "url", "winapi 0.3.9", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - [[package]] name = "stdext" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6012f6ef4d674ce7021a8b0f5093f7e339f54d4ba04fc1f9c901659459b4f35b" -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1 0.6.1", - "syn 1.0.109", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "strsim" version = "0.11.0" @@ -3785,21 +3684,6 @@ dependencies = [ "tikv-jemalloc-sys", ] -[[package]] -name = "time" -version = "0.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" -dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros 0.1.1", - "version_check", - "winapi 0.3.9", -] - [[package]] name = "time" version = "0.3.41" @@ -3814,7 +3698,7 @@ dependencies = [ "powerfmt", "serde", "time-core", - "time-macros 0.2.22", + "time-macros", ] [[package]] @@ -3823,16 +3707,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" -[[package]] -name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - [[package]] name = "time-macros" version = "0.2.22" @@ -3843,19 +3717,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "time-macros-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn 1.0.109", -] - [[package]] name = "tiny_http" version = "0.12.0" @@ -4043,7 +3904,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "sha1 0.10.6", + "sha1", "thiserror", "url", "utf-8", diff --git a/Cargo.toml b/Cargo.toml index 26b166c4834..b54aa38aa13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "stacks-signer", "stacks-node", "contrib/stacks-inspect", + "contrib/clarity-cli", "contrib/stacks-cli" ] diff --git a/clarity-types/src/errors/analysis.rs b/clarity-types/src/errors/analysis.rs index 876a9199573..f98348f6077 100644 --- a/clarity-types/src/errors/analysis.rs +++ b/clarity-types/src/errors/analysis.rs @@ -136,213 +136,410 @@ impl SyntaxBindingError { } } -impl From for CheckErrors { +impl From for CheckErrorKind { fn from(e: SyntaxBindingError) -> Self { Self::BadSyntaxBinding(e) } } +/// Errors encountered during type-checking and analysis of Clarity contract code, ensuring +/// type safety, correct function signatures, and adherence to resource constraints. +/// These errors prevent invalid contracts from being deployed or executed, +/// halting analysis and failing the transaction or contract deployment. #[derive(Debug, PartialEq)] -pub enum CheckErrors { - // cost checker errors +pub enum CheckErrorKind { + // Cost checker errors + /// Arithmetic overflow in cost computation during type-checking, exceeding the maximum threshold. CostOverflow, + /// Cumulative type-checking cost exceeds the allocated budget, indicating budget depletion. + /// The first `ExecutionCost` represents the total consumed cost, and the second represents the budget limit. CostBalanceExceeded(ExecutionCost, ExecutionCost), + /// Memory usage during type-checking exceeds the allocated budget. + /// The first `u64` represents the total consumed memory, and the second represents the memory limit. MemoryBalanceExceeded(u64, u64), + /// Failure in cost-tracking due to an unexpected condition or invalid state. + /// The `String` wraps the specific reason for the failure. CostComputationFailed(String), + // Time checker errors + /// Type-checking time exceeds the allowed budget, halting analysis to ensure responsiveness. + ExecutionTimeExpired, + /// Value exceeds the maximum allowed size for type-checking or serialization. ValueTooLarge, + /// Value is outside the acceptable range for its type (e.g., integer bounds). ValueOutOfBounds, + /// Type signature nesting depth exceeds the allowed limit during analysis. TypeSignatureTooDeep, + /// Expected a name (e.g., variable, function) but found an invalid or missing token. ExpectedName, + /// Supertype (e.g., trait or union) exceeds the maximum allowed size or complexity. + /// This error indicates a transaction would invalidate a block if included. SupertypeTooLarge, - // unexpected interpreter behavior + // Unexpected interpreter behavior + /// Unexpected condition or failure in the type-checker, indicating a bug or invalid state. + /// This error indicates a transaction would invalidate a block if included. Expects(String), - // match errors - BadMatchOptionSyntax(Box), - BadMatchResponseSyntax(Box), + // Match expression errors + /// Invalid syntax in an `option` match expression. + /// The `Box` wraps the underlying error causing the syntax issue. + BadMatchOptionSyntax(Box), + /// Invalid syntax in a `response` match expression. + /// The `Box` wraps the underlying error causing the syntax issue. + BadMatchResponseSyntax(Box), + /// Input to a `match` expression does not conform to the expected type (e.g., `Option` or `Response`). + /// The `Box` wraps the actual type of the provided input. BadMatchInput(Box), - // list typing errors + // List typing errors + /// List elements have mismatched types, violating type consistency. ListTypesMustMatch, + /// Constructed list exceeds the maximum allowed length during type-checking. ConstructedListTooLarge, - // simple type expectation mismatch + // Type mismatch errors + /// Expected type does not match the actual type during analysis. + /// The first `Box` wraps the expected type, and the second wraps the actual type. TypeError(Box, Box), + /// Value does not match the expected type during type-checking. + /// The `Box` wraps the expected type, and the `Box` wraps the invalid value. TypeValueError(Box, Box), + /// Type description is invalid or malformed, preventing proper type-checking. InvalidTypeDescription, + /// Referenced type name does not exist or is undefined. + /// The `String` wraps the non-existent type name. UnknownTypeName(String), - // union type mismatch + // Union type mismatch + /// Type does not belong to the expected union of types during analysis. + /// The `Vec` represents the expected types, and the `Box` wraps the actual type. UnionTypeError(Vec, Box), + /// Value does not belong to the expected union of types during type-checking. + /// The `Vec` represents the expected types, and the `Box` wraps the invalid value. UnionTypeValueError(Vec, Box), + /// Expected an optional type but found a different type. + /// The `Box` wraps the actual type provided. ExpectedOptionalType(Box), + /// Expected a response type but found a different type. + /// The `Box` wraps the actual type provided. ExpectedResponseType(Box), + /// Expected an optional or response type but found a different type. + /// The `Box` wraps the actual type provided. ExpectedOptionalOrResponseType(Box), + /// Expected an optional value but found a different value. + /// The `Box` wraps the actual value provided. ExpectedOptionalValue(Box), + /// Expected a response value but found a different value. + /// The `Box` wraps the actual value provided. ExpectedResponseValue(Box), + /// Expected an optional or response value but found a different value. + /// The `Box` wraps the actual value provided. ExpectedOptionalOrResponseValue(Box), + /// Could not determine the type of the `ok` branch in a response type. CouldNotDetermineResponseOkType, + /// Could not determine the type of the `err` branch in a response type. CouldNotDetermineResponseErrType, + /// Could not determine the serialization type for a value during analysis. CouldNotDetermineSerializationType, + /// Intermediary response types were not properly checked, risking type safety. UncheckedIntermediaryResponses, + /// Expected a contract principal value but found a different value. + /// The `Box` wraps the actual value provided. ExpectedContractPrincipalValue(Box), + // Match type errors + /// Could not determine the types for a match expression’s branches. CouldNotDetermineMatchTypes, + /// Could not determine the type of an expression during analysis. CouldNotDetermineType, // Checker runtime failures + /// Attempt to re-annotate a type that was already annotated, indicating a bug. TypeAlreadyAnnotatedFailure, + /// Unexpected failure in the type-checker implementation, indicating a bug. CheckerImplementationFailure, // Assets + /// Expected a token name as an argument but found an invalid token. BadTokenName, + /// Invalid or malformed signature in a `(define-non-fungible-token ...)` expression. DefineNFTBadSignature, + /// Referenced non-fungible token (NFT) does not exist. + /// The `String` wraps the non-existent token name. NoSuchNFT(String), + /// Referenced fungible token (FT) does not exist. + /// The `String` wraps the non-existent token name. NoSuchFT(String), + // Transfer and asset operation errors + /// Invalid arguments provided to a `stx-transfer?` function. BadTransferSTXArguments, + /// Invalid arguments provided to a fungible token transfer function. BadTransferFTArguments, + /// Invalid arguments provided to a non-fungible token transfer function. BadTransferNFTArguments, + /// Invalid arguments provided to a fungible token mint function. BadMintFTArguments, + /// Invalid arguments provided to a fungible token burn function. BadBurnFTArguments, - // tuples + // Tuples + /// Tuple field name is invalid or violates naming rules. BadTupleFieldName, + /// Expected a tuple type but found a different type. + /// The `Box` wraps the actual type provided. ExpectedTuple(Box), + /// Referenced tuple field does not exist in the tuple type. + /// The `String` wraps the requested field name, and the `TupleTypeSignature` wraps the tuple’s type. NoSuchTupleField(String, TupleTypeSignature), + /// Empty tuple is not allowed in Clarity. EmptyTuplesNotAllowed, + /// Invalid tuple construction due to malformed syntax or type mismatch. + /// The `String` wraps the specific error description. BadTupleConstruction(String), - // variables + // Variables + /// Referenced data variable does not exist in scope. + /// The `String` wraps the non-existent variable name. NoSuchDataVariable(String), - // data map + // Data map + /// Map name is invalid or violates naming rules. BadMapName, + /// Referenced data map does not exist in scope. + /// The `String` wraps the non-existent map name. NoSuchMap(String), - // defines + // Defines + /// Invalid or malformed signature in a function definition. DefineFunctionBadSignature, + /// Function name is invalid or violates naming rules. BadFunctionName, + /// Invalid or malformed map type definition in a `(define-map ...)` expression. BadMapTypeDefinition, + /// Public function must return a response type, but found a different type. + /// The `Box` wraps the actual return type. PublicFunctionMustReturnResponse(Box), + /// Invalid or malformed variable definition in a `(define-data-var ...)` expression. DefineVariableBadSignature, + /// Return types of function branches do not match the expected type. + /// The first `Box` wraps the expected type, and the second wraps the actual type. ReturnTypesMustMatch(Box, Box), + /// Circular reference detected in interdependent function definitions. + /// The `Vec` represents the list of referenced names forming the cycle. CircularReference(Vec), - // contract-call errors + // Contract-call errors + /// Referenced contract does not exist. + /// The `String` wraps the non-existent contract name. NoSuchContract(String), + /// Referenced public function does not exist in the specified contract. + /// The first `String` wraps the contract name, and the second wraps the function name. NoSuchPublicFunction(String, String), + /// Public function is not read-only when expected to be. + /// The first `String` wraps the contract name, and the second wraps the function name. PublicFunctionNotReadOnly(String, String), + /// Attempt to define a contract with a name that already exists. + /// The `String` wraps the conflicting contract name. ContractAlreadyExists(String), + /// Expected a contract name in a `contract-call?` expression but found an invalid token. ContractCallExpectName, + /// Expected a callable type (e.g., function or trait) but found a different type. + /// The `Box` wraps the actual type provided. ExpectedCallableType(Box), // get-block-info? errors + /// Referenced block info property does not exist. + /// The `String` wraps the non-existent property name. NoSuchBlockInfoProperty(String), + /// Referenced burn block info property does not exist. + /// The `String` wraps the non-existent property name. NoSuchBurnBlockInfoProperty(String), + /// Referenced Stacks block info property does not exist. + /// The `String` wraps the non-existent property name. NoSuchStacksBlockInfoProperty(String), + /// Referenced tenure info property does not exist. + /// The `String` wraps the non-existent property name. NoSuchTenureInfoProperty(String), + /// Expected a block info property name but found an invalid token. GetBlockInfoExpectPropertyName, + /// Expected a burn block info property name but found an invalid token. GetBurnBlockInfoExpectPropertyName, + /// Expected a Stacks block info property name but found an invalid token. GetStacksBlockInfoExpectPropertyName, + /// Expected a tenure info property name but found an invalid token. GetTenureInfoExpectPropertyName, + /// Name (e.g., variable, function) is already in use within the same scope. + /// The `String` wraps the conflicting name. NameAlreadyUsed(String), + /// Name is a reserved word in Clarity and cannot be used. + /// The `String` wraps the reserved name. ReservedWord(String), - // expect a function, or applying a function to a list + // Expect a function, or applying a function to a list + /// Attempt to apply a non-function value as a function. NonFunctionApplication, + /// Expected a list application but found a different expression. ExpectedListApplication, + /// Expected a sequence type (e.g., list, buffer) but found a different type. + /// The `Box` wraps the actual type provided. ExpectedSequence(Box), + /// Sequence length exceeds the maximum allowed limit. MaxLengthOverflow, - // let syntax + // Let syntax + /// Invalid syntax in a `let` expression, violating binding or structure rules. BadLetSyntax, - // generic binding syntax + // Generic binding syntax + /// Invalid binding syntax in a generic construct (e.g., `let`, `match`). + /// The `SyntaxBindingError` wraps the specific binding error. BadSyntaxBinding(SyntaxBindingError), + /// Maximum context depth for type-checking has been reached. MaxContextDepthReached, + /// Referenced function is not defined in the current scope. + /// The `String` wraps the non-existent function name. UndefinedFunction(String), + /// Referenced variable is not defined in the current scope. + /// The `String` wraps the non-existent variable name. UndefinedVariable(String), - // argument counts + // Argument counts + /// Function requires at least the specified number of arguments, but fewer were provided. + /// The first `usize` represents the minimum required, and the second represents the actual count. RequiresAtLeastArguments(usize, usize), + /// Function requires at most the specified number of arguments, but more were provided. + /// The first `usize` represents the maximum allowed, and the second represents the actual count. RequiresAtMostArguments(usize, usize), + /// Incorrect number of arguments provided to a function. + /// The first `usize` represents the expected count, and the second represents the actual count. IncorrectArgumentCount(usize, usize), + /// `if` expression arms have mismatched return types. + /// The first `Box` wraps the type of one arm, and the second wraps the other. IfArmsMustMatch(Box, Box), + /// `match` expression arms have mismatched return types. + /// The first `Box` wraps the type of one arm, and the second wraps the other. MatchArmsMustMatch(Box, Box), + /// `default-to` expression types are mismatched. + /// The first `Box` wraps the expected type, and the second wraps the actual type. DefaultTypesMustMatch(Box, Box), + /// Application of an illegal or unknown function. + /// The `String` wraps the function name. IllegalOrUnknownFunctionApplication(String), + /// Referenced function is unknown or not defined. + /// The `String` wraps the non-existent function name. UnknownFunction(String), + /// Too many function parameters specified. + /// The first `usize` represents the number of parameters found, the second represents the maximum allowed. TooManyFunctionParameters(usize, usize), - // traits + // Traits + /// Referenced trait does not exist in the specified contract. + /// The first `String` wraps the contract name, and the second wraps the trait name. NoSuchTrait(String, String), + /// Referenced trait is not defined or cannot be found. + /// The `String` wraps the non-existent trait name. TraitReferenceUnknown(String), + /// Referenced method does not exist in the specified trait. + /// The first `String` wraps the trait name, and the second wraps the method name. TraitMethodUnknown(String, String), + /// Expected a trait identifier (e.g., `.trait-name`) but found an invalid token. ExpectedTraitIdentifier, + /// Trait reference is not allowed in the current context (e.g., storage). TraitReferenceNotAllowed, + /// Invalid implementation of a trait method. + /// The first `String` wraps the trait name, and the second wraps the method name. BadTraitImplementation(String, String), + /// Invalid or malformed signature in a `(define-trait ...)` expression. DefineTraitBadSignature, + /// Trait definition contains duplicate method names. + /// The `String` wraps the duplicate method name. DefineTraitDuplicateMethod(String), + /// Unexpected use of a trait or field reference in a non-trait context. UnexpectedTraitOrFieldReference, + /// Trait-based contract call used in a read-only context, which is prohibited. TraitBasedContractCallInReadOnly, + /// `contract-of` expects a trait type but found a different type. ContractOfExpectsTrait, + /// Trait implementation is incompatible with the expected trait definition. + /// The first `Box` wraps the expected trait, and the second wraps the actual trait. IncompatibleTrait(Box, Box), + /// Too many trait methods specified. + /// The first `usize` represents the number of methods found, the second the maximum allowed. TraitTooManyMethods(usize, usize), - // strings + // Strings + /// String contains invalid or disallowed characters (e.g., non-ASCII in ASCII strings). InvalidCharactersDetected, + /// String contains invalid UTF-8 encoding. InvalidUTF8Encoding, // secp256k1 signature + /// Invalid secp256k1 signature provided in an expression. InvalidSecp65k1Signature, + /// Attempt to write to contract state in a read-only function. WriteAttemptedInReadOnly, + /// `at-block` closure must be read-only but contains write operations. AtBlockClosureMustBeReadOnly, - // time checker errors - ExecutionTimeExpired, - // contract post-conditions + /// Post-condition expects a list of asset allowances but received invalid input. + /// The first `String` wraps the function name, and the second `i32` wraps the argument number. ExpectedListOfAllowances(String, i32), + /// Allowance expressions are only allowed in specific contexts (`restrict-assets?` or `as-contract?`). AllowanceExprNotAllowed, + /// Expected an allowance expression but found invalid input. + /// The `String` wraps the unexpected input. ExpectedAllowanceExpr(String), + /// `with-all-assets-unsafe` is not allowed in this context. WithAllAllowanceNotAllowed, + /// `with-all-assets-unsafe` cannot be used alongside other allowances. WithAllAllowanceNotAlone, + /// `with-nft` allowance requires a list of asset identifiers. WithNftExpectedListOfIdentifiers, + /// `with-nft` allowance identifiers list exceeds the maximum allowed length. + /// The first `u32` represents the maximum length, and the second represents the actual length. MaxIdentifierLengthExceeded(u32, u32), + /// Too many allowances specified in post-condition. + /// The first `usize` represents the maximum allowed, and the second represents the actual count. TooManyAllowances(usize, usize), } #[derive(Debug, PartialEq)] -pub struct CheckError { - pub err: Box, +/// Represents an error encountered during Clarity's type-checking and semantic analysis phase. +/// Wraps a `CheckErrorKind` variant, optionally includes the expressions causing the error, +/// and provides diagnostic information for debugging. +pub struct StaticCheckError { + /// The specific type-checking or semantic error that occurred. + pub err: Box, + /// Optional vector of expressions related to the error, if available. pub expressions: Option>, + /// Diagnostic details (e.g., line/column numbers, error message, suggestions) around the error. pub diagnostic: Diagnostic, } -impl CheckErrors { +impl CheckErrorKind { /// Does this check error indicate that the transaction should be /// rejected? pub fn rejectable(&self) -> bool { matches!( self, - CheckErrors::SupertypeTooLarge | CheckErrors::Expects(_) + CheckErrorKind::SupertypeTooLarge | CheckErrorKind::Expects(_) ) } } -impl CheckError { - pub fn new(err: CheckErrors) -> CheckError { +impl StaticCheckError { + pub fn new(err: CheckErrorKind) -> StaticCheckError { let diagnostic = Diagnostic::err(&err); - CheckError { + StaticCheckError { err: Box::new(err), expressions: None, diagnostic, @@ -363,40 +560,40 @@ impl CheckError { self.expressions.replace(exprs.to_vec()); } - pub fn with_expression(err: CheckErrors, expr: &SymbolicExpression) -> Self { + pub fn with_expression(err: CheckErrorKind, expr: &SymbolicExpression) -> Self { let mut r = Self::new(err); r.set_expression(expr); r } } -impl From<(SyntaxBindingError, &SymbolicExpression)> for CheckError { +impl From<(SyntaxBindingError, &SymbolicExpression)> for StaticCheckError { fn from(e: (SyntaxBindingError, &SymbolicExpression)) -> Self { - Self::with_expression(CheckErrors::BadSyntaxBinding(e.0), e.1) + Self::with_expression(CheckErrorKind::BadSyntaxBinding(e.0), e.1) } } -impl From<(CheckErrors, &SymbolicExpression)> for CheckError { - fn from(e: (CheckErrors, &SymbolicExpression)) -> Self { +impl From<(CheckErrorKind, &SymbolicExpression)> for StaticCheckError { + fn from(e: (CheckErrorKind, &SymbolicExpression)) -> Self { let mut ce = Self::new(e.0); ce.set_expression(e.1); ce } } -impl From<(CheckErrors, &SymbolicExpression)> for CheckErrors { - fn from(e: (CheckErrors, &SymbolicExpression)) -> Self { +impl From<(CheckErrorKind, &SymbolicExpression)> for CheckErrorKind { + fn from(e: (CheckErrorKind, &SymbolicExpression)) -> Self { e.0 } } -impl fmt::Display for CheckErrors { +impl fmt::Display for CheckErrorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{self:?}") } } -impl fmt::Display for CheckError { +impl fmt::Display for StaticCheckError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.err)?; @@ -408,75 +605,81 @@ impl fmt::Display for CheckError { } } -impl From for CheckError { +impl From for StaticCheckError { fn from(err: CostErrors) -> Self { - CheckError::from(CheckErrors::from(err)) + StaticCheckError::from(CheckErrorKind::from(err)) } } -impl From for CheckErrors { +impl From for CheckErrorKind { fn from(err: CostErrors) -> Self { match err { - CostErrors::CostOverflow => CheckErrors::CostOverflow, - CostErrors::CostBalanceExceeded(a, b) => CheckErrors::CostBalanceExceeded(a, b), - CostErrors::MemoryBalanceExceeded(a, b) => CheckErrors::MemoryBalanceExceeded(a, b), - CostErrors::CostComputationFailed(s) => CheckErrors::CostComputationFailed(s), + CostErrors::CostOverflow => CheckErrorKind::CostOverflow, + CostErrors::CostBalanceExceeded(a, b) => CheckErrorKind::CostBalanceExceeded(a, b), + CostErrors::MemoryBalanceExceeded(a, b) => CheckErrorKind::MemoryBalanceExceeded(a, b), + CostErrors::CostComputationFailed(s) => CheckErrorKind::CostComputationFailed(s), CostErrors::CostContractLoadFailure => { - CheckErrors::CostComputationFailed("Failed to load cost contract".into()) + CheckErrorKind::CostComputationFailed("Failed to load cost contract".into()) } CostErrors::InterpreterFailure => { - CheckErrors::Expects("Unexpected interpreter failure in cost computation".into()) + CheckErrorKind::Expects("Unexpected interpreter failure in cost computation".into()) } - CostErrors::Expect(s) => CheckErrors::Expects(s), - CostErrors::ExecutionTimeExpired => CheckErrors::ExecutionTimeExpired, + CostErrors::Expect(s) => CheckErrorKind::Expects(s), + CostErrors::ExecutionTimeExpired => CheckErrorKind::ExecutionTimeExpired, } } } -impl error::Error for CheckError { +impl error::Error for StaticCheckError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { None } } -impl error::Error for CheckErrors { +impl error::Error for CheckErrorKind { fn source(&self) -> Option<&(dyn error::Error + 'static)> { None } } -impl From for CheckError { - fn from(err: CheckErrors) -> Self { - CheckError::new(err) +impl From for StaticCheckError { + fn from(err: CheckErrorKind) -> Self { + StaticCheckError::new(err) } } #[cfg(any(test, feature = "testing"))] -impl From for String { - fn from(o: CheckErrors) -> Self { +impl From for String { + fn from(o: CheckErrorKind) -> Self { o.to_string() } } -pub fn check_argument_count(expected: usize, args: &[T]) -> Result<(), CheckErrors> { +pub fn check_argument_count(expected: usize, args: &[T]) -> Result<(), CheckErrorKind> { if args.len() != expected { - Err(CheckErrors::IncorrectArgumentCount(expected, args.len())) + Err(CheckErrorKind::IncorrectArgumentCount(expected, args.len())) } else { Ok(()) } } -pub fn check_arguments_at_least(expected: usize, args: &[T]) -> Result<(), CheckErrors> { +pub fn check_arguments_at_least(expected: usize, args: &[T]) -> Result<(), CheckErrorKind> { if args.len() < expected { - Err(CheckErrors::RequiresAtLeastArguments(expected, args.len())) + Err(CheckErrorKind::RequiresAtLeastArguments( + expected, + args.len(), + )) } else { Ok(()) } } -pub fn check_arguments_at_most(expected: usize, args: &[T]) -> Result<(), CheckErrors> { +pub fn check_arguments_at_most(expected: usize, args: &[T]) -> Result<(), CheckErrorKind> { if args.len() > expected { - Err(CheckErrors::RequiresAtMostArguments(expected, args.len())) + Err(CheckErrorKind::RequiresAtMostArguments( + expected, + args.len(), + )) } else { Ok(()) } @@ -497,149 +700,149 @@ fn formatted_expected_types(expected_types: &[TypeSignature]) -> String { expected_types_joined } -impl DiagnosableError for CheckErrors { +impl DiagnosableError for CheckErrorKind { fn message(&self) -> String { match &self { - CheckErrors::SupertypeTooLarge => "supertype of two types is too large".into(), - CheckErrors::Expects(s) => format!("unexpected interpreter behavior: {s}"), - CheckErrors::BadMatchOptionSyntax(source) => + CheckErrorKind::SupertypeTooLarge => "supertype of two types is too large".into(), + CheckErrorKind::Expects(s) => format!("unexpected interpreter behavior: {s}"), + CheckErrorKind::BadMatchOptionSyntax(source) => format!("match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: {}", source.message()), - CheckErrors::BadMatchResponseSyntax(source) => + CheckErrorKind::BadMatchResponseSyntax(source) => format!("match on a result type uses the following syntax: (match input ok-name if-ok-expression err-name if-err-expression). Caused by: {}", source.message()), - CheckErrors::BadMatchInput(t) => + CheckErrorKind::BadMatchInput(t) => format!("match requires an input of either a response or optional, found input: '{t}'"), - CheckErrors::CostOverflow => "contract execution cost overflowed cost counter".into(), - CheckErrors::CostBalanceExceeded(a, b) => format!("contract execution cost exceeded budget: {a:?} > {b:?}"), - CheckErrors::MemoryBalanceExceeded(a, b) => format!("contract execution cost exceeded memory budget: {a:?} > {b:?}"), - CheckErrors::InvalidTypeDescription => "supplied type description is invalid".into(), - CheckErrors::EmptyTuplesNotAllowed => "tuple types may not be empty".into(), - CheckErrors::UnknownTypeName(name) => format!("failed to parse type: '{name}'"), - CheckErrors::ValueTooLarge => "created a type which was greater than maximum allowed value size".into(), - CheckErrors::ValueOutOfBounds => "created a type which value size was out of defined bounds".into(), - CheckErrors::TypeSignatureTooDeep => "created a type which was deeper than maximum allowed type depth".into(), - CheckErrors::ExpectedName => "expected a name argument to this function".into(), - CheckErrors::ListTypesMustMatch => "expecting elements of same type in a list".into(), - CheckErrors::ConstructedListTooLarge => "reached limit of elements in a sequence".into(), - CheckErrors::TypeError(expected_type, found_type) => format!("expecting expression of type '{expected_type}', found '{found_type}'"), - CheckErrors::TypeValueError(expected_type, found_value) => format!("expecting expression of type '{expected_type}', found '{found_value}'"), - CheckErrors::UnionTypeError(expected_types, found_type) => format!("expecting expression of type {}, found '{}'", formatted_expected_types(expected_types), found_type), - CheckErrors::UnionTypeValueError(expected_types, found_type) => format!("expecting expression of type {}, found '{}'", formatted_expected_types(expected_types), found_type), - CheckErrors::ExpectedOptionalType(found_type) => format!("expecting expression of type 'optional', found '{found_type}'"), - CheckErrors::ExpectedOptionalOrResponseType(found_type) => format!("expecting expression of type 'optional' or 'response', found '{found_type}'"), - CheckErrors::ExpectedOptionalOrResponseValue(found_value) => format!("expecting expression of type 'optional' or 'response', found '{found_value}'"), - CheckErrors::ExpectedResponseType(found_type) => format!("expecting expression of type 'response', found '{found_type}'"), - CheckErrors::ExpectedOptionalValue(found_value) => format!("expecting expression of type 'optional', found '{found_value}'"), - CheckErrors::ExpectedResponseValue(found_value) => format!("expecting expression of type 'response', found '{found_value}'"), - CheckErrors::ExpectedContractPrincipalValue(found_value) => format!("expecting contract principal value, found '{found_value}'"), - CheckErrors::CouldNotDetermineResponseOkType => "attempted to obtain 'ok' value from response, but 'ok' type is indeterminate".into(), - CheckErrors::CouldNotDetermineResponseErrType => "attempted to obtain 'err' value from response, but 'err' type is indeterminate".into(), - CheckErrors::CouldNotDetermineMatchTypes => "attempted to match on an (optional) or (response) type where either the some, ok, or err type is indeterminate. you may wish to use unwrap-panic or unwrap-err-panic instead.".into(), - CheckErrors::CouldNotDetermineType => "type of expression cannot be determined".into(), - CheckErrors::BadTupleFieldName => "invalid tuple field name".into(), - CheckErrors::ExpectedTuple(type_signature) => format!("expecting tuple, found '{type_signature}'"), - CheckErrors::NoSuchTupleField(field_name, tuple_signature) => format!("cannot find field '{field_name}' in tuple '{tuple_signature}'"), - CheckErrors::BadTupleConstruction(message) => format!("invalid tuple syntax: {message}"), - CheckErrors::NoSuchDataVariable(var_name) => format!("use of unresolved persisted variable '{var_name}'"), - CheckErrors::BadTransferSTXArguments => "STX transfer expects an int amount, from principal, to principal".into(), - CheckErrors::BadTransferFTArguments => "transfer expects an int amount, from principal, to principal".into(), - CheckErrors::BadTransferNFTArguments => "transfer expects an asset, from principal, to principal".into(), - CheckErrors::BadMintFTArguments => "mint expects a uint amount and from principal".into(), - CheckErrors::BadBurnFTArguments => "burn expects a uint amount and from principal".into(), - CheckErrors::BadMapName => "invalid map name".into(), - CheckErrors::NoSuchMap(map_name) => format!("use of unresolved map '{map_name}'"), - CheckErrors::DefineFunctionBadSignature => "invalid function definition".into(), - CheckErrors::BadFunctionName => "invalid function name".into(), - CheckErrors::BadMapTypeDefinition => "invalid map definition".into(), - CheckErrors::PublicFunctionMustReturnResponse(found_type) => format!("public functions must return an expression of type 'response', found '{found_type}'"), - CheckErrors::DefineVariableBadSignature => "invalid variable definition".into(), - CheckErrors::ReturnTypesMustMatch(type_1, type_2) => format!("detected two execution paths, returning two different expression types (got '{type_1}' and '{type_2}')"), - CheckErrors::NoSuchContract(contract_identifier) => format!("use of unresolved contract '{contract_identifier}'"), - CheckErrors::NoSuchPublicFunction(contract_identifier, function_name) => format!("contract '{contract_identifier}' has no public function '{function_name}'"), - CheckErrors::PublicFunctionNotReadOnly(contract_identifier, function_name) => format!("function '{contract_identifier}' in '{function_name}' is not read-only"), - CheckErrors::ContractAlreadyExists(contract_identifier) => format!("contract name '{contract_identifier}' conflicts with existing contract"), - CheckErrors::ContractCallExpectName => "missing contract name for call".into(), - CheckErrors::ExpectedCallableType(found_type) => format!("expected a callable contract, found {found_type}"), - CheckErrors::NoSuchBlockInfoProperty(property_name) => format!("use of block unknown property '{property_name}'"), - CheckErrors::NoSuchBurnBlockInfoProperty(property_name) => format!("use of burn block unknown property '{property_name}'"), - CheckErrors::NoSuchStacksBlockInfoProperty(property_name) => format!("use of unknown stacks block property '{property_name}'"), - CheckErrors::NoSuchTenureInfoProperty(property_name) => format!("use of unknown tenure property '{property_name}'"), - CheckErrors::GetBlockInfoExpectPropertyName => "missing property name for block info introspection".into(), - CheckErrors::GetBurnBlockInfoExpectPropertyName => "missing property name for burn block info introspection".into(), - CheckErrors::GetStacksBlockInfoExpectPropertyName => "missing property name for stacks block info introspection".into(), - CheckErrors::GetTenureInfoExpectPropertyName => "missing property name for tenure info introspection".into(), - CheckErrors::NameAlreadyUsed(name) => format!("defining '{name}' conflicts with previous value"), - CheckErrors::ReservedWord(name) => format!("{name} is a reserved word"), - CheckErrors::NonFunctionApplication => "expecting expression of type function".into(), - CheckErrors::ExpectedListApplication => "expecting expression of type list".into(), - CheckErrors::ExpectedSequence(found_type) => format!("expecting expression of type 'list', 'buff', 'string-ascii' or 'string-utf8' - found '{found_type}'"), - CheckErrors::MaxLengthOverflow => format!("expecting a value <= {}", u32::MAX), - CheckErrors::BadLetSyntax => "invalid syntax of 'let'".into(), - CheckErrors::CircularReference(references) => format!("detected circular reference: ({})", references.join(", ")), - CheckErrors::BadSyntaxBinding(binding_error) => format!("invalid syntax binding: {}", &binding_error.message()), - CheckErrors::MaxContextDepthReached => "reached depth limit".into(), - CheckErrors::UndefinedVariable(var_name) => format!("use of unresolved variable '{var_name}'"), - CheckErrors::UndefinedFunction(var_name) => format!("use of unresolved function '{var_name}'"), - CheckErrors::RequiresAtLeastArguments(expected, found) => format!("expecting >= {expected} arguments, got {found}"), - CheckErrors::RequiresAtMostArguments(expected, found) => format!("expecting < {expected} arguments, got {found}"), - CheckErrors::IncorrectArgumentCount(expected_count, found_count) => format!("expecting {expected_count} arguments, got {found_count}"), - CheckErrors::IfArmsMustMatch(type_1, type_2) => format!("expression types returned by the arms of 'if' must match (got '{type_1}' and '{type_2}')"), - CheckErrors::MatchArmsMustMatch(type_1, type_2) => format!("expression types returned by the arms of 'match' must match (got '{type_1}' and '{type_2}')"), - CheckErrors::DefaultTypesMustMatch(type_1, type_2) => format!("expression types passed in 'default-to' must match (got '{type_1}' and '{type_2}')"), - CheckErrors::IllegalOrUnknownFunctionApplication(function_name) => format!("use of illegal / unresolved function '{function_name}"), - CheckErrors::UnknownFunction(function_name) => format!("use of unresolved function '{function_name}'"), - CheckErrors::TooManyFunctionParameters(found, allowed) => format!("too many function parameters specified: found {found}, the maximum is {allowed}"), - CheckErrors::TraitBasedContractCallInReadOnly => "use of trait based contract calls are not allowed in read-only context".into(), - CheckErrors::WriteAttemptedInReadOnly => "expecting read-only statements, detected a writing operation".into(), - CheckErrors::AtBlockClosureMustBeReadOnly => "(at-block ...) closures expect read-only statements, but detected a writing operation".into(), - CheckErrors::BadTokenName => "expecting an token name as an argument".into(), - CheckErrors::DefineNFTBadSignature => "(define-asset ...) expects an asset name and an asset identifier type signature as arguments".into(), - CheckErrors::NoSuchNFT(asset_name) => format!("tried to use asset function with a undefined asset ('{asset_name}')"), - CheckErrors::NoSuchFT(asset_name) => format!("tried to use token function with a undefined token ('{asset_name}')"), - CheckErrors::NoSuchTrait(contract_name, trait_name) => format!("use of unresolved trait {contract_name}.{trait_name}"), - CheckErrors::TraitReferenceUnknown(trait_name) => format!("use of undeclared trait <{trait_name}>"), - CheckErrors::TraitMethodUnknown(trait_name, func_name) => format!("method '{func_name}' unspecified in trait <{trait_name}>"), - CheckErrors::BadTraitImplementation(trait_name, func_name) => format!("invalid signature for method '{func_name}' regarding trait's specification <{trait_name}>"), - CheckErrors::ExpectedTraitIdentifier => "expecting expression of type trait identifier".into(), - CheckErrors::UnexpectedTraitOrFieldReference => "unexpected use of trait reference or field".into(), - CheckErrors::DefineTraitBadSignature => "invalid trait definition".into(), - CheckErrors::DefineTraitDuplicateMethod(method_name) => format!("duplicate method name '{method_name}' in trait definition"), - CheckErrors::TraitReferenceNotAllowed => "trait references can not be stored".into(), - CheckErrors::ContractOfExpectsTrait => "trait reference expected".into(), - CheckErrors::IncompatibleTrait(expected_trait, actual_trait) => format!("trait '{actual_trait}' is not a compatible with expected trait, '{expected_trait}'"), - CheckErrors::TraitTooManyMethods(found, allowed) => format!("too many trait methods specified: found {found}, the maximum is {allowed}"), - CheckErrors::InvalidCharactersDetected => "invalid characters detected".into(), - CheckErrors::InvalidUTF8Encoding => "invalid UTF8 encoding".into(), - CheckErrors::InvalidSecp65k1Signature => "invalid seckp256k1 signature".into(), - CheckErrors::TypeAlreadyAnnotatedFailure | CheckErrors::CheckerImplementationFailure => { + CheckErrorKind::CostOverflow => "contract execution cost overflowed cost counter".into(), + CheckErrorKind::CostBalanceExceeded(a, b) => format!("contract execution cost exceeded budget: {a:?} > {b:?}"), + CheckErrorKind::MemoryBalanceExceeded(a, b) => format!("contract execution cost exceeded memory budget: {a:?} > {b:?}"), + CheckErrorKind::InvalidTypeDescription => "supplied type description is invalid".into(), + CheckErrorKind::EmptyTuplesNotAllowed => "tuple types may not be empty".into(), + CheckErrorKind::UnknownTypeName(name) => format!("failed to parse type: '{name}'"), + CheckErrorKind::ValueTooLarge => "created a type which was greater than maximum allowed value size".into(), + CheckErrorKind::ValueOutOfBounds => "created a type which value size was out of defined bounds".into(), + CheckErrorKind::TypeSignatureTooDeep => "created a type which was deeper than maximum allowed type depth".into(), + CheckErrorKind::ExpectedName => "expected a name argument to this function".into(), + CheckErrorKind::ListTypesMustMatch => "expecting elements of same type in a list".into(), + CheckErrorKind::ConstructedListTooLarge => "reached limit of elements in a sequence".into(), + CheckErrorKind::TypeError(expected_type, found_type) => format!("expecting expression of type '{expected_type}', found '{found_type}'"), + CheckErrorKind::TypeValueError(expected_type, found_value) => format!("expecting expression of type '{expected_type}', found '{found_value}'"), + CheckErrorKind::UnionTypeError(expected_types, found_type) => format!("expecting expression of type {}, found '{}'", formatted_expected_types(expected_types), found_type), + CheckErrorKind::UnionTypeValueError(expected_types, found_type) => format!("expecting expression of type {}, found '{}'", formatted_expected_types(expected_types), found_type), + CheckErrorKind::ExpectedOptionalType(found_type) => format!("expecting expression of type 'optional', found '{found_type}'"), + CheckErrorKind::ExpectedOptionalOrResponseType(found_type) => format!("expecting expression of type 'optional' or 'response', found '{found_type}'"), + CheckErrorKind::ExpectedOptionalOrResponseValue(found_value) => format!("expecting expression of type 'optional' or 'response', found '{found_value}'"), + CheckErrorKind::ExpectedResponseType(found_type) => format!("expecting expression of type 'response', found '{found_type}'"), + CheckErrorKind::ExpectedOptionalValue(found_value) => format!("expecting expression of type 'optional', found '{found_value}'"), + CheckErrorKind::ExpectedResponseValue(found_value) => format!("expecting expression of type 'response', found '{found_value}'"), + CheckErrorKind::ExpectedContractPrincipalValue(found_value) => format!("expecting contract principal value, found '{found_value}'"), + CheckErrorKind::CouldNotDetermineResponseOkType => "attempted to obtain 'ok' value from response, but 'ok' type is indeterminate".into(), + CheckErrorKind::CouldNotDetermineResponseErrType => "attempted to obtain 'err' value from response, but 'err' type is indeterminate".into(), + CheckErrorKind::CouldNotDetermineMatchTypes => "attempted to match on an (optional) or (response) type where either the some, ok, or err type is indeterminate. you may wish to use unwrap-panic or unwrap-err-panic instead.".into(), + CheckErrorKind::CouldNotDetermineType => "type of expression cannot be determined".into(), + CheckErrorKind::BadTupleFieldName => "invalid tuple field name".into(), + CheckErrorKind::ExpectedTuple(type_signature) => format!("expecting tuple, found '{type_signature}'"), + CheckErrorKind::NoSuchTupleField(field_name, tuple_signature) => format!("cannot find field '{field_name}' in tuple '{tuple_signature}'"), + CheckErrorKind::BadTupleConstruction(message) => format!("invalid tuple syntax: {message}"), + CheckErrorKind::NoSuchDataVariable(var_name) => format!("use of unresolved persisted variable '{var_name}'"), + CheckErrorKind::BadTransferSTXArguments => "STX transfer expects an int amount, from principal, to principal".into(), + CheckErrorKind::BadTransferFTArguments => "transfer expects an int amount, from principal, to principal".into(), + CheckErrorKind::BadTransferNFTArguments => "transfer expects an asset, from principal, to principal".into(), + CheckErrorKind::BadMintFTArguments => "mint expects a uint amount and from principal".into(), + CheckErrorKind::BadBurnFTArguments => "burn expects a uint amount and from principal".into(), + CheckErrorKind::BadMapName => "invalid map name".into(), + CheckErrorKind::NoSuchMap(map_name) => format!("use of unresolved map '{map_name}'"), + CheckErrorKind::DefineFunctionBadSignature => "invalid function definition".into(), + CheckErrorKind::BadFunctionName => "invalid function name".into(), + CheckErrorKind::BadMapTypeDefinition => "invalid map definition".into(), + CheckErrorKind::PublicFunctionMustReturnResponse(found_type) => format!("public functions must return an expression of type 'response', found '{found_type}'"), + CheckErrorKind::DefineVariableBadSignature => "invalid variable definition".into(), + CheckErrorKind::ReturnTypesMustMatch(type_1, type_2) => format!("detected two execution paths, returning two different expression types (got '{type_1}' and '{type_2}')"), + CheckErrorKind::NoSuchContract(contract_identifier) => format!("use of unresolved contract '{contract_identifier}'"), + CheckErrorKind::NoSuchPublicFunction(contract_identifier, function_name) => format!("contract '{contract_identifier}' has no public function '{function_name}'"), + CheckErrorKind::PublicFunctionNotReadOnly(contract_identifier, function_name) => format!("function '{contract_identifier}' in '{function_name}' is not read-only"), + CheckErrorKind::ContractAlreadyExists(contract_identifier) => format!("contract name '{contract_identifier}' conflicts with existing contract"), + CheckErrorKind::ContractCallExpectName => "missing contract name for call".into(), + CheckErrorKind::ExpectedCallableType(found_type) => format!("expected a callable contract, found {found_type}"), + CheckErrorKind::NoSuchBlockInfoProperty(property_name) => format!("use of block unknown property '{property_name}'"), + CheckErrorKind::NoSuchBurnBlockInfoProperty(property_name) => format!("use of burn block unknown property '{property_name}'"), + CheckErrorKind::NoSuchStacksBlockInfoProperty(property_name) => format!("use of unknown stacks block property '{property_name}'"), + CheckErrorKind::NoSuchTenureInfoProperty(property_name) => format!("use of unknown tenure property '{property_name}'"), + CheckErrorKind::GetBlockInfoExpectPropertyName => "missing property name for block info introspection".into(), + CheckErrorKind::GetBurnBlockInfoExpectPropertyName => "missing property name for burn block info introspection".into(), + CheckErrorKind::GetStacksBlockInfoExpectPropertyName => "missing property name for stacks block info introspection".into(), + CheckErrorKind::GetTenureInfoExpectPropertyName => "missing property name for tenure info introspection".into(), + CheckErrorKind::NameAlreadyUsed(name) => format!("defining '{name}' conflicts with previous value"), + CheckErrorKind::ReservedWord(name) => format!("{name} is a reserved word"), + CheckErrorKind::NonFunctionApplication => "expecting expression of type function".into(), + CheckErrorKind::ExpectedListApplication => "expecting expression of type list".into(), + CheckErrorKind::ExpectedSequence(found_type) => format!("expecting expression of type 'list', 'buff', 'string-ascii' or 'string-utf8' - found '{found_type}'"), + CheckErrorKind::MaxLengthOverflow => format!("expecting a value <= {}", u32::MAX), + CheckErrorKind::BadLetSyntax => "invalid syntax of 'let'".into(), + CheckErrorKind::CircularReference(references) => format!("detected circular reference: ({})", references.join(", ")), + CheckErrorKind::BadSyntaxBinding(binding_error) => format!("invalid syntax binding: {}", &binding_error.message()), + CheckErrorKind::MaxContextDepthReached => "reached depth limit".into(), + CheckErrorKind::UndefinedVariable(var_name) => format!("use of unresolved variable '{var_name}'"), + CheckErrorKind::UndefinedFunction(var_name) => format!("use of unresolved function '{var_name}'"), + CheckErrorKind::RequiresAtLeastArguments(expected, found) => format!("expecting >= {expected} arguments, got {found}"), + CheckErrorKind::RequiresAtMostArguments(expected, found) => format!("expecting < {expected} arguments, got {found}"), + CheckErrorKind::IncorrectArgumentCount(expected_count, found_count) => format!("expecting {expected_count} arguments, got {found_count}"), + CheckErrorKind::IfArmsMustMatch(type_1, type_2) => format!("expression types returned by the arms of 'if' must match (got '{type_1}' and '{type_2}')"), + CheckErrorKind::MatchArmsMustMatch(type_1, type_2) => format!("expression types returned by the arms of 'match' must match (got '{type_1}' and '{type_2}')"), + CheckErrorKind::DefaultTypesMustMatch(type_1, type_2) => format!("expression types passed in 'default-to' must match (got '{type_1}' and '{type_2}')"), + CheckErrorKind::IllegalOrUnknownFunctionApplication(function_name) => format!("use of illegal / unresolved function '{function_name}"), + CheckErrorKind::UnknownFunction(function_name) => format!("use of unresolved function '{function_name}'"), + CheckErrorKind::TooManyFunctionParameters(found, allowed) => format!("too many function parameters specified: found {found}, the maximum is {allowed}"), + CheckErrorKind::TraitBasedContractCallInReadOnly => "use of trait based contract calls are not allowed in read-only context".into(), + CheckErrorKind::WriteAttemptedInReadOnly => "expecting read-only statements, detected a writing operation".into(), + CheckErrorKind::AtBlockClosureMustBeReadOnly => "(at-block ...) closures expect read-only statements, but detected a writing operation".into(), + CheckErrorKind::BadTokenName => "expecting an token name as an argument".into(), + CheckErrorKind::DefineNFTBadSignature => "(define-asset ...) expects an asset name and an asset identifier type signature as arguments".into(), + CheckErrorKind::NoSuchNFT(asset_name) => format!("tried to use asset function with a undefined asset ('{asset_name}')"), + CheckErrorKind::NoSuchFT(asset_name) => format!("tried to use token function with a undefined token ('{asset_name}')"), + CheckErrorKind::NoSuchTrait(contract_name, trait_name) => format!("use of unresolved trait {contract_name}.{trait_name}"), + CheckErrorKind::TraitReferenceUnknown(trait_name) => format!("use of undeclared trait <{trait_name}>"), + CheckErrorKind::TraitMethodUnknown(trait_name, func_name) => format!("method '{func_name}' unspecified in trait <{trait_name}>"), + CheckErrorKind::BadTraitImplementation(trait_name, func_name) => format!("invalid signature for method '{func_name}' regarding trait's specification <{trait_name}>"), + CheckErrorKind::ExpectedTraitIdentifier => "expecting expression of type trait identifier".into(), + CheckErrorKind::UnexpectedTraitOrFieldReference => "unexpected use of trait reference or field".into(), + CheckErrorKind::DefineTraitBadSignature => "invalid trait definition".into(), + CheckErrorKind::DefineTraitDuplicateMethod(method_name) => format!("duplicate method name '{method_name}' in trait definition"), + CheckErrorKind::TraitReferenceNotAllowed => "trait references can not be stored".into(), + CheckErrorKind::ContractOfExpectsTrait => "trait reference expected".into(), + CheckErrorKind::IncompatibleTrait(expected_trait, actual_trait) => format!("trait '{actual_trait}' is not a compatible with expected trait, '{expected_trait}'"), + CheckErrorKind::TraitTooManyMethods(found, allowed) => format!("too many trait methods specified: found {found}, the maximum is {allowed}"), + CheckErrorKind::InvalidCharactersDetected => "invalid characters detected".into(), + CheckErrorKind::InvalidUTF8Encoding => "invalid UTF8 encoding".into(), + CheckErrorKind::InvalidSecp65k1Signature => "invalid seckp256k1 signature".into(), + CheckErrorKind::TypeAlreadyAnnotatedFailure | CheckErrorKind::CheckerImplementationFailure => { "internal error - please file an issue on https://github.com/stacks-network/stacks-blockchain".into() }, - CheckErrors::UncheckedIntermediaryResponses => "intermediary responses in consecutive statements must be checked".into(), - CheckErrors::CostComputationFailed(s) => format!("contract cost computation failed: {s}"), - CheckErrors::CouldNotDetermineSerializationType => "could not determine the input type for the serialization function".into(), - CheckErrors::ExecutionTimeExpired => "execution time expired".into(), - CheckErrors::ExpectedListOfAllowances(fn_name, arg_num) => format!("{fn_name} expects a list of asset allowances as argument {arg_num}"), - CheckErrors::AllowanceExprNotAllowed => "allowance expressions are only allowed in the context of a `restrict-assets?` or `as-contract?`".into(), - CheckErrors::ExpectedAllowanceExpr(got_name) => format!("expected an allowance expression, got: {got_name}"), - CheckErrors::WithAllAllowanceNotAllowed => "with-all-assets-unsafe is not allowed here, only in the allowance list for `as-contract?`".into(), - CheckErrors::WithAllAllowanceNotAlone => "with-all-assets-unsafe must not be used along with other allowances".into(), - CheckErrors::WithNftExpectedListOfIdentifiers => "with-nft allowance must include a list of asset identifiers".into(), - CheckErrors::MaxIdentifierLengthExceeded(max_len, len) => format!("with-nft allowance identifiers list must not exceed {max_len} elements, got {len}"), - CheckErrors::TooManyAllowances(max_allowed, found) => format!("too many allowances specified, the maximum is {max_allowed}, found {found}"), + CheckErrorKind::UncheckedIntermediaryResponses => "intermediary responses in consecutive statements must be checked".into(), + CheckErrorKind::CostComputationFailed(s) => format!("contract cost computation failed: {s}"), + CheckErrorKind::CouldNotDetermineSerializationType => "could not determine the input type for the serialization function".into(), + CheckErrorKind::ExecutionTimeExpired => "execution time expired".into(), + CheckErrorKind::ExpectedListOfAllowances(fn_name, arg_num) => format!("{fn_name} expects a list of asset allowances as argument {arg_num}"), + CheckErrorKind::AllowanceExprNotAllowed => "allowance expressions are only allowed in the context of a `restrict-assets?` or `as-contract?`".into(), + CheckErrorKind::ExpectedAllowanceExpr(got_name) => format!("expected an allowance expression, got: {got_name}"), + CheckErrorKind::WithAllAllowanceNotAllowed => "with-all-assets-unsafe is not allowed here, only in the allowance list for `as-contract?`".into(), + CheckErrorKind::WithAllAllowanceNotAlone => "with-all-assets-unsafe must not be used along with other allowances".into(), + CheckErrorKind::WithNftExpectedListOfIdentifiers => "with-nft allowance must include a list of asset identifiers".into(), + CheckErrorKind::MaxIdentifierLengthExceeded(max_len, len) => format!("with-nft allowance identifiers list must not exceed {max_len} elements, got {len}"), + CheckErrorKind::TooManyAllowances(max_allowed, found) => format!("too many allowances specified, the maximum is {max_allowed}, found {found}"), } } fn suggestion(&self) -> Option { match &self { - CheckErrors::BadLetSyntax => Some( + CheckErrorKind::BadLetSyntax => Some( "'let' syntax example: (let ((supply 1000) (ttl 60)) )".into(), ), - CheckErrors::TraitReferenceUnknown(_) => Some( + CheckErrorKind::TraitReferenceUnknown(_) => Some( "traits should be either defined, with define-trait, or imported, with use-trait." .into(), ), - CheckErrors::NoSuchBlockInfoProperty(_) => Some( + CheckErrorKind::NoSuchBlockInfoProperty(_) => Some( "properties available: time, header-hash, burnchain-header-hash, vrf-seed".into(), ), _ => None, diff --git a/clarity-types/src/errors/ast.rs b/clarity-types/src/errors/ast.rs index f2b774bd1b7..9edfba4bbdf 100644 --- a/clarity-types/src/errors/ast.rs +++ b/clarity-types/src/errors/ast.rs @@ -23,88 +23,177 @@ use crate::representations::{PreSymbolicExpression, Span}; use crate::token::Token; pub type ParseResult = Result; - +/// Errors encountered during the lexical and syntactic analysis of Clarity source code +/// when constructing the abstract syntax tree (AST). #[derive(Debug, PartialEq)] -pub enum ParseErrors { - // Cost errors +pub enum ParseErrorKind { + // Cost-related errors + /// Arithmetic overflow in cost computation during AST construction, exceeding the maximum threshold. CostOverflow, + /// Cumulative parsing cost exceeds the allocated budget. + /// The first `ExecutionCost` represents the total consumed cost, and the second represents the budget limit. CostBalanceExceeded(ExecutionCost, ExecutionCost), + /// Memory usage during AST construction exceeds the allocated budget. + /// The first `u64` represents the total consumed memory, and the second represents the memory limit. MemoryBalanceExceeded(u64, u64), + /// Failure in cost-tracking due to an unexpected condition or invalid state. + /// The `String` represents the specific reason for the failure. CostComputationFailed(String), + /// Parsing time exceeds the allowed budget, halting AST construction to ensure responsiveness. ExecutionTimeExpired, + // Structural errors + /// Number of expressions exceeds the maximum allowed limit. TooManyExpressions, + /// Nesting depth of expressions exceeds the maximum allowed stack depth. ExpressionStackDepthTooDeep, + /// Nesting depth of expressions exceeds the maximum allowed stack depth. VaryExpressionStackDepthTooDeep, + + // Semantic errors + /// Failed to parse a string into an integer literal. + /// The `String` represents the invalid input string. FailedParsingIntValue(String), + /// Circular reference detected in interdependent function definitions. + /// The `Vec` represents the list of function names forming the cycle. CircularReference(Vec), + /// Variable name is already in use within the same scope. + /// The `String` represents the conflicting variable name. NameAlreadyUsed(String), + /// Attempt to store a trait reference, which is prohibited to ensure type safety. TraitReferenceNotAllowed, + /// Invalid or malformed signature in a `(use-trait ...)` expression. ImportTraitBadSignature, + /// Invalid or malformed signature in a `(define-trait ...)` expression. DefineTraitBadSignature, + /// Invalid or malformed signature in a `(impl-trait ...)` expression. ImplTraitBadSignature, + /// Referenced trait does not exist or cannot be found. + /// The `String` represents the non-existent trait name. TraitReferenceUnknown(String), - // V1 errors + // V1 Errors + /// Failed to capture an expected substring or value during pattern matching in lexical analysis. FailedCapturingInput, + /// Expected a whitespace or closing parenthesis but found an unexpected token or character. + /// The `String` represents the unexpected token or character found. SeparatorExpected(String), + /// Expected a whitespace after a colon but found an unexpected token. + /// The `String` represents the unexpected token found. SeparatorExpectedAfterColon(String), + /// Input program exceeds the maximum allowed number of lines. ProgramTooLarge, + /// Variable name contains invalid characters or violates naming rules. + /// The `String` represents the invalid variable name. IllegalVariableName(String), + /// Failed to parse a string into a buffer literal. + /// The `String` represents the invalid buffer string. FailedParsingBuffer(String), + /// Failed to parse a string into a hexadecimal value. + /// The first `String` represents the invalid input string, and the second represents the error details. FailedParsingHexValue(String, String), + /// Failed to parse a string into a principal literal (e.g., invalid principal format). + /// The `String` represents the invalid principal string. FailedParsingPrincipal(String), + /// Failed to parse a string into a valid field literal. + /// The `String` represents the invalid field string. FailedParsingField(String), + /// Failed to parse the remaining input after processing a construct, leaving invalid tokens. + /// The `String` represents the unparsed remainder of the input. FailedParsingRemainder(String), + /// Unexpected closing parenthesis encountered in the input. ClosingParenthesisUnexpected, + /// Expected a closing parenthesis but found another token or end of input. ClosingParenthesisExpected, + /// Unexpected closing brace for a tuple literal encountered in the input. ClosingTupleLiteralUnexpected, + /// Expected a closing brace for a tuple literal but it was missing. ClosingTupleLiteralExpected, + /// Expected a colon in a tuple literal at the specified position, but it was missing. + /// The `usize` represents the index where the colon was expected. TupleColonExpected(usize), + /// Expected a comma in a tuple literal at the specified position, but it was missing. + /// The `usize` represents the index where the comma was expected. TupleCommaExpected(usize), + /// Expected a tuple item (e.g., key-value pair) at the specified position, but it was missing or invalid. + /// The `usize` represents the index where the item was expected. TupleItemExpected(usize), + /// Unexpected comma separator encountered outside a valid list or tuple context. CommaSeparatorUnexpected, + /// Unexpected colon separator encountered. ColonSeparatorUnexpected, + /// Input contains invalid or disallowed characters. InvalidCharactersDetected, + /// Invalid escape sequence in a string literal (e.g., incorrect use of `\`). InvalidEscaping, // V2 Errors + /// Lexical analysis failed due to an underlying lexer error. + /// The `LexerError` represents the specific lexer error encountered. Lexer(LexerError), + /// Contract name exceeds the maximum allowed length. + /// The `String` represents the overly long contract name. ContractNameTooLong(String), + /// Expected a specific closing token (e.g., parenthesis or brace) but found another token. + /// The `Token` represents the expected closing token. ExpectedClosing(Token), + /// Expected a contract identifier (e.g., `.contract-name`) but found an invalid or missing token. ExpectedContractIdentifier, + /// Expected a trait identifier (e.g., `.trait-name`) but found an invalid or missing token. ExpectedTraitIdentifier, + /// Expected whitespace to separate tokens but found an unexpected token or character. ExpectedWhitespace, + /// Failed to parse a string into an unsigned integer literal. + /// The `String` represents the invalid unsigned integer string. FailedParsingUIntValue(String), + /// Trait name contains invalid characters or violates naming rules. + /// The `String` represents the invalid trait name. IllegalTraitName(String), + /// Invalid principal literal format, preventing parsing into a valid principal. InvalidPrincipalLiteral, + /// Invalid buffer literal format, preventing parsing into a valid buffer. InvalidBuffer, + /// Name (e.g., variable or function) exceeds the maximum allowed length. + /// The `String` represents the overly long name. NameTooLong(String), + /// Encountered an unexpected token during parsing. + /// The `Token` represents the unexpected token found. UnexpectedToken(Token), + /// Expected a colon in a tuple literal (version 2 syntax) but it was missing. TupleColonExpectedv2, + /// Expected a comma in a tuple literal (version 2 syntax) but it was missing. TupleCommaExpectedv2, + /// Expected a value in a tuple literal but it was missing or invalid. TupleValueExpected, + /// Clarity name (e.g., variable, function, or trait) contains invalid characters or violates naming rules. + /// The `String` represents the invalid Clarity name. IllegalClarityName(String), + /// ASCII string literal contains invalid characters or violates format rules. + /// The `String` represents the invalid ASCII string. IllegalASCIIString(String), + /// Contract name contains invalid characters or violates naming rules. + /// The `String` represents the invalid contract name. IllegalContractName(String), + // Notes + /// Indicates a token mismatch for internal parser diagnostics. + /// The `Token` represents the expected token to match. NoteToMatchThis(Token), - /// Should be an unreachable error + /// Unreachable error indicating an unexpected parser failure; should never occur in valid execution. UnexpectedParserFailure, - - /// Should be an unreachable failure which invalidates the transaction + /// Unreachable failure indicating an invalid transaction due to an unexpected interpreter error. InterpreterFailure, } #[derive(Debug, PartialEq)] pub struct ParseError { - pub err: Box, + pub err: Box, pub pre_expressions: Option>, pub diagnostic: Diagnostic, } impl ParseError { - pub fn new(err: ParseErrors) -> ParseError { + pub fn new(err: ParseErrorKind) -> ParseError { let diagnostic = Diagnostic::err(&err); ParseError { err: Box::new(err), @@ -116,9 +205,9 @@ impl ParseError { pub fn rejectable(&self) -> bool { matches!( *self.err, - ParseErrors::InterpreterFailure - | ParseErrors::ExpressionStackDepthTooDeep - | ParseErrors::VaryExpressionStackDepthTooDeep + ParseErrorKind::InterpreterFailure + | ParseErrorKind::ExpressionStackDepthTooDeep + | ParseErrorKind::VaryExpressionStackDepthTooDeep ) } @@ -155,8 +244,8 @@ impl error::Error for ParseError { } } -impl From for ParseError { - fn from(err: ParseErrors) -> Self { +impl From for ParseError { + fn from(err: ParseErrorKind) -> Self { ParseError::new(err) } } @@ -164,143 +253,153 @@ impl From for ParseError { impl From for ParseError { fn from(err: CostErrors) -> Self { match err { - CostErrors::CostOverflow => ParseError::new(ParseErrors::CostOverflow), + CostErrors::CostOverflow => ParseError::new(ParseErrorKind::CostOverflow), CostErrors::CostBalanceExceeded(a, b) => { - ParseError::new(ParseErrors::CostBalanceExceeded(a, b)) + ParseError::new(ParseErrorKind::CostBalanceExceeded(a, b)) } CostErrors::MemoryBalanceExceeded(a, b) => { - ParseError::new(ParseErrors::MemoryBalanceExceeded(a, b)) + ParseError::new(ParseErrorKind::MemoryBalanceExceeded(a, b)) } CostErrors::CostComputationFailed(s) => { - ParseError::new(ParseErrors::CostComputationFailed(s)) + ParseError::new(ParseErrorKind::CostComputationFailed(s)) } CostErrors::CostContractLoadFailure => ParseError::new( - ParseErrors::CostComputationFailed("Failed to load cost contract".into()), + ParseErrorKind::CostComputationFailed("Failed to load cost contract".into()), ), CostErrors::InterpreterFailure | CostErrors::Expect(_) => { - ParseError::new(ParseErrors::InterpreterFailure) + ParseError::new(ParseErrorKind::InterpreterFailure) + } + CostErrors::ExecutionTimeExpired => { + ParseError::new(ParseErrorKind::ExecutionTimeExpired) } - CostErrors::ExecutionTimeExpired => ParseError::new(ParseErrors::ExecutionTimeExpired), } } } -impl DiagnosableError for ParseErrors { +impl DiagnosableError for ParseErrorKind { fn message(&self) -> String { match &self { - ParseErrors::CostOverflow => "Used up cost budget during the parse".into(), - ParseErrors::CostBalanceExceeded(bal, used) => { + ParseErrorKind::CostOverflow => "Used up cost budget during the parse".into(), + ParseErrorKind::CostBalanceExceeded(bal, used) => { format!("Used up cost budget during the parse: {bal} balance, {used} used") } - ParseErrors::MemoryBalanceExceeded(bal, used) => { + ParseErrorKind::MemoryBalanceExceeded(bal, used) => { format!("Used up memory budget during the parse: {bal} balance, {used} used") } - ParseErrors::TooManyExpressions => "Too many expressions".into(), - ParseErrors::FailedCapturingInput => "Failed to capture value from input".into(), - ParseErrors::SeparatorExpected(found) => { + ParseErrorKind::TooManyExpressions => "Too many expressions".into(), + ParseErrorKind::FailedCapturingInput => "Failed to capture value from input".into(), + ParseErrorKind::SeparatorExpected(found) => { format!("Expected whitespace or a close parens. Found: '{found}'") } - ParseErrors::SeparatorExpectedAfterColon(found) => { + ParseErrorKind::SeparatorExpectedAfterColon(found) => { format!("Whitespace expected after colon (:), Found: '{found}'") } - ParseErrors::ProgramTooLarge => "Program too large to parse".into(), - ParseErrors::IllegalContractName(contract_name) => { + ParseErrorKind::ProgramTooLarge => "Program too large to parse".into(), + ParseErrorKind::IllegalContractName(contract_name) => { format!("Illegal contract name: '{contract_name}'") } - ParseErrors::IllegalVariableName(var_name) => { + ParseErrorKind::IllegalVariableName(var_name) => { format!("Illegal variable name: '{var_name}'") } - ParseErrors::FailedParsingIntValue(value) => { + ParseErrorKind::FailedParsingIntValue(value) => { format!("Failed to parse int literal '{value}'") } - ParseErrors::FailedParsingUIntValue(value) => { + ParseErrorKind::FailedParsingUIntValue(value) => { format!("Failed to parse uint literal 'u{value}'") } - ParseErrors::FailedParsingHexValue(value, x) => { + ParseErrorKind::FailedParsingHexValue(value, x) => { format!("Invalid hex-string literal {value}: {x}") } - ParseErrors::FailedParsingPrincipal(value) => { + ParseErrorKind::FailedParsingPrincipal(value) => { format!("Invalid principal literal: {value}") } - ParseErrors::FailedParsingBuffer(value) => format!("Invalid buffer literal: {value}"), - ParseErrors::FailedParsingField(value) => format!("Invalid field literal: {value}"), - ParseErrors::FailedParsingRemainder(remainder) => { + ParseErrorKind::FailedParsingBuffer(value) => { + format!("Invalid buffer literal: {value}") + } + ParseErrorKind::FailedParsingField(value) => format!("Invalid field literal: {value}"), + ParseErrorKind::FailedParsingRemainder(remainder) => { format!("Failed to lex input remainder: '{remainder}'") } - ParseErrors::ClosingParenthesisUnexpected => { + ParseErrorKind::ClosingParenthesisUnexpected => { "Tried to close list which isn't open.".into() } - ParseErrors::ClosingParenthesisExpected => "List expressions (..) left opened.".into(), - ParseErrors::ClosingTupleLiteralUnexpected => { + ParseErrorKind::ClosingParenthesisExpected => { + "List expressions (..) left opened.".into() + } + ParseErrorKind::ClosingTupleLiteralUnexpected => { "Tried to close tuple literal which isn't open.".into() } - ParseErrors::ClosingTupleLiteralExpected => "Tuple literal {{..}} left opened.".into(), - ParseErrors::ColonSeparatorUnexpected => "Misplaced colon.".into(), - ParseErrors::CommaSeparatorUnexpected => "Misplaced comma.".into(), - ParseErrors::TupleColonExpected(i) => { + ParseErrorKind::ClosingTupleLiteralExpected => { + "Tuple literal {{..}} left opened.".into() + } + ParseErrorKind::ColonSeparatorUnexpected => "Misplaced colon.".into(), + ParseErrorKind::CommaSeparatorUnexpected => "Misplaced comma.".into(), + ParseErrorKind::TupleColonExpected(i) => { format!("Tuple literal construction expects a colon at index {i}") } - ParseErrors::TupleCommaExpected(i) => { + ParseErrorKind::TupleCommaExpected(i) => { format!("Tuple literal construction expects a comma at index {i}") } - ParseErrors::TupleItemExpected(i) => { + ParseErrorKind::TupleItemExpected(i) => { format!("Tuple literal construction expects a key or value at index {i}") } - ParseErrors::CircularReference(function_names) => format!( + ParseErrorKind::CircularReference(function_names) => format!( "detected interdependent functions ({})", function_names.join(", ") ), - ParseErrors::NameAlreadyUsed(name) => { + ParseErrorKind::NameAlreadyUsed(name) => { format!("defining '{name}' conflicts with previous value") } - ParseErrors::ImportTraitBadSignature => { + ParseErrorKind::ImportTraitBadSignature => { "(use-trait ...) expects a trait name and a trait identifier".into() } - ParseErrors::DefineTraitBadSignature => { + ParseErrorKind::DefineTraitBadSignature => { "(define-trait ...) expects a trait name and a trait definition".into() } - ParseErrors::ImplTraitBadSignature => { + ParseErrorKind::ImplTraitBadSignature => { "(impl-trait ...) expects a trait identifier".into() } - ParseErrors::TraitReferenceNotAllowed => "trait references can not be stored".into(), - ParseErrors::TraitReferenceUnknown(trait_name) => { + ParseErrorKind::TraitReferenceNotAllowed => "trait references can not be stored".into(), + ParseErrorKind::TraitReferenceUnknown(trait_name) => { format!("use of undeclared trait <{trait_name}>") } - ParseErrors::ExpressionStackDepthTooDeep => format!( + ParseErrorKind::ExpressionStackDepthTooDeep => format!( "AST has too deep of an expression nesting. The maximum stack depth is {MAX_CALL_STACK_DEPTH}" ), - ParseErrors::VaryExpressionStackDepthTooDeep => format!( + ParseErrorKind::VaryExpressionStackDepthTooDeep => format!( "AST has too deep of an expression nesting. The maximum stack depth is {MAX_CALL_STACK_DEPTH}" ), - ParseErrors::InvalidCharactersDetected => "invalid characters detected".into(), - ParseErrors::InvalidEscaping => "invalid escaping detected in string".into(), - ParseErrors::CostComputationFailed(s) => format!("Cost computation failed: {s}"), + ParseErrorKind::InvalidCharactersDetected => "invalid characters detected".into(), + ParseErrorKind::InvalidEscaping => "invalid escaping detected in string".into(), + ParseErrorKind::CostComputationFailed(s) => format!("Cost computation failed: {s}"), // Parser v2 errors - ParseErrors::Lexer(le) => le.message(), - ParseErrors::ContractNameTooLong(name) => { + ParseErrorKind::Lexer(le) => le.message(), + ParseErrorKind::ContractNameTooLong(name) => { format!("contract name '{name}' is too long") } - ParseErrors::ExpectedContractIdentifier => "expected contract identifier".into(), - ParseErrors::ExpectedTraitIdentifier => "expected trait identifier".into(), - ParseErrors::IllegalTraitName(name) => format!("illegal trait name, '{name}'"), - ParseErrors::InvalidPrincipalLiteral => "invalid principal literal".into(), - ParseErrors::InvalidBuffer => "invalid hex-string literal".into(), - ParseErrors::NameTooLong(name) => format!("illegal name (too long), '{name}'"), - ParseErrors::UnexpectedToken(token) => format!("unexpected '{token}'"), - ParseErrors::ExpectedClosing(token) => format!("expected closing '{token}'"), - ParseErrors::TupleColonExpectedv2 => "expected ':' after key in tuple".into(), - ParseErrors::TupleCommaExpectedv2 => { + ParseErrorKind::ExpectedContractIdentifier => "expected contract identifier".into(), + ParseErrorKind::ExpectedTraitIdentifier => "expected trait identifier".into(), + ParseErrorKind::IllegalTraitName(name) => format!("illegal trait name, '{name}'"), + ParseErrorKind::InvalidPrincipalLiteral => "invalid principal literal".into(), + ParseErrorKind::InvalidBuffer => "invalid hex-string literal".into(), + ParseErrorKind::NameTooLong(name) => format!("illegal name (too long), '{name}'"), + ParseErrorKind::UnexpectedToken(token) => format!("unexpected '{token}'"), + ParseErrorKind::ExpectedClosing(token) => format!("expected closing '{token}'"), + ParseErrorKind::TupleColonExpectedv2 => "expected ':' after key in tuple".into(), + ParseErrorKind::TupleCommaExpectedv2 => { "expected ',' separating key-value pairs in tuple".into() } - ParseErrors::TupleValueExpected => "expected value expression for tuple".into(), - ParseErrors::IllegalClarityName(name) => format!("illegal clarity name, '{name}'"), - ParseErrors::IllegalASCIIString(s) => format!("illegal ascii string \"{s}\""), - ParseErrors::ExpectedWhitespace => "expected whitespace before expression".into(), - ParseErrors::NoteToMatchThis(token) => format!("to match this '{token}'"), - ParseErrors::UnexpectedParserFailure => "unexpected failure while parsing".to_string(), - ParseErrors::InterpreterFailure => "unexpected failure while parsing".to_string(), - ParseErrors::ExecutionTimeExpired => "max execution time expired".to_string(), + ParseErrorKind::TupleValueExpected => "expected value expression for tuple".into(), + ParseErrorKind::IllegalClarityName(name) => format!("illegal clarity name, '{name}'"), + ParseErrorKind::IllegalASCIIString(s) => format!("illegal ascii string \"{s}\""), + ParseErrorKind::ExpectedWhitespace => "expected whitespace before expression".into(), + ParseErrorKind::NoteToMatchThis(token) => format!("to match this '{token}'"), + ParseErrorKind::UnexpectedParserFailure => { + "unexpected failure while parsing".to_string() + } + ParseErrorKind::InterpreterFailure => "unexpected failure while parsing".to_string(), + ParseErrorKind::ExecutionTimeExpired => "max execution time expired".to_string(), } } @@ -310,14 +409,14 @@ impl DiagnosableError for ParseErrors { fn level(&self) -> Level { match self { - ParseErrors::NoteToMatchThis(_) => Level::Note, - ParseErrors::Lexer(lexer_error) => lexer_error.level(), + ParseErrorKind::NoteToMatchThis(_) => Level::Note, + ParseErrorKind::Lexer(lexer_error) => lexer_error.level(), _ => Level::Error, } } } pub struct PlacedError { - pub e: ParseErrors, + pub e: ParseErrorKind, pub span: Span, } diff --git a/clarity-types/src/errors/cost.rs b/clarity-types/src/errors/cost.rs index 2678d8ade41..13693d3fffe 100644 --- a/clarity-types/src/errors/cost.rs +++ b/clarity-types/src/errors/cost.rs @@ -16,16 +16,43 @@ use std::fmt; use crate::execution_cost::ExecutionCost; +/// Errors related to cost tracking and resource accounting in the Clarity VM. +/// +/// Each error variant is annotated with "Invalidates Block" status, indicating +/// whether the inclusion of the transaction that caused the error should cause +/// an entire block to be rejected. #[derive(Debug, PartialEq, Eq)] pub enum CostErrors { - CostComputationFailed(String), + /// Arithmetic overflow in cost computation during type-checking, exceeding the maximum threshold. + /// Invalidates Block: true. CostOverflow, + /// Cumulative type-checking cost exceeds the allocated budget, indicating budget depletion. + /// The first `ExecutionCost` represents the total consumed cost, and the second represents the budget limit. + /// Invalidates Block: true. CostBalanceExceeded(ExecutionCost, ExecutionCost), + /// Memory usage during type-checking exceeds the allocated budget. + /// The first `u64` represents the total consumed memory, and the second represents the memory limit. + /// Invalidates Block: + /// - true if happens during contract analysis + /// - false if happens during contract intitialization or contract call. MemoryBalanceExceeded(u64, u64), + /// Failure to access or load cost-related contracts or their state during runtime operations. + /// Invalidates Block: false. CostContractLoadFailure, + /// Failure in cost-tracking due to an unexpected condition or invalid state. + /// The `String` wraps the specific reason for the failure. + /// Invalidates Block: false. + CostComputationFailed(String), + // Time checker errors + /// Type-checking time exceeds the allowed budget, halting analysis to ensure responsiveness. + /// Invalidates Block: true. + ExecutionTimeExpired, + /// Unexpected condition or failure, indicating a bug or invalid state. + /// Invalidates Block: true. InterpreterFailure, + /// Unexpected condition or failure, indicating a bug or invalid state. + /// Invalidates Block: true. Expect(String), - ExecutionTimeExpired, } impl fmt::Display for CostErrors { diff --git a/clarity-types/src/errors/mod.rs b/clarity-types/src/errors/mod.rs index 58b42b8a99d..34f03a549cb 100644 --- a/clarity-types/src/errors/mod.rs +++ b/clarity-types/src/errors/mod.rs @@ -20,8 +20,8 @@ pub mod lexer; use std::{error, fmt}; -pub use analysis::{CheckError, CheckErrors}; -pub use ast::{ParseError, ParseErrors, ParseResult}; +pub use analysis::{CheckErrorKind, StaticCheckError}; +pub use ast::{ParseError, ParseErrorKind, ParseResult}; pub use cost::CostErrors; pub use lexer::LexerError; #[cfg(feature = "rusqlite")] @@ -33,108 +33,204 @@ use crate::types::{FunctionIdentifier, Value}; pub type StackTrace = Vec; +/// Wraps error types that do not implement [`PartialEq`], enabling their +/// use in enums that implement the trait. Any two `IncomparableError` values +/// are always considered unequal. #[derive(Debug)] pub struct IncomparableError { + /// The wrapped error value. pub err: T, } +/// Errors that can occur during the runtime execution of Clarity contracts in the virtual machine. +/// These encompass type-checking failures, interpreter issues, runtime errors, and premature returns. +/// Unlike static analysis errors in `ClarityError::StaticCheck(StaticCheckError)` or `ClarityError::Parse(ParseError)`, +/// which are caught before execution during type-checking or parsing, these errors occur during dynamic +/// evaluation and may involve conditions not detectable statically, such as dynamically constructed expressions +/// (e.g., based on VRF seeds or runtime data). #[derive(Debug)] -pub enum Error { - /// UncheckedErrors are errors that *should* be caught by the - /// TypeChecker and other check passes. Test executions may - /// trigger these errors. - Unchecked(CheckErrors), - Interpreter(InterpreterError), - Runtime(RuntimeErrorType, Option), - ShortReturn(ShortReturnType), +pub enum VmExecutionError { + /// Type-checking errors caught during runtime analysis, which should typically be detected by + /// static type-checking passes before execution. These may occur in test executions or when + /// dynamic expression construction (e.g., using runtime data like VRF seeds) creates structures + /// violating type or resource constraints (e.g., excessive stack depth). + /// The `CheckErrorKind` wraps the specific type-checking error encountered at runtime. + Unchecked(CheckErrorKind), + /// A critical, unrecoverable bug within the VM's internal logic. + /// + /// The presence of this error indicates a violation of one of the VM's + /// invariants or a corrupted state. This is **not** an error in the user's + /// Clarity code, but a bug in the VM's Rust implementation. + /// + /// # Example + /// The VM's evaluation loop attempts to `pop` from an empty internal call stack, + /// indicating a mismatch in function entry/exit logic. + Internal(VmInternalError), + /// Errors that occur during runtime execution of Clarity code, such as arithmetic errors or + /// invalid operations, expected as part of contract evaluation. + /// The `RuntimeError` wraps the specific runtime error, and the `Option` provides + /// an optional stack trace for debugging, if available. + Runtime(RuntimeError, Option), + /// Errors triggered during Clarity contract evaluation that cause early termination with + /// insufficient results (e.g., unwrapping an empty `Option`). + /// The `EarlyReturnError` wraps the specific early return condition, detailing the premature + /// termination cause. + EarlyReturn(EarlyReturnError), } -/// InterpreterErrors are errors that *should never* occur. -/// Test executions may trigger these errors. +/// Represents an internal, unrecoverable error within the Clarity VM. +/// +/// These errors signify a bug in the VM's logic or a violation of its internal +/// invariants. They are not meant to be caught or handled by Clarity contracts. #[derive(Debug, PartialEq)] -pub enum InterpreterError { +pub enum VmInternalError { + /// Raised when the VM encounters an invalid or malformed `SymbolicExpression` + /// e.g., bad variable name or missing argument. + /// The `String` provides a message describing the specific issue. BadSymbolicRepresentation(String), - InterpreterError(String), + /// A generic, unexpected internal error, indicating a logic failure within + /// the VM. + /// The `String` provides a message describing the specific failure. + InvariantViolation(String), // TODO: merge with VmInternalError::Expect + /// The VM failed to produce the final `AssetMap` when finalizing the + /// execution environment for a transaction. FailedToConstructAssetTable, + /// The VM failed to produce the final `EventBatch` when finalizing the + /// execution environment for a transaction. FailedToConstructEventBatch, + /// An error occurred during an interaction with the database. + /// The parameter contains the corresponding SQLite error. #[cfg(feature = "rusqlite")] SqliteError(IncomparableError), + /// The file path provided for the MARF database is invalid because it + /// contains non-UTF-8 characters. BadFileName, + /// The VM failed to create the necessary directory for the MARF persistent + /// storage. Likely due to a file system permissions error or an invalid path FailedToCreateDataDirectory, + /// A failure occurred within the MARF implementation. + /// The `String` provides a message describing the specific failure. MarfFailure(String), + /// Failed to construct a tuple value from provided data because it did not + /// match the expected type signature. FailureConstructingTupleWithType, + /// Failed to construct a list value from provided data because it + /// did not match the expected type signature. FailureConstructingListWithType, + /// An STX transfer failed due to insufficient balance. InsufficientBalance, + /// A generic error occurred during a database operation. + /// The `String` represents a descriptive message detailing the specific issue. DBError(String), + /// An internal expectation or assertion failed. This is used for conditions + /// that are believed to be unreachable but are handled gracefully to prevent + /// a panic. + /// The `String` provides a message describing the failed expectation. Expect(String), } -/// RuntimeErrors are errors that smart contracts are expected -/// to be able to trigger during execution (e.g., arithmetic errors) +/// Runtime errors that Clarity smart contracts are expected to trigger during execution in the virtual +/// machine, such as arithmetic errors, invalid operations, or blockchain-specific issues. These errors +/// are distinct from static analysis errors and occur during dynamic evaluation of contract code. #[derive(Debug, PartialEq)] -pub enum RuntimeErrorType { +pub enum RuntimeError { + /// A generic arithmetic error encountered during contract execution. + /// The `String` represents a descriptive message detailing the specific arithmetic issue. Arithmetic(String), + /// An arithmetic operation exceeded the maximum value for the data type (e.g., `u128`). ArithmeticOverflow, + /// An arithmetic operation resulted in a value below zero for an unsigned type. ArithmeticUnderflow, + /// Attempt to increase token supply beyond the maximum limit. + /// The first u128 represents the attempted new supply (current supply plus increase), + /// and the second represents the maximum allowed supply. SupplyOverflow(u128, u128), + /// Attempt to decrease token supply below zero. + /// The first `u128` represents the current token supply, and the second represents the attempted decrease amount. SupplyUnderflow(u128, u128), + /// Attempt to divide or compute modulo by zero. DivisionByZero, - // error in parsing types - ParseError(String), - // error in parsing the AST + /// Failure to parse types dynamically during contract execution. + /// The `String` represents the specific parsing issue, such as invalid data formats. + TypeParseFailure(String), + /// Failure to parse the abstract syntax tree (AST) during dynamic evaluation. + /// The `Box` wraps the specific parsing error encountered, detailing code interpretation issues. ASTError(Box), + /// The call stack exceeded the virtual machine's maximum depth. MaxStackDepthReached, + /// The execution context depth exceeded the virtual machine's limit. MaxContextDepthReached, + /// Attempt to construct an invalid or unsupported type at runtime (e.g., malformed data structure). BadTypeConstruction, + /// Reference to an invalid or out-of-bounds block height. + /// The `String` represents the string representation of the queried block height that was invalid. BadBlockHeight(String), + /// Attempt to interact with a non-existent token (e.g., in NFT or fungible token operations). NoSuchToken, + /// Feature or function not yet implemented in the virtual machine. NotImplemented, + /// No caller principal available in the current execution context. NoCallerInContext, + /// No sender principal available in the current execution context. NoSenderInContext, + /// Invalid name-value pair in contract data (e.g., map keys). + /// The `&'static str` represents the name of the invalid pair, and the `String` represents the offending value. BadNameValue(&'static str, String), + /// Reference to a non-existent block header hash. + /// The `BlockHeaderHash` represents the unknown block header hash. UnknownBlockHeaderHash(BlockHeaderHash), + /// Invalid block hash provided (e.g., incorrect format or length). + /// The `Vec` represents the invalid block hash data. BadBlockHash(Vec), + /// Failed to unwrap an `Optional` (`none`) or `Response` (`err` or `ok`) Clarity value. UnwrapFailure, - MetadataAlreadySet, - // pox-locking errors + /// Interaction with a deprecated or inactive Proof of Transfer (PoX) contract. DefunctPoxContract, + /// Attempt to lock STX for stacking when already locked in an active PoX cycle. PoxAlreadyLocked, - + /// Block time unavailable during execution. BlockTimeNotAvailable, } #[derive(Debug, PartialEq)] -pub enum ShortReturnType { - ExpectedValue(Box), +/// Errors triggered during Clarity contract evaluation that cause early termination. +/// These errors halt evaluation and fail the transaction. +pub enum EarlyReturnError { + /// Failed to unwrap an `Optional` (`none`) or `Response` (`err` or `ok`) Clarity value. + /// The `Box` holds the original or thrown value. Triggered by `try!`, `unwrap-or`, or + /// `unwrap-err-or`. + UnwrapFailed(Box), + /// An 'asserts!' expression evaluated to false. + /// The `Box` holds the value provided as the second argument to `asserts!`. AssertionFailed(Box), } -pub type InterpreterResult = Result; - impl PartialEq> for IncomparableError { fn eq(&self, _other: &IncomparableError) -> bool { false } } -impl PartialEq for Error { - fn eq(&self, other: &Error) -> bool { +impl PartialEq for VmExecutionError { + fn eq(&self, other: &VmExecutionError) -> bool { match (self, other) { - (Error::Runtime(x, _), Error::Runtime(y, _)) => x == y, - (Error::Unchecked(x), Error::Unchecked(y)) => x == y, - (Error::ShortReturn(x), Error::ShortReturn(y)) => x == y, - (Error::Interpreter(x), Error::Interpreter(y)) => x == y, + (VmExecutionError::Runtime(x, _), VmExecutionError::Runtime(y, _)) => x == y, + (VmExecutionError::Unchecked(x), VmExecutionError::Unchecked(y)) => x == y, + (VmExecutionError::EarlyReturn(x), VmExecutionError::EarlyReturn(y)) => x == y, + (VmExecutionError::Internal(x), VmExecutionError::Internal(y)) => x == y, _ => false, } } } -impl fmt::Display for Error { +impl fmt::Display for VmExecutionError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Error::Runtime(err, stack) => { + VmExecutionError::Runtime(err, stack) => { write!(f, "{err}")?; - if let Some(stack_trace) = stack { + if let Some(stack_trace) = stack + && !stack_trace.is_empty() + { writeln!(f, "\n Stack Trace: ")?; for item in stack_trace.iter() { writeln!(f, "{item}")?; @@ -147,89 +243,89 @@ impl fmt::Display for Error { } } -impl fmt::Display for RuntimeErrorType { +impl fmt::Display for RuntimeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{self:?}") } } -impl error::Error for Error { +impl error::Error for VmExecutionError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { None } } -impl error::Error for RuntimeErrorType { +impl error::Error for RuntimeError { fn source(&self) -> Option<&(dyn error::Error + 'static)> { None } } -impl From for Error { +impl From for VmExecutionError { fn from(err: ParseError) -> Self { match *err.err { - ParseErrors::InterpreterFailure => Error::from(InterpreterError::Expect( + ParseErrorKind::InterpreterFailure => VmExecutionError::from(VmInternalError::Expect( "Unexpected interpreter failure during parsing".into(), )), - _ => Error::from(RuntimeErrorType::ASTError(Box::new(err))), + _ => VmExecutionError::from(RuntimeError::ASTError(Box::new(err))), } } } -impl From for Error { +impl From for VmExecutionError { fn from(err: CostErrors) -> Self { match err { - CostErrors::InterpreterFailure => Error::from(InterpreterError::Expect( + CostErrors::InterpreterFailure => VmExecutionError::from(VmInternalError::Expect( "Interpreter failure during cost calculation".into(), )), - CostErrors::Expect(s) => Error::from(InterpreterError::Expect(format!( + CostErrors::Expect(s) => VmExecutionError::from(VmInternalError::Expect(format!( "Interpreter failure during cost calculation: {s}" ))), - other_err => Error::from(CheckErrors::from(other_err)), + other_err => VmExecutionError::from(CheckErrorKind::from(other_err)), } } } -impl From for Error { - fn from(err: RuntimeErrorType) -> Self { - Error::Runtime(err, None) +impl From for VmExecutionError { + fn from(err: RuntimeError) -> Self { + VmExecutionError::Runtime(err, None) } } -impl From for Error { - fn from(err: CheckErrors) -> Self { - Error::Unchecked(err) +impl From for VmExecutionError { + fn from(err: CheckErrorKind) -> Self { + VmExecutionError::Unchecked(err) } } -impl From<(CheckErrors, &SymbolicExpression)> for Error { - fn from(err: (CheckErrors, &SymbolicExpression)) -> Self { - Error::Unchecked(err.0) +impl From<(CheckErrorKind, &SymbolicExpression)> for VmExecutionError { + fn from(err: (CheckErrorKind, &SymbolicExpression)) -> Self { + VmExecutionError::Unchecked(err.0) } } -impl From for Error { - fn from(err: ShortReturnType) -> Self { - Error::ShortReturn(err) +impl From for VmExecutionError { + fn from(err: EarlyReturnError) -> Self { + VmExecutionError::EarlyReturn(err) } } -impl From for Error { - fn from(err: InterpreterError) -> Self { - Error::Interpreter(err) +impl From for VmExecutionError { + fn from(err: VmInternalError) -> Self { + VmExecutionError::Internal(err) } } #[cfg(any(test, feature = "testing"))] -impl From for () { - fn from(_err: Error) -> Self {} +impl From for () { + fn from(_err: VmExecutionError) -> Self {} } -impl From for Value { - fn from(val: ShortReturnType) -> Self { +impl From for Value { + fn from(val: EarlyReturnError) -> Self { match val { - ShortReturnType::ExpectedValue(v) => *v, - ShortReturnType::AssertionFailed(v) => *v, + EarlyReturnError::UnwrapFailed(v) => *v, + EarlyReturnError::AssertionFailed(v) => *v, } } } @@ -241,16 +337,21 @@ mod test { #[test] fn equality() { assert_eq!( - Error::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool(true)))), - Error::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool(true)))) + VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(Box::new(Value::Bool( + true + )))), + VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(Box::new(Value::Bool( + true + )))) ); assert_eq!( - Error::Interpreter(InterpreterError::InterpreterError("".to_string())), - Error::Interpreter(InterpreterError::InterpreterError("".to_string())) + VmExecutionError::Internal(VmInternalError::InvariantViolation("".to_string())), + VmExecutionError::Internal(VmInternalError::InvariantViolation("".to_string())) ); assert!( - Error::ShortReturn(ShortReturnType::ExpectedValue(Box::new(Value::Bool(true)))) - != Error::Interpreter(InterpreterError::InterpreterError("".to_string())) + VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(Box::new(Value::Bool( + true + )))) != VmExecutionError::Internal(VmInternalError::InvariantViolation("".to_string())) ); } } diff --git a/clarity-types/src/lib.rs b/clarity-types/src/lib.rs index de51f539156..68cc269b47f 100644 --- a/clarity-types/src/lib.rs +++ b/clarity-types/src/lib.rs @@ -31,7 +31,7 @@ pub mod representations; pub mod token; pub mod types; -pub use errors::Error; +pub use errors::VmExecutionError; pub use representations::{ClarityName, ContractName}; pub use types::Value; diff --git a/clarity-types/src/representations.rs b/clarity-types/src/representations.rs index e941e9b7ec0..86275e25a43 100644 --- a/clarity-types/src/representations.rs +++ b/clarity-types/src/representations.rs @@ -23,7 +23,7 @@ use regex::Regex; use stacks_common::codec::{Error as codec_error, StacksMessageCodec, read_next, write_next}; use crate::Value; -use crate::errors::RuntimeErrorType; +use crate::errors::RuntimeError; use crate::types::TraitIdentifier; pub const CONTRACT_MIN_NAME_LENGTH: usize = 1; @@ -66,8 +66,8 @@ guarded_string!( "ClarityName", CLARITY_NAME_REGEX, MAX_STRING_LEN, - RuntimeErrorType, - RuntimeErrorType::BadNameValue + RuntimeError, + RuntimeError::BadNameValue ); guarded_string!( @@ -75,8 +75,8 @@ guarded_string!( "ContractName", CONTRACT_NAME_REGEX, MAX_STRING_LEN, - RuntimeErrorType, - RuntimeErrorType::BadNameValue + RuntimeError, + RuntimeError::BadNameValue ); impl StacksMessageCodec for ClarityName { @@ -623,14 +623,14 @@ impl SymbolicExpression { } /// Encode this SymbolicExpression as a String suitable for logging an error (such as in - /// CheckErrors). The `developer-mode` feature includes the `span`. + /// CheckErrorKind). The `developer-mode` feature includes the `span`. #[cfg(feature = "developer-mode")] pub fn as_error_string(&self) -> String { format!("{} at {:?}", &self.expr, &self.span) } /// Encode this SymbolicExpression as a String suitable for logging an error (such as in - /// CheckErrors). + /// CheckErrorKind). #[cfg(not(feature = "developer-mode"))] pub fn as_error_string(&self) -> String { format!("{}", &self.expr) diff --git a/clarity-types/src/tests/representations.rs b/clarity-types/src/tests/representations.rs index ac395809c7d..0d00f7bc87f 100644 --- a/clarity-types/src/tests/representations.rs +++ b/clarity-types/src/tests/representations.rs @@ -15,7 +15,7 @@ use rstest::rstest; -use crate::errors::RuntimeErrorType; +use crate::errors::RuntimeError; use crate::representations::{ CONTRACT_MAX_NAME_LENGTH, CONTRACT_MIN_NAME_LENGTH, ClarityName, ContractName, MAX_STRING_LEN, }; @@ -73,7 +73,7 @@ fn test_clarity_name_invalid(#[case] name: &str) { assert!(result.is_err()); assert!(matches!( result.unwrap_err(), - RuntimeErrorType::BadNameValue(_, _) + RuntimeError::BadNameValue(_, _) )); } @@ -157,7 +157,7 @@ fn test_contract_name_invalid(#[case] name: &str) { assert!(result.is_err()); assert!(matches!( result.unwrap_err(), - RuntimeErrorType::BadNameValue(_, _) + RuntimeError::BadNameValue(_, _) )); } diff --git a/clarity-types/src/tests/types/mod.rs b/clarity-types/src/tests/types/mod.rs index 8c8d861c7ce..ef0a023a60b 100644 --- a/clarity-types/src/tests/types/mod.rs +++ b/clarity-types/src/tests/types/mod.rs @@ -18,8 +18,8 @@ mod signatures; use rstest::rstest; use stacks_common::types::StacksEpochId; -use crate::Error; -use crate::errors::{CheckErrors, InterpreterError, RuntimeErrorType}; +use crate::VmExecutionError; +use crate::errors::{CheckErrorKind, RuntimeError, VmInternalError}; use crate::types::{ ASCIIData, BuffData, CharType, ListTypeData, MAX_VALUE_SIZE, PrincipalData, QualifiedContractIdentifier, SequenceData, SequencedValue as _, StandardPrincipalData, @@ -34,16 +34,16 @@ fn test_constructors() { vec![Value::Int(5), Value::Int(2)], ListTypeData::new_list(TypeSignature::BoolType, 3).unwrap() ), - Err(InterpreterError::FailureConstructingListWithType.into()) + Err(VmInternalError::FailureConstructingListWithType.into()) ); assert_eq!( ListTypeData::new_list(TypeSignature::IntType, MAX_VALUE_SIZE), - Err(CheckErrors::ValueTooLarge) + Err(CheckErrorKind::ValueTooLarge) ); assert_eq!( Value::buff_from(vec![0; (MAX_VALUE_SIZE + 1) as usize]), - Err(CheckErrors::ValueTooLarge.into()) + Err(CheckErrorKind::ValueTooLarge.into()) ); // Test that wrappers (okay, error, some) @@ -52,17 +52,17 @@ fn test_constructors() { // isn't causing the error). assert_eq!( Value::okay(Value::buff_from(vec![0; (MAX_VALUE_SIZE) as usize]).unwrap()), - Err(CheckErrors::ValueTooLarge.into()) + Err(CheckErrorKind::ValueTooLarge.into()) ); assert_eq!( Value::error(Value::buff_from(vec![0; (MAX_VALUE_SIZE) as usize]).unwrap()), - Err(CheckErrors::ValueTooLarge.into()) + Err(CheckErrorKind::ValueTooLarge.into()) ); assert_eq!( Value::some(Value::buff_from(vec![0; (MAX_VALUE_SIZE) as usize]).unwrap()), - Err(CheckErrors::ValueTooLarge.into()) + Err(CheckErrorKind::ValueTooLarge.into()) ); // Test that the depth limit is correctly enforced: @@ -86,24 +86,24 @@ fn test_constructors() { let inner_value = cons().unwrap(); assert_eq!( TupleData::from_data(vec![("a".into(), inner_value.clone())]), - Err(CheckErrors::TypeSignatureTooDeep.into()) + Err(CheckErrorKind::TypeSignatureTooDeep.into()) ); assert_eq!( Value::list_from(vec![inner_value.clone()]), - Err(CheckErrors::TypeSignatureTooDeep.into()) + Err(CheckErrorKind::TypeSignatureTooDeep.into()) ); assert_eq!( Value::okay(inner_value.clone()), - Err(CheckErrors::TypeSignatureTooDeep.into()) + Err(CheckErrorKind::TypeSignatureTooDeep.into()) ); assert_eq!( Value::error(inner_value.clone()), - Err(CheckErrors::TypeSignatureTooDeep.into()) + Err(CheckErrorKind::TypeSignatureTooDeep.into()) ); assert_eq!( Value::some(inner_value), - Err(CheckErrors::TypeSignatureTooDeep.into()) + Err(CheckErrorKind::TypeSignatureTooDeep.into()) ); if std::env::var("CIRCLE_TESTING") == Ok("1".to_string()) { @@ -115,7 +115,7 @@ fn test_constructors() { if (u32::MAX as usize) < usize::MAX { assert_eq!( Value::buff_from(vec![0; (u32::MAX as usize) + 10]), - Err(CheckErrors::ValueTooLarge.into()) + Err(CheckErrorKind::ValueTooLarge.into()) ); } } @@ -255,7 +255,7 @@ fn test_qualified_contract_identifier_local_returns_runtime_error() { let err = QualifiedContractIdentifier::local("1nvalid-name") .expect_err("Unexpected qualified contract identifier"); assert_eq!( - Error::from(RuntimeErrorType::BadNameValue( + VmExecutionError::from(RuntimeError::BadNameValue( "ContractName", "1nvalid-name".into() )), @@ -264,55 +264,55 @@ fn test_qualified_contract_identifier_local_returns_runtime_error() { } #[rstest] -#[case::too_short("S162RK3CHJPCSSK6BM757FW", RuntimeErrorType::ParseError( +#[case::too_short("S162RK3CHJPCSSK6BM757FW", RuntimeError::TypeParseFailure( "Invalid principal literal: Expected 20 data bytes.".to_string(), ))] -#[case::too_long("S1C5H66S35CSKK6CK1C9HP8SB6CWSK4RB2CDJK8HY4", RuntimeErrorType::ParseError( +#[case::too_long("S1C5H66S35CSKK6CK1C9HP8SB6CWSK4RB2CDJK8HY4", RuntimeError::TypeParseFailure( "Invalid principal literal: Expected 20 data bytes.".to_string(), ))] -#[case::invalid_c32("II2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G", RuntimeErrorType::ParseError( +#[case::invalid_c32("II2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G", RuntimeError::TypeParseFailure( "Invalid principal literal: base58ck checksum 0x1074d4f7 does not match expected 0xae29c6e0".to_string(), ))] fn test_principal_data_parse_standard_principal_returns_runtime_error( #[case] input: &str, - #[case] expected_err: RuntimeErrorType, + #[case] expected_err: RuntimeError, ) { let err = PrincipalData::parse_standard_principal(input).expect_err("Unexpected principal data"); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } #[rstest] -#[case::no_dot("SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0Gcontract-name", RuntimeErrorType::ParseError( +#[case::no_dot("SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0Gcontract-name", RuntimeError::TypeParseFailure( "Invalid principal literal: expected a `.` in a qualified contract name" .to_string(), ))] -#[case::invalid_contract_name("SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G.1nvalid-name", RuntimeErrorType::BadNameValue("ContractName", "1nvalid-name".into()))] +#[case::invalid_contract_name("SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G.1nvalid-name", RuntimeError::BadNameValue("ContractName", "1nvalid-name".into()))] -fn test_qualified_contract_identifier_parse_returns_interpreter_error( +fn test_qualified_contract_identifier_parse_returns_vm_internal_error( #[case] input: &str, - #[case] expected_err: RuntimeErrorType, + #[case] expected_err: RuntimeError, ) { let err = QualifiedContractIdentifier::parse(input) .expect_err("Unexpected qualified contract identifier"); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } #[rstest] -#[case::no_dot("SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-traitnft-trait", RuntimeErrorType::ParseError( +#[case::no_dot("SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-traitnft-trait", RuntimeError::TypeParseFailure( "Invalid principal literal: expected a `.` in a qualified contract name" .to_string(), ))] -#[case::invalid_contract_name("SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.1nvalid-contract.valid-trait", RuntimeErrorType::BadNameValue("ContractName", "1nvalid-contract".into()))] -#[case::invalid_trait_name("SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.valid-contract.1nvalid-trait", RuntimeErrorType::BadNameValue("ClarityName", "1nvalid-trait".into()))] -#[case::invalid_standard_principal("S162RK3CHJPCSSK6BM757FW.valid-contract.valid-trait", RuntimeErrorType::ParseError( +#[case::invalid_contract_name("SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.1nvalid-contract.valid-trait", RuntimeError::BadNameValue("ContractName", "1nvalid-contract".into()))] +#[case::invalid_trait_name("SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.valid-contract.1nvalid-trait", RuntimeError::BadNameValue("ClarityName", "1nvalid-trait".into()))] +#[case::invalid_standard_principal("S162RK3CHJPCSSK6BM757FW.valid-contract.valid-trait", RuntimeError::TypeParseFailure( "Invalid principal literal: Expected 20 data bytes.".to_string(), ))] fn test_trait_identifier_parse_returns_runtime_error( #[case] input: &str, - #[case] expected_err: RuntimeErrorType, + #[case] expected_err: RuntimeError, ) { - let expected_err = Error::from(expected_err); + let expected_err = VmExecutionError::from(expected_err); let err = TraitIdentifier::parse(input).expect_err("Unexpected trait identifier"); assert_eq!(expected_err, err); @@ -323,71 +323,71 @@ fn test_trait_identifier_parse_returns_runtime_error( } #[rstest] -#[case::bad_type_construction(".valid-contract.valid-trait", RuntimeErrorType::BadTypeConstruction)] -#[case::forwards_parse_errors("S162RK3CHJPCSSK6BM757FW.valid-contract.valid-trait", RuntimeErrorType::ParseError( +#[case::bad_type_construction(".valid-contract.valid-trait", RuntimeError::BadTypeConstruction)] +#[case::forwards_parse_errors("S162RK3CHJPCSSK6BM757FW.valid-contract.valid-trait", RuntimeError::TypeParseFailure( "Invalid principal literal: Expected 20 data bytes.".to_string(), ))] fn test_trait_identifier_parse_fully_qualified_returns_runtime_error( #[case] input: &str, - #[case] expected_err: RuntimeErrorType, + #[case] expected_err: RuntimeError, ) { let err = TraitIdentifier::parse_fully_qualified(input).expect_err("Unexpected trait identifier"); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_standard_principal_data_new_returns_interpreter_error_consensus_critical() { +fn test_standard_principal_data_new_returns_vm_internal_error_consensus_critical() { let result = StandardPrincipalData::new(32, [0; 20]); let err = result.expect_err("Unexpected principal data"); assert_eq!( - Error::from(InterpreterError::Expect("Unexpected principal data".into())), + VmExecutionError::from(VmInternalError::Expect("Unexpected principal data".into())), err.into(), ); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_sequence_data_element_at_returns_interpreter_error_consensus_critical() { +fn test_sequence_data_element_at_returns_vm_internal_error_consensus_critical() { let buff = SequenceData::String(CharType::ASCII(ASCIIData { data: vec![1] })); let err = buff.element_at(0).unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(VmInternalError::Expect( "BUG: failed to initialize single-byte ASCII buffer".into() )), err ); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_ascii_data_to_value_returns_interpreter_error_consensus_critical() { +fn test_ascii_data_to_value_returns_vm_internal_error_consensus_critical() { let err = ASCIIData::to_value(&1).unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(VmInternalError::Expect( "ERROR: Invalid ASCII string successfully constructed".into() )), err ); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_utf8_data_to_value_returns_interpreter_error_consensus_critical() { +fn test_utf8_data_to_value_returns_vm_internal_error_consensus_critical() { let err = UTF8Data::to_value(&vec![0xED, 0xA0, 0x80]).unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(VmInternalError::Expect( "ERROR: Invalid UTF8 string successfully constructed".into() )), err ); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_tuple_data_from_data_typed_returns_interpreter_error_consensus_critical() { +fn test_tuple_data_from_data_typed_returns_vm_internal_error_consensus_critical() { let tuple_type = TupleTypeSignature::try_from(vec![("a".into(), TypeSignature::IntType)]).unwrap(); let err = TupleData::from_data_typed( @@ -397,159 +397,159 @@ fn test_tuple_data_from_data_typed_returns_interpreter_error_consensus_critical( ) .unwrap_err(); assert_eq!( - Error::from(InterpreterError::FailureConstructingTupleWithType), + VmExecutionError::from(VmInternalError::FailureConstructingTupleWithType), err ); } #[rstest] -#[case::not_a_string(Value::none(), InterpreterError::Expect("Expected ASCII string".to_string()))] -#[case::invalid_utf8(Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data: vec![0xED, 0xA0, 0x80] }))), InterpreterError::Expect("Non UTF-8 data in string".to_string()))] -fn test_value_expect_ascii_returns_interpreter_error( +#[case::not_a_string(Value::none(), VmInternalError::Expect("Expected ASCII string".to_string()))] +#[case::invalid_utf8(Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data: vec![0xED, 0xA0, 0x80] }))), VmInternalError::Expect("Non UTF-8 data in string".to_string()))] +fn test_value_expect_ascii_returns_vm_internal_error( #[case] value: Value, - #[case] expected_err: InterpreterError, + #[case] expected_err: VmInternalError, ) { let err = value.expect_ascii().unwrap_err(); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_value_expect_u128_returns_interpreter_error_consensus_critical() { +fn test_value_expect_u128_returns_vm_internal_error_consensus_critical() { let err = Value::none().expect_u128().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected u128".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected u128".to_string())), err ); } #[test] -fn test_value_expect_i128_returns_interpreter_error() { +fn test_value_expect_i128_returns_vm_internal_error() { let err = Value::none().expect_i128().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected i128".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected i128".to_string())), err ); } #[rstest] -#[case::not_a_buffer(Value::none(), InterpreterError::Expect("Expected buff".to_string()))] -#[case::too_small(Value::buff_from(vec![1, 2, 3, 4]).unwrap(), InterpreterError::Expect("Unexpected buff length".to_string()))] -fn test_value_expect_buff_returns_interpreter_error( +#[case::not_a_buffer(Value::none(), VmInternalError::Expect("Expected buff".to_string()))] +#[case::too_small(Value::buff_from(vec![1, 2, 3, 4]).unwrap(), VmInternalError::Expect("Unexpected buff length".to_string()))] +fn test_value_expect_buff_returns_vm_internal_error( #[case] value: Value, - #[case] expected_err: InterpreterError, + #[case] expected_err: VmInternalError, ) { let err = value.expect_buff(1).unwrap_err(); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } #[test] -fn test_value_expect_tuple_returns_interpreter_error() { +fn test_value_expect_tuple_returns_vm_internal_error() { let err = Value::none().expect_tuple().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected tuple".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected tuple".to_string())), err ); } #[test] -fn test_value_expect_list_returns_interpreter_error() { +fn test_value_expect_list_returns_vm_internal_error() { let err = Value::none().expect_list().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected list".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected list".to_string())), err ); } #[test] -fn test_value_expect_buff_padded_returns_interpreter_error() { +fn test_value_expect_buff_padded_returns_vm_internal_error() { let err = Value::none().expect_buff_padded(10, 0).unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected buff".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected buff".to_string())), err ); } #[test] -fn test_value_expect_bool_returns_interpreter_error() { +fn test_value_expect_bool_returns_vm_internal_error() { let err = Value::none().expect_bool().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected bool".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected bool".to_string())), err ); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_value_expect_optional_returns_interpreter_error_consensus_critical() { +fn test_value_expect_optional_returns_vm_internal_error_consensus_critical() { let err = Value::okay_true().expect_optional().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected optional".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected optional".to_string())), err ); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_value_expect_principal_returns_interpreter_error_consensus_critical() { +fn test_value_expect_principal_returns_vm_internal_error_consensus_critical() { let err = Value::none().expect_principal().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected principal".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected principal".to_string())), err ); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_value_expect_callable_returns_interpreter_error_consensus_critical() { +fn test_value_expect_callable_returns_vm_internal_error_consensus_critical() { let err = Value::none().expect_callable().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected callable".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected callable".to_string())), err ); } #[test] -fn test_value_expect_result_returns_interpreter_error() { +fn test_value_expect_result_returns_vm_internal_error() { let err = Value::none().expect_result().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect("Expected response".to_string())), + VmExecutionError::from(VmInternalError::Expect("Expected response".to_string())), err ); } #[rstest] -#[case::not_a_response(Value::none(), InterpreterError::Expect("Expected response".to_string()))] -#[case::not_an_ok_response(Value::error(Value::Int(1)).unwrap(), InterpreterError::Expect("Expected ok response".to_string()))] -fn test_value_expect_result_ok_returns_interpreter_error( +#[case::not_a_response(Value::none(), VmInternalError::Expect("Expected response".to_string()))] +#[case::not_an_ok_response(Value::error(Value::Int(1)).unwrap(), VmInternalError::Expect("Expected ok response".to_string()))] +fn test_value_expect_result_ok_returns_vm_internal_error( #[case] value: Value, - #[case] expected_err: InterpreterError, + #[case] expected_err: VmInternalError, ) { let err = value.expect_result_ok().unwrap_err(); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } #[rstest] -#[case::not_a_response(Value::none(), InterpreterError::Expect("Expected response".to_string()))] -#[case::not_an_err_response(Value::okay_true(), InterpreterError::Expect("Expected err response".to_string()))] -fn test_value_expect_result_err_returns_interpreter_error( +#[case::not_a_response(Value::none(), VmInternalError::Expect("Expected response".to_string()))] +#[case::not_an_err_response(Value::okay_true(), VmInternalError::Expect("Expected err response".to_string()))] +fn test_value_expect_result_err_returns_vm_internal_error( #[case] value: Value, - #[case] expected_err: InterpreterError, + #[case] expected_err: VmInternalError, ) { let err = value.expect_result_err().unwrap_err(); - assert_eq!(Error::from(expected_err), err); + assert_eq!(VmExecutionError::from(expected_err), err); } -/// The returned InterpreterError is consensus-critical. +/// The returned VMInternalError is consensus-critical. #[test] -fn test_buff_data_len_returns_interpreter_error_consensus_critical() { +fn test_buff_data_len_returns_vm_internal_error_consensus_critical() { let err = BuffData { data: vec![1; MAX_VALUE_SIZE as usize + 1], } .len() .unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(VmInternalError::Expect( "Data length should be valid".into() )), err @@ -557,14 +557,14 @@ fn test_buff_data_len_returns_interpreter_error_consensus_critical() { } #[test] -fn test_ascii_data_len_returns_interpreter_error() { +fn test_ascii_data_len_returns_vm_internal_error() { let err = ASCIIData { data: vec![1; MAX_VALUE_SIZE as usize + 1], } .len() .unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(VmInternalError::Expect( "Data length should be valid".into() )), err @@ -572,14 +572,14 @@ fn test_ascii_data_len_returns_interpreter_error() { } #[test] -fn test_utf8_data_len_returns_interpreter_error() { +fn test_utf8_data_len_returns_vm_internal_error() { let err = UTF8Data { data: vec![vec![]; MAX_VALUE_SIZE as usize + 1], } .len() .unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(VmInternalError::Expect( "Data length should be valid".into() )), err diff --git a/clarity-types/src/tests/types/serialization.rs b/clarity-types/src/tests/types/serialization.rs index 679befd351c..9878bf148c1 100644 --- a/clarity-types/src/tests/types/serialization.rs +++ b/clarity-types/src/tests/types/serialization.rs @@ -14,8 +14,8 @@ // along with this program. If not, see . use std::io::Write; -use crate::Error; -use crate::errors::{CheckErrors, InterpreterError}; +use crate::VmExecutionError; +use crate::errors::{CheckErrorKind, VmInternalError}; use crate::types::serialization::SerializationError; use crate::types::{ ASCIIData, CharType, MAX_VALUE_SIZE, PrincipalData, QualifiedContractIdentifier, SequenceData, @@ -394,7 +394,7 @@ fn try_deser_large_tuple() { fn try_overflow_stack() { let input = "08080808080808080808070707080807080808080808080708080808080708080707080707080807080808080808080708080808080708080707080708070807080808080808080708080808080708080708080808080808080807070807080808080808070808070707080807070808070808080808070808070708070807080808080808080707080708070807080708080808080808070808080808070808070808080808080808080707080708080808080807080807070708080707080807080808080807080807070807080708080808080808070708070808080808080708080707070808070708080807080807070708"; assert_eq!( - Err(CheckErrors::TypeSignatureTooDeep.into()), + Err(CheckErrorKind::TypeSignatureTooDeep.into()), Value::try_deserialize_hex_untyped(input) ); } @@ -416,30 +416,30 @@ fn test_principals() { test_bad_expectation(standard_p, TypeSignature::BoolType); } -/// The returned InterpreterError is consensus-critical. +/// The returned VmInternalError is consensus-critical. #[test] -fn test_serialize_to_vec_returns_interpreter_error_consensus_critical() { +fn test_serialize_to_vec_returns_vm_internal_error_consensus_critical() { let value = Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data: vec![0; MAX_VALUE_SIZE as usize + 1], }))); let err = value.serialize_to_vec().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(VmInternalError::Expect( "IOError filling byte buffer.".into() )), err.into() ); } -/// The returned InterpreterError is consensus-critical. +/// The returned VmInternalError is consensus-critical. #[test] -fn test_serialize_to_hex_returns_interpreter_error_consensus_critical() { +fn test_serialize_to_hex_returns_vm_internal_error_consensus_critical() { let value = Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data: vec![0; MAX_VALUE_SIZE as usize + 1], }))); let err = value.serialize_to_hex().unwrap_err(); assert_eq!( - Error::from(InterpreterError::Expect( + VmExecutionError::from(VmInternalError::Expect( "IOError filling byte buffer.".into() )), err.into() diff --git a/clarity-types/src/tests/types/signatures.rs b/clarity-types/src/tests/types/signatures.rs index dc516fde613..6fecdd77767 100644 --- a/clarity-types/src/tests/types/signatures.rs +++ b/clarity-types/src/tests/types/signatures.rs @@ -14,7 +14,7 @@ // along with this program. If not, see . use std::collections::HashSet; -use crate::errors::CheckErrors; +use crate::errors::CheckErrorKind; use crate::representations::CONTRACT_MAX_NAME_LENGTH; use crate::types::TypeSignature::{BoolType, IntType, ListUnionType, UIntType}; use crate::types::signatures::{CallableSubtype, TypeSignature}; @@ -43,7 +43,7 @@ fn test_buffer_length_try_from_u32_trait() { assert_eq!(MAX_VALUE_SIZE, buffer.get_value()); let err = BufferLength::try_from(MAX_VALUE_SIZE + 1).unwrap_err(); - assert_eq!(CheckErrors::ValueTooLarge, err); + assert_eq!(CheckErrorKind::ValueTooLarge, err); } #[test] @@ -55,7 +55,7 @@ fn test_buffer_length_try_from_usize_trait() { assert_eq!(MAX_VALUE_SIZE, buffer.get_value()); let err = BufferLength::try_from(MAX_VALUE_SIZE as usize + 1).unwrap_err(); - assert_eq!(CheckErrors::ValueTooLarge, err); + assert_eq!(CheckErrorKind::ValueTooLarge, err); } #[test] @@ -67,10 +67,10 @@ fn test_buffer_length_try_from_i128_trait() { assert_eq!(MAX_VALUE_SIZE, buffer.get_value()); let err = BufferLength::try_from(MAX_VALUE_SIZE as i128 + 1).unwrap_err(); - assert_eq!(CheckErrors::ValueTooLarge, err); + assert_eq!(CheckErrorKind::ValueTooLarge, err); let err = BufferLength::try_from(-1_i128).unwrap_err(); - assert_eq!(CheckErrors::ValueOutOfBounds, err); + assert_eq!(CheckErrorKind::ValueOutOfBounds, err); } #[test] @@ -229,7 +229,7 @@ fn test_string_utf8_length_try_from_u32_trait() { assert_eq!(MAX_UTF8_VALUE_SIZE, string.get_value()); let err = StringUTF8Length::try_from(MAX_UTF8_VALUE_SIZE + 1).unwrap_err(); - assert_eq!(CheckErrors::ValueTooLarge, err); + assert_eq!(CheckErrorKind::ValueTooLarge, err); } #[test] @@ -244,7 +244,7 @@ fn test_string_utf8_length_try_from_usize_trait() { assert_eq!(MAX_UTF8_VALUE_SIZE, string.get_value()); let err = StringUTF8Length::try_from(MAX_UTF8_VALUE_SIZE as usize + 1).unwrap_err(); - assert_eq!(CheckErrors::ValueTooLarge, err); + assert_eq!(CheckErrorKind::ValueTooLarge, err); } #[test] @@ -259,10 +259,10 @@ fn test_string_utf8_length_try_from_i128_trait() { assert_eq!(MAX_UTF8_VALUE_SIZE, string.get_value()); let err = StringUTF8Length::try_from(MAX_UTF8_VALUE_SIZE as i128 + 1).unwrap_err(); - assert_eq!(CheckErrors::ValueTooLarge, err); + assert_eq!(CheckErrorKind::ValueTooLarge, err); let err = StringUTF8Length::try_from(-1_i128).unwrap_err(); - assert_eq!(CheckErrors::ValueOutOfBounds, err); + assert_eq!(CheckErrorKind::ValueOutOfBounds, err); } #[test] @@ -826,11 +826,11 @@ fn test_least_supertype() { for pair in bad_pairs { matches!( TypeSignature::least_supertype_v2_1(&pair.0, &pair.1).unwrap_err(), - CheckErrors::TypeError(..) + CheckErrorKind::TypeError(..) ); matches!( TypeSignature::least_supertype_v2_1(&pair.1, &pair.0).unwrap_err(), - CheckErrors::TypeError(..) + CheckErrorKind::TypeError(..) ); } } diff --git a/clarity-types/src/types/mod.rs b/clarity-types/src/types/mod.rs index 72dad1ae7cb..d6581a3523f 100644 --- a/clarity-types/src/types/mod.rs +++ b/clarity-types/src/types/mod.rs @@ -36,7 +36,7 @@ pub use self::signatures::{ AssetIdentifier, BufferLength, ListTypeData, SequenceSubtype, StringSubtype, StringUTF8Length, TupleTypeSignature, TypeSignature, }; -use crate::errors::{CheckErrors, InterpreterError, InterpreterResult as Result, RuntimeErrorType}; +use crate::errors::{CheckErrorKind, RuntimeError, VmExecutionError, VmInternalError}; use crate::representations::{ClarityName, ContractName, SymbolicExpression}; /// Maximum size in bytes allowed for types. @@ -90,9 +90,9 @@ impl StandardPrincipalData { } impl StandardPrincipalData { - pub fn new(version: u8, bytes: [u8; 20]) -> std::result::Result { + pub fn new(version: u8, bytes: [u8; 20]) -> std::result::Result { if version >= 32 { - return Err(InterpreterError::Expect("Unexpected principal data".into())); + return Err(VmInternalError::Expect("Unexpected principal data".into())); } Ok(Self(version, bytes)) } @@ -174,7 +174,7 @@ impl QualifiedContractIdentifier { Self { issuer, name } } - pub fn local(name: &str) -> Result { + pub fn local(name: &str) -> Result { let name = name.to_string().try_into()?; Ok(Self::new(StandardPrincipalData::transient(), name)) } @@ -193,10 +193,10 @@ impl QualifiedContractIdentifier { self.issuer.1 == [0; 20] } - pub fn parse(literal: &str) -> Result { + pub fn parse(literal: &str) -> Result { let split: Vec<_> = literal.splitn(2, '.').collect(); if split.len() != 2 { - return Err(RuntimeErrorType::ParseError( + return Err(RuntimeError::TypeParseFailure( "Invalid principal literal: expected a `.` in a qualified contract name" .to_string(), ) @@ -282,23 +282,25 @@ impl TraitIdentifier { } } - pub fn parse_fully_qualified(literal: &str) -> Result { + pub fn parse_fully_qualified(literal: &str) -> Result { let (issuer, contract_name, name) = Self::parse(literal)?; - let issuer = issuer.ok_or(RuntimeErrorType::BadTypeConstruction)?; + let issuer = issuer.ok_or(RuntimeError::BadTypeConstruction)?; Ok(TraitIdentifier::new(issuer, contract_name, name)) } - pub fn parse_sugared_syntax(literal: &str) -> Result<(ContractName, ClarityName)> { + pub fn parse_sugared_syntax( + literal: &str, + ) -> Result<(ContractName, ClarityName), VmExecutionError> { let (_, contract_name, name) = Self::parse(literal)?; Ok((contract_name, name)) } pub fn parse( literal: &str, - ) -> Result<(Option, ContractName, ClarityName)> { + ) -> Result<(Option, ContractName, ClarityName), VmExecutionError> { let split: Vec<_> = literal.splitn(3, '.').collect(); if split.len() != 3 { - return Err(RuntimeErrorType::ParseError( + return Err(RuntimeError::TypeParseFailure( "Invalid principal literal: expected a `.` in a qualified contract name" .to_string(), ) @@ -340,7 +342,7 @@ pub enum SequenceData { } impl SequenceData { - pub fn atom_values(&mut self) -> Result> { + pub fn atom_values(&mut self) -> Result, VmExecutionError> { match self { SequenceData::Buffer(data) => data.atom_values(), SequenceData::List(data) => data.atom_values(), @@ -349,7 +351,7 @@ impl SequenceData { } } - pub fn element_size(&self) -> Result { + pub fn element_size(&self) -> Result { let out = match self { SequenceData::Buffer(..) => TypeSignature::BUFFER_MIN.size(), SequenceData::List(data) => data.type_signature.get_list_item_type().size(), @@ -372,7 +374,7 @@ impl SequenceData { self.len() == 0 } - pub fn element_at(self, index: usize) -> Result> { + pub fn element_at(self, index: usize) -> Result, VmExecutionError> { if self.len() <= index { return Ok(None); } @@ -381,7 +383,7 @@ impl SequenceData { SequenceData::List(mut data) => data.data.remove(index), SequenceData::String(CharType::ASCII(data)) => { Value::string_ascii_from_bytes(vec![data.data[index]]).map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "BUG: failed to initialize single-byte ASCII buffer".into(), ) })? @@ -396,7 +398,12 @@ impl SequenceData { Ok(Some(result)) } - pub fn replace_at(self, epoch: &StacksEpochId, index: usize, element: Value) -> Result { + pub fn replace_at( + self, + epoch: &StacksEpochId, + index: usize, + element: Value, + ) -> Result { let seq_length = self.len(); // Check that the length of the provided element is 1. In the case that SequenceData @@ -405,14 +412,14 @@ impl SequenceData { if let Value::Sequence(data) = &element { let elem_length = data.len(); if elem_length != 1 { - return Err(RuntimeErrorType::BadTypeConstruction.into()); + return Err(RuntimeError::BadTypeConstruction.into()); } } else { - return Err(RuntimeErrorType::BadTypeConstruction.into()); + return Err(RuntimeError::BadTypeConstruction.into()); } } if index >= seq_length { - return Err(CheckErrors::ValueOutOfBounds.into()); + return Err(CheckErrorKind::ValueOutOfBounds.into()); } let new_seq_data = match (self, element) { @@ -423,7 +430,7 @@ impl SequenceData { (SequenceData::List(mut data), elem) => { let entry_type = data.type_signature.get_list_item_type(); if !entry_type.admits(epoch, &elem)? { - return Err(CheckErrors::ListTypesMustMatch.into()); + return Err(CheckErrorKind::ListTypesMustMatch.into()); } data.data[index] = elem; SequenceData::List(data) @@ -442,13 +449,13 @@ impl SequenceData { data.data[index] = elem.data.swap_remove(0); SequenceData::String(CharType::UTF8(data)) } - _ => return Err(CheckErrors::ListTypesMustMatch.into()), + _ => return Err(CheckErrorKind::ListTypesMustMatch.into()), }; Value::some(Value::Sequence(new_seq_data)) } - pub fn contains(&self, to_find: Value) -> Result> { + pub fn contains(&self, to_find: Value) -> Result, VmExecutionError> { match self { SequenceData::Buffer(data) => { if let Value::Sequence(SequenceData::Buffer(to_find_vec)) = to_find { @@ -463,7 +470,7 @@ impl SequenceData { Ok(None) } } else { - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_MIN), Box::new(to_find), ) @@ -492,7 +499,7 @@ impl SequenceData { Ok(None) } } else { - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::STRING_ASCII_MIN), Box::new(to_find), ) @@ -513,7 +520,7 @@ impl SequenceData { Ok(None) } } else { - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::STRING_UTF8_MIN), Box::new(to_find), ) @@ -523,9 +530,9 @@ impl SequenceData { } } - pub fn filter(&mut self, filter: &mut F) -> Result<()> + pub fn filter(&mut self, filter: &mut F) -> Result<(), VmExecutionError> where - F: FnMut(SymbolicExpression) -> Result, + F: FnMut(SymbolicExpression) -> Result, { // Note: this macro can probably get removed once // ```Vec::drain_filter(&mut self, filter: F) -> DrainFilter``` @@ -566,7 +573,11 @@ impl SequenceData { Ok(()) } - pub fn concat(&mut self, epoch: &StacksEpochId, other_seq: SequenceData) -> Result<()> { + pub fn concat( + &mut self, + epoch: &StacksEpochId, + other_seq: SequenceData, + ) -> Result<(), VmExecutionError> { match (self, other_seq) { (SequenceData::List(inner_data), SequenceData::List(other_inner_data)) => { inner_data.append(epoch, other_inner_data)?; @@ -582,7 +593,7 @@ impl SequenceData { SequenceData::String(CharType::UTF8(inner_data)), SequenceData::String(CharType::UTF8(ref mut other_inner_data)), ) => inner_data.append(other_inner_data), - _ => return Err(RuntimeErrorType::BadTypeConstruction.into()), + _ => return Err(RuntimeError::BadTypeConstruction.into()), }; Ok(()) } @@ -592,7 +603,7 @@ impl SequenceData { epoch: &StacksEpochId, left_position: usize, right_position: usize, - ) -> Result { + ) -> Result { let empty_seq = left_position == right_position; let result = match self { @@ -700,15 +711,15 @@ impl fmt::Display for UTF8Data { } pub trait SequencedValue { - fn type_signature(&self) -> std::result::Result; + fn type_signature(&self) -> std::result::Result; fn items(&self) -> &Vec; fn drained_items(&mut self) -> Vec; - fn to_value(v: &T) -> Result; + fn to_value(v: &T) -> Result; - fn atom_values(&mut self) -> Result> { + fn atom_values(&mut self) -> Result, VmExecutionError> { self.drained_items() .iter() .map(|item| Ok(SymbolicExpression::atom_value(Self::to_value(item)?))) @@ -725,13 +736,13 @@ impl SequencedValue for ListData { self.data.drain(..).collect() } - fn type_signature(&self) -> std::result::Result { + fn type_signature(&self) -> std::result::Result { Ok(TypeSignature::SequenceType(SequenceSubtype::ListType( self.type_signature.clone(), ))) } - fn to_value(v: &Value) -> Result { + fn to_value(v: &Value) -> Result { Ok(v.clone()) } } @@ -745,16 +756,16 @@ impl SequencedValue for BuffData { self.data.drain(..).collect() } - fn type_signature(&self) -> std::result::Result { + fn type_signature(&self) -> std::result::Result { let buff_length = BufferLength::try_from(self.data.len()).map_err(|_| { - CheckErrors::Expects("ERROR: Too large of a buffer successfully constructed.".into()) + CheckErrorKind::Expects("ERROR: Too large of a buffer successfully constructed.".into()) })?; Ok(TypeSignature::SequenceType(SequenceSubtype::BufferType( buff_length, ))) } - fn to_value(v: &u8) -> Result { + fn to_value(v: &u8) -> Result { Ok(Value::buff_from_byte(*v)) } } @@ -768,18 +779,18 @@ impl SequencedValue for ASCIIData { self.data.drain(..).collect() } - fn type_signature(&self) -> std::result::Result { + fn type_signature(&self) -> std::result::Result { let buff_length = BufferLength::try_from(self.data.len()).map_err(|_| { - CheckErrors::Expects("ERROR: Too large of a buffer successfully constructed.".into()) + CheckErrorKind::Expects("ERROR: Too large of a buffer successfully constructed.".into()) })?; Ok(TypeSignature::SequenceType(SequenceSubtype::StringType( StringSubtype::ASCII(buff_length), ))) } - fn to_value(v: &u8) -> Result { + fn to_value(v: &u8) -> Result { Value::string_ascii_from_bytes(vec![*v]).map_err(|_| { - InterpreterError::Expect("ERROR: Invalid ASCII string successfully constructed".into()) + VmInternalError::Expect("ERROR: Invalid ASCII string successfully constructed".into()) .into() }) } @@ -794,37 +805,37 @@ impl SequencedValue> for UTF8Data { self.data.drain(..).collect() } - fn type_signature(&self) -> std::result::Result { + fn type_signature(&self) -> std::result::Result { let str_len = StringUTF8Length::try_from(self.data.len()).map_err(|_| { - CheckErrors::Expects("ERROR: Too large of a buffer successfully constructed.".into()) + CheckErrorKind::Expects("ERROR: Too large of a buffer successfully constructed.".into()) })?; Ok(TypeSignature::SequenceType(SequenceSubtype::StringType( StringSubtype::UTF8(str_len), ))) } - fn to_value(v: &Vec) -> Result { + fn to_value(v: &Vec) -> Result { Value::string_utf8_from_bytes(v.clone()).map_err(|_| { - InterpreterError::Expect("ERROR: Invalid UTF8 string successfully constructed".into()) + VmInternalError::Expect("ERROR: Invalid UTF8 string successfully constructed".into()) .into() }) } } impl OptionalData { - pub fn type_signature(&self) -> std::result::Result { + pub fn type_signature(&self) -> std::result::Result { let type_result = match self.data { Some(ref v) => TypeSignature::new_option(TypeSignature::type_of(v)?), None => TypeSignature::new_option(TypeSignature::NoType), }; type_result.map_err(|_| { - CheckErrors::Expects("Should not have constructed too large of a type.".into()) + CheckErrorKind::Expects("Should not have constructed too large of a type.".into()) }) } } impl ResponseData { - pub fn type_signature(&self) -> std::result::Result { + pub fn type_signature(&self) -> std::result::Result { let type_result = match self.committed { true => TypeSignature::new_response( TypeSignature::type_of(&self.data)?, @@ -836,7 +847,7 @@ impl ResponseData { ), }; type_result.map_err(|_| { - CheckErrors::Expects("Should not have constructed too large of a type.".into()) + CheckErrorKind::Expects("Should not have constructed too large of a type.".into()) }) } } @@ -856,11 +867,11 @@ impl PartialEq for TupleData { pub const NONE: Value = Value::Optional(OptionalData { data: None }); impl Value { - pub fn some(data: Value) -> Result { + pub fn some(data: Value) -> Result { if data.size()? + WRAPPER_VALUE_SIZE > MAX_VALUE_SIZE { - Err(CheckErrors::ValueTooLarge.into()) + Err(CheckErrorKind::ValueTooLarge.into()) } else if data.depth()? + 1 > MAX_TYPE_DEPTH { - Err(CheckErrors::TypeSignatureTooDeep.into()) + Err(CheckErrorKind::TypeSignatureTooDeep.into()) } else { Ok(Value::Optional(OptionalData { data: Some(Box::new(data)), @@ -893,11 +904,11 @@ impl Value { }) } - pub fn okay(data: Value) -> Result { + pub fn okay(data: Value) -> Result { if data.size()? + WRAPPER_VALUE_SIZE > MAX_VALUE_SIZE { - Err(CheckErrors::ValueTooLarge.into()) + Err(CheckErrorKind::ValueTooLarge.into()) } else if data.depth()? + 1 > MAX_TYPE_DEPTH { - Err(CheckErrors::TypeSignatureTooDeep.into()) + Err(CheckErrorKind::TypeSignatureTooDeep.into()) } else { Ok(Value::Response(ResponseData { committed: true, @@ -906,11 +917,11 @@ impl Value { } } - pub fn error(data: Value) -> Result { + pub fn error(data: Value) -> Result { if data.size()? + WRAPPER_VALUE_SIZE > MAX_VALUE_SIZE { - Err(CheckErrors::ValueTooLarge.into()) + Err(CheckErrorKind::ValueTooLarge.into()) } else if data.depth()? + 1 > MAX_TYPE_DEPTH { - Err(CheckErrors::TypeSignatureTooDeep.into()) + Err(CheckErrorKind::TypeSignatureTooDeep.into()) } else { Ok(Value::Response(ResponseData { committed: false, @@ -919,11 +930,11 @@ impl Value { } } - pub fn size(&self) -> Result { + pub fn size(&self) -> Result { Ok(TypeSignature::type_of(self)?.size()?) } - pub fn depth(&self) -> Result { + pub fn depth(&self) -> Result { Ok(TypeSignature::type_of(self)?.depth()) } @@ -934,12 +945,12 @@ impl Value { epoch: &StacksEpochId, list_data: Vec, expected_type: ListTypeData, - ) -> Result { + ) -> Result { // Constructors for TypeSignature ensure that the size of the Value cannot // be greater than MAX_VALUE_SIZE (they error on such constructions) // so we do not need to perform that check here. if (expected_type.get_max_len() as usize) < list_data.len() { - return Err(InterpreterError::FailureConstructingListWithType.into()); + return Err(VmInternalError::FailureConstructingListWithType.into()); } { @@ -947,7 +958,7 @@ impl Value { for item in &list_data { if !expected_item_type.admits(epoch, item)? { - return Err(InterpreterError::FailureConstructingListWithType.into()); + return Err(VmInternalError::FailureConstructingListWithType.into()); } } } @@ -958,7 +969,7 @@ impl Value { }))) } - pub fn cons_list_unsanitized(list_data: Vec) -> Result { + pub fn cons_list_unsanitized(list_data: Vec) -> Result { let type_sig = TypeSignature::construct_parent_list_type(&list_data)?; Ok(Value::Sequence(SequenceData::List(ListData { data: list_data, @@ -967,11 +978,14 @@ impl Value { } #[cfg(any(test, feature = "testing"))] - pub fn list_from(list_data: Vec) -> Result { + pub fn list_from(list_data: Vec) -> Result { Value::cons_list_unsanitized(list_data) } - pub fn cons_list(list_data: Vec, epoch: &StacksEpochId) -> Result { + pub fn cons_list( + list_data: Vec, + epoch: &StacksEpochId, + ) -> Result { // Constructors for TypeSignature ensure that the size of the Value cannot // be greater than MAX_VALUE_SIZE (they error on such constructions) // Aaron: at this point, we've _already_ allocated memory for this type. @@ -986,7 +1000,7 @@ impl Value { .map(|(value, _did_sanitize)| value) }) .collect(); - let list_data = list_data_opt.ok_or_else(|| CheckErrors::ListTypesMustMatch)?; + let list_data = list_data_opt.ok_or_else(|| CheckErrorKind::ListTypesMustMatch)?; Ok(Value::Sequence(SequenceData::List(ListData { data: list_data, type_signature: type_sig, @@ -994,8 +1008,8 @@ impl Value { } /// # Errors - /// - CheckErrors::ValueTooLarge if `buff_data` is too large. - pub fn buff_from(buff_data: Vec) -> Result { + /// - CheckErrorKind::ValueTooLarge if `buff_data` is too large. + pub fn buff_from(buff_data: Vec) -> Result { // check the buffer size BufferLength::try_from(buff_data.len())?; // construct the buffer @@ -1008,13 +1022,13 @@ impl Value { Value::Sequence(SequenceData::Buffer(BuffData { data: vec![byte] })) } - pub fn string_ascii_from_bytes(bytes: Vec) -> Result { + pub fn string_ascii_from_bytes(bytes: Vec) -> Result { // check the string size BufferLength::try_from(bytes.len())?; for b in bytes.iter() { if !b.is_ascii_alphanumeric() && !b.is_ascii_punctuation() && !b.is_ascii_whitespace() { - return Err(CheckErrors::InvalidCharactersDetected.into()); + return Err(CheckErrorKind::InvalidCharactersDetected.into()); } } // construct the string @@ -1023,9 +1037,11 @@ impl Value { )))) } - pub fn string_utf8_from_string_utf8_literal(tokenized_str: String) -> Result { + pub fn string_utf8_from_string_utf8_literal( + tokenized_str: String, + ) -> Result { let wrapped_codepoints_matcher = Regex::new("^\\\\u\\{(?P[[:xdigit:]]+)\\}") - .map_err(|_| InterpreterError::Expect("Bad regex".into()))?; + .map_err(|_| VmInternalError::Expect("Bad regex".into()))?; let mut window = tokenized_str.as_str(); let mut cursor = 0; let mut data: Vec> = vec![]; @@ -1033,12 +1049,12 @@ impl Value { if let Some(captures) = wrapped_codepoints_matcher.captures(window) { let matched = captures .name("value") - .ok_or_else(|| InterpreterError::Expect("Expected capture".into()))?; + .ok_or_else(|| VmInternalError::Expect("Expected capture".into()))?; let scalar_value = window[matched.start()..matched.end()].to_string(); let unicode_char = { let u = u32::from_str_radix(&scalar_value, 16) - .map_err(|_| CheckErrors::InvalidUTF8Encoding)?; - let c = char::from_u32(u).ok_or_else(|| CheckErrors::InvalidUTF8Encoding)?; + .map_err(|_| CheckErrorKind::InvalidUTF8Encoding)?; + let c = char::from_u32(u).ok_or_else(|| CheckErrorKind::InvalidUTF8Encoding)?; let mut encoded_char: Vec = vec![0; c.len_utf8()]; c.encode_utf8(&mut encoded_char[..]); encoded_char @@ -1062,10 +1078,10 @@ impl Value { )))) } - pub fn string_utf8_from_bytes(bytes: Vec) -> Result { + pub fn string_utf8_from_bytes(bytes: Vec) -> Result { let validated_utf8_str = match str::from_utf8(&bytes) { Ok(string) => string, - _ => return Err(CheckErrors::InvalidCharactersDetected.into()), + _ => return Err(CheckErrorKind::InvalidCharactersDetected.into()), }; let data = validated_utf8_str .chars() @@ -1083,35 +1099,35 @@ impl Value { )))) } - pub fn expect_ascii(self) -> Result { + pub fn expect_ascii(self) -> Result { if let Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data }))) = self { Ok(String::from_utf8(data) - .map_err(|_| InterpreterError::Expect("Non UTF-8 data in string".into()))?) + .map_err(|_| VmInternalError::Expect("Non UTF-8 data in string".into()))?) } else { error!("Value '{self:?}' is not an ASCII string"); - Err(InterpreterError::Expect("Expected ASCII string".into()).into()) + Err(VmInternalError::Expect("Expected ASCII string".into()).into()) } } - pub fn expect_u128(self) -> Result { + pub fn expect_u128(self) -> Result { if let Value::UInt(inner) = self { Ok(inner) } else { error!("Value '{self:?}' is not a u128"); - Err(InterpreterError::Expect("Expected u128".into()).into()) + Err(VmInternalError::Expect("Expected u128".into()).into()) } } - pub fn expect_i128(self) -> Result { + pub fn expect_i128(self) -> Result { if let Value::Int(inner) = self { Ok(inner) } else { error!("Value '{self:?}' is not an i128"); - Err(InterpreterError::Expect("Expected i128".into()).into()) + Err(VmInternalError::Expect("Expected i128".into()).into()) } } - pub fn expect_buff(self, sz: usize) -> Result> { + pub fn expect_buff(self, sz: usize) -> Result, VmExecutionError> { if let Value::Sequence(SequenceData::Buffer(buffdata)) = self { if buffdata.data.len() <= sz { Ok(buffdata.data) @@ -1120,24 +1136,24 @@ impl Value { "Value buffer has len {}, expected {sz}", buffdata.data.len() ); - Err(InterpreterError::Expect("Unexpected buff length".into()).into()) + Err(VmInternalError::Expect("Unexpected buff length".into()).into()) } } else { error!("Value '{self:?}' is not a buff"); - Err(InterpreterError::Expect("Expected buff".into()).into()) + Err(VmInternalError::Expect("Expected buff".into()).into()) } } - pub fn expect_list(self) -> Result> { + pub fn expect_list(self) -> Result, VmExecutionError> { if let Value::Sequence(SequenceData::List(listdata)) = self { Ok(listdata.data) } else { error!("Value '{self:?}' is not a list"); - Err(InterpreterError::Expect("Expected list".into()).into()) + Err(VmInternalError::Expect("Expected list".into()).into()) } } - pub fn expect_buff_padded(self, sz: usize, pad: u8) -> Result> { + pub fn expect_buff_padded(self, sz: usize, pad: u8) -> Result, VmExecutionError> { let mut data = self.expect_buff(sz)?; if sz > data.len() { for _ in data.len()..sz { @@ -1147,25 +1163,25 @@ impl Value { Ok(data) } - pub fn expect_bool(self) -> Result { + pub fn expect_bool(self) -> Result { if let Value::Bool(b) = self { Ok(b) } else { error!("Value '{self:?}' is not a bool"); - Err(InterpreterError::Expect("Expected bool".into()).into()) + Err(VmInternalError::Expect("Expected bool".into()).into()) } } - pub fn expect_tuple(self) -> Result { + pub fn expect_tuple(self) -> Result { if let Value::Tuple(data) = self { Ok(data) } else { error!("Value '{self:?}' is not a tuple"); - Err(InterpreterError::Expect("Expected tuple".into()).into()) + Err(VmInternalError::Expect("Expected tuple".into()).into()) } } - pub fn expect_optional(self) -> Result> { + pub fn expect_optional(self) -> Result, VmExecutionError> { if let Value::Optional(opt) = self { match opt.data { Some(boxed_value) => Ok(Some(*boxed_value)), @@ -1173,29 +1189,29 @@ impl Value { } } else { error!("Value '{self:?}' is not an optional"); - Err(InterpreterError::Expect("Expected optional".into()).into()) + Err(VmInternalError::Expect("Expected optional".into()).into()) } } - pub fn expect_principal(self) -> Result { + pub fn expect_principal(self) -> Result { if let Value::Principal(p) = self { Ok(p) } else { error!("Value '{self:?}' is not a principal"); - Err(InterpreterError::Expect("Expected principal".into()).into()) + Err(VmInternalError::Expect("Expected principal".into()).into()) } } - pub fn expect_callable(self) -> Result { + pub fn expect_callable(self) -> Result { if let Value::CallableContract(t) = self { Ok(t) } else { error!("Value '{self:?}' is not a callable contract"); - Err(InterpreterError::Expect("Expected callable".into()).into()) + Err(VmInternalError::Expect("Expected callable".into()).into()) } } - pub fn expect_result(self) -> Result> { + pub fn expect_result(self) -> Result, VmExecutionError> { if let Value::Response(res_data) = self { if res_data.committed { Ok(Ok(*res_data.data)) @@ -1204,55 +1220,55 @@ impl Value { } } else { error!("Value '{self:?}' is not a response"); - Err(InterpreterError::Expect("Expected response".into()).into()) + Err(VmInternalError::Expect("Expected response".into()).into()) } } - pub fn expect_result_ok(self) -> Result { + pub fn expect_result_ok(self) -> Result { if let Value::Response(res_data) = self { if res_data.committed { Ok(*res_data.data) } else { error!("Value is not a (ok ..)"); - Err(InterpreterError::Expect("Expected ok response".into()).into()) + Err(VmInternalError::Expect("Expected ok response".into()).into()) } } else { error!("Value '{self:?}' is not a response"); - Err(InterpreterError::Expect("Expected response".into()).into()) + Err(VmInternalError::Expect("Expected response".into()).into()) } } - pub fn expect_result_err(self) -> Result { + pub fn expect_result_err(self) -> Result { if let Value::Response(res_data) = self { if !res_data.committed { Ok(*res_data.data) } else { error!("Value is not a (err ..)"); - Err(InterpreterError::Expect("Expected err response".into()).into()) + Err(VmInternalError::Expect("Expected err response".into()).into()) } } else { error!("Value '{self:?}' is not a response"); - Err(InterpreterError::Expect("Expected response".into()).into()) + Err(VmInternalError::Expect("Expected response".into()).into()) } } - pub fn expect_string_ascii(self) -> Result { + pub fn expect_string_ascii(self) -> Result { if let Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data }))) = self { Ok(String::from_utf8(data) - .map_err(|_| InterpreterError::Expect("Non UTF-8 data in string".into()))?) + .map_err(|_| VmInternalError::Expect("Non UTF-8 data in string".into()))?) } else { error!("Value '{self:?}' is not an ASCII string"); - Err(InterpreterError::Expect("Expected ASCII string".into()).into()) + Err(VmInternalError::Expect("Expected ASCII string".into()).into()) } } } impl BuffData { - pub fn len(&self) -> Result { + pub fn len(&self) -> Result { self.data .len() .try_into() - .map_err(|_| InterpreterError::Expect("Data length should be valid".into()).into()) + .map_err(|_| VmInternalError::Expect("Data length should be valid".into()).into()) } pub fn as_slice(&self) -> &[u8] { @@ -1269,25 +1285,29 @@ impl BuffData { } impl ListData { - pub fn len(&self) -> Result { + pub fn len(&self) -> Result { self.data .len() .try_into() - .map_err(|_| InterpreterError::Expect("Data length should be valid".into()).into()) + .map_err(|_| VmInternalError::Expect("Data length should be valid".into()).into()) } pub fn is_empty(&self) -> bool { self.data.is_empty() } - fn append(&mut self, epoch: &StacksEpochId, other_seq: ListData) -> Result<()> { + fn append( + &mut self, + epoch: &StacksEpochId, + other_seq: ListData, + ) -> Result<(), VmExecutionError> { let entry_type_a = self.type_signature.get_list_item_type(); let entry_type_b = other_seq.type_signature.get_list_item_type(); let entry_type = TypeSignature::factor_out_no_type(epoch, entry_type_a, entry_type_b)?; let max_len = self.type_signature.get_max_len() + other_seq.type_signature.get_max_len(); for item in other_seq.data.into_iter() { let (item, _) = Value::sanitize_value(epoch, &entry_type, item) - .ok_or_else(|| CheckErrors::ListTypesMustMatch)?; + .ok_or_else(|| CheckErrorKind::ListTypesMustMatch)?; self.data.push(item); } @@ -1301,11 +1321,11 @@ impl ASCIIData { self.data.append(&mut other_seq.data); } - pub fn len(&self) -> Result { + pub fn len(&self) -> Result { self.data .len() .try_into() - .map_err(|_| InterpreterError::Expect("Data length should be valid".into()).into()) + .map_err(|_| VmInternalError::Expect("Data length should be valid".into()).into()) } } @@ -1314,11 +1334,11 @@ impl UTF8Data { self.data.append(&mut other_seq.data); } - pub fn len(&self) -> Result { + pub fn len(&self) -> Result { self.data .len() .try_into() - .map_err(|_| InterpreterError::Expect("Data length should be valid".into()).into()) + .map_err(|_| VmInternalError::Expect("Data length should be valid".into()).into()) } } @@ -1403,7 +1423,7 @@ impl PrincipalData { self.version() < 32 } - pub fn parse(literal: &str) -> Result { + pub fn parse(literal: &str) -> Result { // be permissive about leading single-quote let literal = literal.strip_prefix('\'').unwrap_or(literal); @@ -1414,16 +1434,21 @@ impl PrincipalData { } } - pub fn parse_qualified_contract_principal(literal: &str) -> Result { + pub fn parse_qualified_contract_principal( + literal: &str, + ) -> Result { let contract_id = QualifiedContractIdentifier::parse(literal)?; Ok(PrincipalData::Contract(contract_id)) } - pub fn parse_standard_principal(literal: &str) -> Result { - let (version, data) = c32::c32_address_decode(literal) - .map_err(|x| RuntimeErrorType::ParseError(format!("Invalid principal literal: {x}")))?; + pub fn parse_standard_principal( + literal: &str, + ) -> Result { + let (version, data) = c32::c32_address_decode(literal).map_err(|x| { + RuntimeError::TypeParseFailure(format!("Invalid principal literal: {x}")) + })?; if data.len() != 20 { - return Err(RuntimeErrorType::ParseError( + return Err(RuntimeError::TypeParseFailure( "Invalid principal literal: Expected 20 data bytes.".to_string(), ) .into()); @@ -1563,7 +1588,7 @@ impl TupleData { // TODO: add tests from mutation testing results #4833 #[cfg_attr(test, mutants::skip)] - pub fn from_data(data: Vec<(ClarityName, Value)>) -> Result { + pub fn from_data(data: Vec<(ClarityName, Value)>) -> Result { let mut type_map = BTreeMap::new(); let mut data_map = BTreeMap::new(); for (name, value) in data.into_iter() { @@ -1571,7 +1596,9 @@ impl TupleData { let entry = type_map.entry(name.clone()); match entry { Entry::Vacant(e) => e.insert(type_info), - Entry::Occupied(_) => return Err(CheckErrors::NameAlreadyUsed(name.into()).into()), + Entry::Occupied(_) => { + return Err(CheckErrorKind::NameAlreadyUsed(name.into()).into()); + } }; data_map.insert(name, value); } @@ -1585,33 +1612,36 @@ impl TupleData { epoch: &StacksEpochId, data: Vec<(ClarityName, Value)>, expected: &TupleTypeSignature, - ) -> Result { + ) -> Result { let mut data_map = BTreeMap::new(); for (name, value) in data.into_iter() { let expected_type = expected .field_type(&name) - .ok_or(InterpreterError::FailureConstructingTupleWithType)?; + .ok_or(VmInternalError::FailureConstructingTupleWithType)?; if !expected_type.admits(epoch, &value)? { - return Err(InterpreterError::FailureConstructingTupleWithType.into()); + return Err(VmInternalError::FailureConstructingTupleWithType.into()); } data_map.insert(name, value); } Ok(Self::new(expected.clone(), data_map)) } - pub fn get(&self, name: &str) -> Result<&Value> { + pub fn get(&self, name: &str) -> Result<&Value, VmExecutionError> { self.data_map.get(name).ok_or_else(|| { - CheckErrors::NoSuchTupleField(name.to_string(), self.type_signature.clone()).into() + CheckErrorKind::NoSuchTupleField(name.to_string(), self.type_signature.clone()).into() }) } - pub fn get_owned(mut self, name: &str) -> Result { + pub fn get_owned(mut self, name: &str) -> Result { self.data_map.remove(name).ok_or_else(|| { - CheckErrors::NoSuchTupleField(name.to_string(), self.type_signature.clone()).into() + CheckErrorKind::NoSuchTupleField(name.to_string(), self.type_signature.clone()).into() }) } - pub fn shallow_merge(mut base: TupleData, updates: TupleData) -> Result { + pub fn shallow_merge( + mut base: TupleData, + updates: TupleData, + ) -> Result { let TupleData { data_map, mut type_signature, diff --git a/clarity-types/src/types/serialization.rs b/clarity-types/src/types/serialization.rs index 2179efd824c..929b2e43136 100644 --- a/clarity-types/src/types/serialization.rs +++ b/clarity-types/src/types/serialization.rs @@ -23,7 +23,7 @@ use stacks_common::util::hash::{hex_bytes, to_hex}; use stacks_common::util::retry::BoundReader; use super::{ListTypeData, TupleTypeSignature}; -use crate::errors::{CheckErrors, IncomparableError, InterpreterError}; +use crate::errors::{CheckErrorKind, IncomparableError, VmInternalError}; use crate::representations::{ClarityName, ContractName, MAX_STRING_LEN}; use crate::types::{ BOUND_VALUE_SERIALIZATION_BYTES, BufferLength, CallableData, CharType, MAX_TYPE_DEPTH, @@ -33,14 +33,14 @@ use crate::types::{ /// Errors that may occur in serialization or deserialization /// If deserialization failed because the described type is a bad type and -/// a CheckError is thrown, it gets wrapped in BadTypeError. +/// a CheckErrorKind is thrown, it gets wrapped in BadTypeError. /// Any IOErrrors from the supplied buffer will manifest as IOError variants, /// except for EOF -- if the deserialization code experiences an EOF, it is caught /// and rethrown as DeserializationError #[derive(Debug, PartialEq)] pub enum SerializationError { IOError(IncomparableError), - BadTypeError(CheckErrors), + BadTypeError(CheckErrorKind), DeserializationError(String), DeserializeExpected(Box), LeftoverBytesInDeserialization, @@ -122,8 +122,8 @@ impl From<&str> for SerializationError { } } -impl From for SerializationError { - fn from(e: CheckErrors) -> Self { +impl From for SerializationError { + fn from(e: CheckErrorKind) -> Self { SerializationError::BadTypeError(e) } } @@ -394,7 +394,7 @@ impl TypeSignature { /// size of a `(buff 1024*1024)` is `1+1024*1024` because of the /// type prefix byte. However, that is 1 byte larger than the maximum /// buffer size in Clarity. - pub fn max_serialized_size(&self) -> Result { + pub fn max_serialized_size(&self) -> Result { let type_prefix_size = 1; let max_output_size = match self { @@ -405,7 +405,7 @@ impl TypeSignature { // `some` or similar with `result` types). So, when // serializing an object with a `NoType`, the other // branch should always be used. - return Err(CheckErrors::CouldNotDetermineSerializationType); + return Err(CheckErrorKind::CouldNotDetermineSerializationType); } TypeSignature::IntType => 16, TypeSignature::UIntType => 16, @@ -417,14 +417,14 @@ impl TypeSignature { .get_max_len() .checked_mul(list_type.get_list_item_type().max_serialized_size()?) .and_then(|x| x.checked_add(list_length_encode)) - .ok_or_else(|| CheckErrors::ValueTooLarge)? + .ok_or_else(|| CheckErrorKind::ValueTooLarge)? } TypeSignature::SequenceType(SequenceSubtype::BufferType(buff_length)) => { // u32 length as big-endian bytes let buff_length_encode = 4; u32::from(buff_length) .checked_add(buff_length_encode) - .ok_or_else(|| CheckErrors::ValueTooLarge)? + .ok_or_else(|| CheckErrorKind::ValueTooLarge)? } TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII( length, @@ -434,7 +434,7 @@ impl TypeSignature { // ascii is 1-byte per character u32::from(length) .checked_add(str_length_encode) - .ok_or_else(|| CheckErrors::ValueTooLarge)? + .ok_or_else(|| CheckErrorKind::ValueTooLarge)? } TypeSignature::SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8( length, @@ -445,7 +445,7 @@ impl TypeSignature { u32::from(length) .checked_mul(4) .and_then(|x| x.checked_add(str_length_encode)) - .ok_or_else(|| CheckErrors::ValueTooLarge)? + .ok_or_else(|| CheckErrorKind::ValueTooLarge)? } TypeSignature::PrincipalType | TypeSignature::CallableType(_) @@ -468,7 +468,7 @@ impl TypeSignature { .checked_add(1) // length of key-name .and_then(|x| x.checked_add(key.len() as u32)) // ClarityName is ascii-only, so 1 byte per length .and_then(|x| x.checked_add(value_size)) - .ok_or_else(|| CheckErrors::ValueTooLarge)?; + .ok_or_else(|| CheckErrorKind::ValueTooLarge)?; } total_size } @@ -477,7 +477,7 @@ impl TypeSignature { Ok(size) => size, // if NoType, then this is just serializing a none // value, which is only the type prefix - Err(CheckErrors::CouldNotDetermineSerializationType) => 0, + Err(CheckErrorKind::CouldNotDetermineSerializationType) => 0, Err(e) => return Err(e), } } @@ -485,17 +485,17 @@ impl TypeSignature { let (ok_type, err_type) = response_types.as_ref(); let (ok_type_max_size, no_ok_type) = match ok_type.max_serialized_size() { Ok(size) => (size, false), - Err(CheckErrors::CouldNotDetermineSerializationType) => (0, true), + Err(CheckErrorKind::CouldNotDetermineSerializationType) => (0, true), Err(e) => return Err(e), }; let err_type_max_size = match err_type.max_serialized_size() { Ok(size) => size, - Err(CheckErrors::CouldNotDetermineSerializationType) => { + Err(CheckErrorKind::CouldNotDetermineSerializationType) => { if no_ok_type { // if both the ok type and the error type are NoType, - // throw a CheckError. This should not be possible, but the check + // throw a CheckErrorKind. This should not be possible, but the check // is done out of caution. - return Err(CheckErrors::CouldNotDetermineSerializationType); + return Err(CheckErrorKind::CouldNotDetermineSerializationType); } else { 0 } @@ -505,13 +505,13 @@ impl TypeSignature { cmp::max(ok_type_max_size, err_type_max_size) } TypeSignature::ListUnionType(_) => { - return Err(CheckErrors::CouldNotDetermineSerializationType); + return Err(CheckErrorKind::CouldNotDetermineSerializationType); } }; max_output_size .checked_add(type_prefix_size) - .ok_or_else(|| CheckErrors::ValueTooLarge) + .ok_or_else(|| CheckErrorKind::ValueTooLarge) } } @@ -583,7 +583,7 @@ impl Value { UNSANITIZED_DEPTH_CHECK }; if stack.len() > depth_check { - return Err(CheckErrors::TypeSignatureTooDeep.into()); + return Err(CheckErrorKind::TypeSignatureTooDeep.into()); } #[allow(clippy::expect_used)] @@ -1215,15 +1215,15 @@ impl Write for WriteCounter { } impl Value { - pub fn serialize_to_vec(&self) -> Result, InterpreterError> { + pub fn serialize_to_vec(&self) -> Result, VmInternalError> { let mut byte_serialization = Vec::new(); self.serialize_write(&mut byte_serialization) - .map_err(|_| InterpreterError::Expect("IOError filling byte buffer.".into()))?; + .map_err(|_| VmInternalError::Expect("IOError filling byte buffer.".into()))?; Ok(byte_serialization) } /// This does *not* perform any data sanitization - pub fn serialize_to_hex(&self) -> Result { + pub fn serialize_to_hex(&self) -> Result { let byte_serialization = self.serialize_to_vec()?; Ok(to_hex(byte_serialization.as_slice())) } diff --git a/clarity-types/src/types/signatures.rs b/clarity-types/src/types/signatures.rs index f0ca3314525..dd68701210a 100644 --- a/clarity-types/src/types/signatures.rs +++ b/clarity-types/src/types/signatures.rs @@ -22,7 +22,7 @@ use std::{cmp, fmt}; use serde::{Deserialize, Serialize}; use stacks_common::types::StacksEpochId; -use crate::errors::CheckErrors; +use crate::errors::CheckErrorKind; use crate::representations::{CONTRACT_MAX_NAME_LENGTH, ClarityName, ContractName}; use crate::types::{ CharType, MAX_TO_ASCII_BUFFER_LEN, MAX_TO_ASCII_RESULT_LEN, MAX_TYPE_DEPTH, @@ -121,11 +121,11 @@ impl BufferLength { /// /// This function is primarily intended for internal runtime use, /// and serves as the central place for all integer validation logic. - fn try_from_i128(data: i128) -> Result { + fn try_from_i128(data: i128) -> Result { if data > (MAX_VALUE_SIZE as i128) { - Err(CheckErrors::ValueTooLarge) + Err(CheckErrorKind::ValueTooLarge) } else if data < 0 { - Err(CheckErrors::ValueOutOfBounds) + Err(CheckErrorKind::ValueOutOfBounds) } else { Ok(BufferLength(data as u32)) } @@ -161,22 +161,22 @@ impl From for u32 { } impl TryFrom for BufferLength { - type Error = CheckErrors; - fn try_from(data: u32) -> Result { + type Error = CheckErrorKind; + fn try_from(data: u32) -> Result { Self::try_from(data as i128) } } impl TryFrom for BufferLength { - type Error = CheckErrors; - fn try_from(data: usize) -> Result { + type Error = CheckErrorKind; + fn try_from(data: usize) -> Result { Self::try_from(data as i128) } } impl TryFrom for BufferLength { - type Error = CheckErrors; - fn try_from(data: i128) -> Result { + type Error = CheckErrorKind; + fn try_from(data: i128) -> Result { Self::try_from_i128(data) } } @@ -202,11 +202,11 @@ impl StringUTF8Length { /// /// This function is primarily intended for internal runtime use, /// and serves as the central place for all integer validation logic. - fn try_from_i128(value: i128) -> Result { + fn try_from_i128(value: i128) -> Result { if value > MAX_UTF8_VALUE_SIZE as i128 { - Err(CheckErrors::ValueTooLarge) + Err(CheckErrorKind::ValueTooLarge) } else if value < 0 { - Err(CheckErrors::ValueOutOfBounds) + Err(CheckErrorKind::ValueOutOfBounds) } else { Ok(StringUTF8Length(value as u32)) } @@ -242,22 +242,22 @@ impl From for u32 { } impl TryFrom for StringUTF8Length { - type Error = CheckErrors; - fn try_from(data: u32) -> Result { + type Error = CheckErrorKind; + fn try_from(data: u32) -> Result { Self::try_from(data as i128) } } impl TryFrom for StringUTF8Length { - type Error = CheckErrors; - fn try_from(data: usize) -> Result { + type Error = CheckErrorKind; + fn try_from(data: usize) -> Result { Self::try_from(data as i128) } } impl TryFrom for StringUTF8Length { - type Error = CheckErrors; - fn try_from(data: i128) -> Result { + type Error = CheckErrorKind; + fn try_from(data: i128) -> Result { Self::try_from_i128(data) } } @@ -355,10 +355,13 @@ impl From for TypeSignature { } impl ListTypeData { - pub fn new_list(entry_type: TypeSignature, max_len: u32) -> Result { + pub fn new_list( + entry_type: TypeSignature, + max_len: u32, + ) -> Result { let would_be_depth = 1 + entry_type.depth(); if would_be_depth > MAX_TYPE_DEPTH { - return Err(CheckErrors::TypeSignatureTooDeep); + return Err(CheckErrorKind::TypeSignatureTooDeep); } let list_data = ListTypeData { @@ -367,9 +370,9 @@ impl ListTypeData { }; let would_be_size = list_data .inner_size()? - .ok_or_else(|| CheckErrors::ValueTooLarge)?; + .ok_or_else(|| CheckErrorKind::ValueTooLarge)?; if would_be_size > MAX_VALUE_SIZE { - Err(CheckErrors::ValueTooLarge) + Err(CheckErrorKind::ValueTooLarge) } else { Ok(list_data) } @@ -397,13 +400,13 @@ impl ListTypeData { } impl TypeSignature { - pub fn new_option(inner_type: TypeSignature) -> Result { + pub fn new_option(inner_type: TypeSignature) -> Result { let new_size = WRAPPER_VALUE_SIZE + inner_type.size()?; let new_depth = 1 + inner_type.depth(); if new_size > MAX_VALUE_SIZE { - Err(CheckErrors::ValueTooLarge) + Err(CheckErrorKind::ValueTooLarge) } else if new_depth > MAX_TYPE_DEPTH { - Err(CheckErrors::TypeSignatureTooDeep) + Err(CheckErrorKind::TypeSignatureTooDeep) } else { Ok(OptionalType(Box::new(inner_type))) } @@ -412,14 +415,14 @@ impl TypeSignature { pub fn new_response( ok_type: TypeSignature, err_type: TypeSignature, - ) -> Result { + ) -> Result { let new_size = WRAPPER_VALUE_SIZE + cmp::max(ok_type.size()?, err_type.size()?); let new_depth = 1 + cmp::max(ok_type.depth(), err_type.depth()); if new_size > MAX_VALUE_SIZE { - Err(CheckErrors::ValueTooLarge) + Err(CheckErrorKind::ValueTooLarge) } else if new_depth > MAX_TYPE_DEPTH { - Err(CheckErrors::TypeSignatureTooDeep) + Err(CheckErrorKind::TypeSignatureTooDeep) } else { Ok(ResponseType(Box::new((ok_type, err_type)))) } @@ -433,7 +436,7 @@ impl TypeSignature { &TypeSignature::NoType == self } - pub fn admits(&self, epoch: &StacksEpochId, x: &Value) -> Result { + pub fn admits(&self, epoch: &StacksEpochId, x: &Value) -> Result { let x_type = TypeSignature::type_of(x)?; self.admits_type(epoch, &x_type) } @@ -442,7 +445,7 @@ impl TypeSignature { &self, epoch: &StacksEpochId, other: &TypeSignature, - ) -> Result { + ) -> Result { match epoch { StacksEpochId::Epoch20 | StacksEpochId::Epoch2_05 => self.admits_type_v2_0(other), StacksEpochId::Epoch21 @@ -454,11 +457,13 @@ impl TypeSignature { | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 | StacksEpochId::Epoch33 => self.admits_type_v2_1(other), - StacksEpochId::Epoch10 => Err(CheckErrors::Expects("epoch 1.0 not supported".into())), + StacksEpochId::Epoch10 => { + Err(CheckErrorKind::Expects("epoch 1.0 not supported".into())) + } } } - pub fn admits_type_v2_0(&self, other: &TypeSignature) -> Result { + pub fn admits_type_v2_0(&self, other: &TypeSignature) -> Result { match self { SequenceType(SequenceSubtype::ListType(my_list_type)) => { if let SequenceType(SequenceSubtype::ListType(other_list_type)) = other { @@ -540,18 +545,18 @@ impl TypeSignature { Ok(false) } } - NoType => Err(CheckErrors::CouldNotDetermineType), - CallableType(_) => Err(CheckErrors::Expects( + NoType => Err(CheckErrorKind::CouldNotDetermineType), + CallableType(_) => Err(CheckErrorKind::Expects( "CallableType should not be used in epoch v2.0".into(), )), - ListUnionType(_) => Err(CheckErrors::Expects( + ListUnionType(_) => Err(CheckErrorKind::Expects( "ListUnionType should not be used in epoch v2.0".into(), )), _ => Ok(other == self), } } - fn admits_type_v2_1(&self, other: &TypeSignature) -> Result { + fn admits_type_v2_1(&self, other: &TypeSignature) -> Result { let other = match other.concretize() { Ok(other) => other, Err(_) => { @@ -640,7 +645,7 @@ impl TypeSignature { Ok(false) } } - NoType => Err(CheckErrors::CouldNotDetermineType), + NoType => Err(CheckErrorKind::CouldNotDetermineType), _ => Ok(&other == self), } } @@ -697,7 +702,7 @@ impl TypeSignature { /// Concretize the type. The input to this method may include /// `ListUnionType` and the `CallableType` variant for a `principal. /// This method turns these "temporary" types into actual types. - pub fn concretize(&self) -> Result { + pub fn concretize(&self) -> Result { match self { ListUnionType(types) => { let mut is_trait = None; @@ -706,7 +711,7 @@ impl TypeSignature { match partial { CallableSubtype::Principal(_) => { if is_trait.is_some() { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(TypeSignature::CallableType(partial.clone())), Box::new(TypeSignature::PrincipalType), )); @@ -716,7 +721,7 @@ impl TypeSignature { } CallableSubtype::Trait(t) => { if is_principal { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::CallableType(partial.clone())), )); @@ -739,12 +744,12 @@ impl TypeSignature { } impl TryFrom> for TupleTypeSignature { - type Error = CheckErrors; + type Error = CheckErrorKind; fn try_from( type_data: Vec<(ClarityName, TypeSignature)>, - ) -> Result { + ) -> Result { if type_data.is_empty() { - return Err(CheckErrors::EmptyTuplesNotAllowed); + return Err(CheckErrorKind::EmptyTuplesNotAllowed); } let mut type_map = BTreeMap::new(); @@ -752,7 +757,7 @@ impl TryFrom> for TupleTypeSignature { if let Entry::Vacant(e) = type_map.entry(name.clone()) { e.insert(type_info); } else { - return Err(CheckErrors::NameAlreadyUsed(name.into())); + return Err(CheckErrorKind::NameAlreadyUsed(name.into())); } } TupleTypeSignature::try_from(type_map) @@ -760,25 +765,25 @@ impl TryFrom> for TupleTypeSignature { } impl TryFrom> for TupleTypeSignature { - type Error = CheckErrors; + type Error = CheckErrorKind; fn try_from( type_map: BTreeMap, - ) -> Result { + ) -> Result { if type_map.is_empty() { - return Err(CheckErrors::EmptyTuplesNotAllowed); + return Err(CheckErrorKind::EmptyTuplesNotAllowed); } for child_sig in type_map.values() { if (1 + child_sig.depth()) > MAX_TYPE_DEPTH { - return Err(CheckErrors::TypeSignatureTooDeep); + return Err(CheckErrorKind::TypeSignatureTooDeep); } } let type_map = Arc::new(type_map.into_iter().collect()); let result = TupleTypeSignature { type_map }; let would_be_size = result .inner_size()? - .ok_or_else(|| CheckErrors::ValueTooLarge)?; + .ok_or_else(|| CheckErrorKind::ValueTooLarge)?; if would_be_size > MAX_VALUE_SIZE { - Err(CheckErrors::ValueTooLarge) + Err(CheckErrorKind::ValueTooLarge) } else { Ok(result) } @@ -808,7 +813,7 @@ impl TupleTypeSignature { &self, epoch: &StacksEpochId, other: &TupleTypeSignature, - ) -> Result { + ) -> Result { if self.type_map.len() != other.type_map.len() { return Ok(false); } @@ -929,7 +934,7 @@ impl TypeSignature { /// Creates a string ASCII type with the specified length. /// Returns an error if the provided length is invalid. - pub fn new_ascii_type(len: i128) -> Result { + pub fn new_ascii_type(len: i128) -> Result { Ok(SequenceType(SequenceSubtype::StringType( StringSubtype::ASCII(BufferLength::try_from_i128(len)?), ))) @@ -940,7 +945,7 @@ impl TypeSignature { epoch: &StacksEpochId, a: &TypeSignature, b: &TypeSignature, - ) -> Result { + ) -> Result { if a.is_no_type() { Ok(b.clone()) } else if b.is_no_type() { @@ -991,7 +996,7 @@ impl TypeSignature { epoch: &StacksEpochId, a: &TypeSignature, b: &TypeSignature, - ) -> Result { + ) -> Result { match epoch { StacksEpochId::Epoch20 | StacksEpochId::Epoch2_05 => Self::least_supertype_v2_0(a, b), StacksEpochId::Epoch21 @@ -1003,14 +1008,16 @@ impl TypeSignature { | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 | StacksEpochId::Epoch33 => Self::least_supertype_v2_1(a, b), - StacksEpochId::Epoch10 => Err(CheckErrors::Expects("epoch 1.0 not supported".into())), + StacksEpochId::Epoch10 => { + Err(CheckErrorKind::Expects("epoch 1.0 not supported".into())) + } } } pub fn least_supertype_v2_0( a: &TypeSignature, b: &TypeSignature, - ) -> Result { + ) -> Result { match (a, b) { ( TupleType(TupleTypeSignature { type_map: types_a }), @@ -1018,7 +1025,7 @@ impl TypeSignature { ) => { let mut type_map_out = BTreeMap::new(); for (name, entry_a) in types_a.iter() { - let entry_b = types_b.get(name).ok_or(CheckErrors::TypeError( + let entry_b = types_b.get(name).ok_or(CheckErrorKind::TypeError( Box::new(a.clone()), Box::new(b.clone()), ))?; @@ -1027,7 +1034,7 @@ impl TypeSignature { } Ok(TupleTypeSignature::try_from(type_map_out) .map(|x| x.into()) - .map_err(|_| CheckErrors::SupertypeTooLarge)?) + .map_err(|_| CheckErrorKind::SupertypeTooLarge)?) } ( SequenceType(SequenceSubtype::ListType(ListTypeData { @@ -1048,7 +1055,7 @@ impl TypeSignature { }; let max_len = cmp::max(len_a, len_b); Ok(Self::list_of(entry_type, *max_len) - .map_err(|_| CheckErrors::SupertypeTooLarge)?) + .map_err(|_| CheckErrorKind::SupertypeTooLarge)?) } (ResponseType(resp_a), ResponseType(resp_b)) => { let ok_type = @@ -1107,7 +1114,7 @@ impl TypeSignature { if x == y { Ok(x.clone()) } else { - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(a.clone()), Box::new(b.clone()), )) @@ -1119,7 +1126,7 @@ impl TypeSignature { pub fn least_supertype_v2_1( a: &TypeSignature, b: &TypeSignature, - ) -> Result { + ) -> Result { match (a, b) { ( TupleType(TupleTypeSignature { type_map: types_a }), @@ -1127,7 +1134,7 @@ impl TypeSignature { ) => { let mut type_map_out = BTreeMap::new(); for (name, entry_a) in types_a.iter() { - let entry_b = types_b.get(name).ok_or(CheckErrors::TypeError( + let entry_b = types_b.get(name).ok_or(CheckErrorKind::TypeError( Box::new(a.clone()), Box::new(b.clone()), ))?; @@ -1136,7 +1143,7 @@ impl TypeSignature { } Ok(TupleTypeSignature::try_from(type_map_out) .map(|x| x.into()) - .map_err(|_| CheckErrors::SupertypeTooLarge)?) + .map_err(|_| CheckErrorKind::SupertypeTooLarge)?) } ( SequenceType(SequenceSubtype::ListType(ListTypeData { @@ -1157,7 +1164,7 @@ impl TypeSignature { }; let max_len = cmp::max(len_a, len_b); Ok(Self::list_of(entry_type, *max_len) - .map_err(|_| CheckErrors::SupertypeTooLarge)?) + .map_err(|_| CheckErrorKind::SupertypeTooLarge)?) } (ResponseType(resp_a), ResponseType(resp_b)) => { let ok_type = @@ -1238,7 +1245,7 @@ impl TypeSignature { if all_principals { Ok(PrincipalType) } else { - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(a.clone()), Box::new(b.clone()), )) @@ -1251,7 +1258,7 @@ impl TypeSignature { if x == y { Ok(x.clone()) } else { - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(a.clone()), Box::new(b.clone()), )) @@ -1260,7 +1267,10 @@ impl TypeSignature { } } - pub fn list_of(item_type: TypeSignature, max_len: u32) -> Result { + pub fn list_of( + item_type: TypeSignature, + max_len: u32, + ) -> Result { ListTypeData::new_list(item_type, max_len).map(|x| x.into()) } @@ -1271,7 +1281,7 @@ impl TypeSignature { } } - pub fn type_of(x: &Value) -> Result { + pub fn type_of(x: &Value) -> Result { let out = match x { Value::Principal(_) => PrincipalType, Value::Int(_v) => IntType, @@ -1300,7 +1310,7 @@ impl TypeSignature { Ok(out) } - pub fn literal_type_of(x: &Value) -> Result { + pub fn literal_type_of(x: &Value) -> Result { match x { Value::Principal(PrincipalData::Contract(contract_id)) => Ok(CallableType( CallableSubtype::Principal(contract_id.clone()), @@ -1310,19 +1320,19 @@ impl TypeSignature { } // Checks if resulting type signature is of valid size. - pub fn construct_parent_list_type(args: &[Value]) -> Result { - let children_types: Result, CheckErrors> = + pub fn construct_parent_list_type(args: &[Value]) -> Result { + let children_types: Result, CheckErrorKind> = args.iter().map(TypeSignature::type_of).collect(); TypeSignature::parent_list_type(&children_types?) } - pub fn parent_list_type(children: &[TypeSignature]) -> Result { + pub fn parent_list_type(children: &[TypeSignature]) -> Result { if let Some((first, rest)) = children.split_first() { let mut current_entry_type = first.clone(); for next_entry in rest.iter() { current_entry_type = Self::least_supertype_v2_1(¤t_entry_type, next_entry)?; } - let len = u32::try_from(children.len()).map_err(|_| CheckErrors::ValueTooLarge)?; + let len = u32::try_from(children.len()).map_err(|_| CheckErrorKind::ValueTooLarge)?; ListTypeData::new_list(current_entry_type, len) } else { Ok(TypeSignature::empty_list()) @@ -1362,16 +1372,16 @@ impl TypeSignature { } } - pub fn size(&self) -> Result { + pub fn size(&self) -> Result { self.inner_size()?.ok_or_else(|| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: .size() overflowed on too large of a type. construction should have failed!" .into(), ) }) } - fn inner_size(&self) -> Result, CheckErrors> { + fn inner_size(&self) -> Result, CheckErrorKind> { let out = match self { // NoType's may be asked for their size at runtime -- // legal constructions like `(ok 1)` have NoType parts (if they have unknown error variant types). @@ -1404,9 +1414,9 @@ impl TypeSignature { Ok(out) } - pub fn type_size(&self) -> Result { + pub fn type_size(&self) -> Result { self.inner_type_size() - .ok_or_else(|| CheckErrors::ValueTooLarge) + .ok_or_else(|| CheckErrorKind::ValueTooLarge) } /// Returns the size of the _type signature_ @@ -1436,7 +1446,7 @@ impl TypeSignature { impl ListTypeData { /// List Size: type_signature_size + max_len * entry_type.size() - fn inner_size(&self) -> Result, CheckErrors> { + fn inner_size(&self) -> Result, CheckErrorKind> { let total_size = self .entry_type .size()? @@ -1485,9 +1495,10 @@ impl TupleTypeSignature { } } - pub fn size(&self) -> Result { - self.inner_size()? - .ok_or_else(|| CheckErrors::Expects("size() overflowed on a constructed type.".into())) + pub fn size(&self) -> Result { + self.inner_size()?.ok_or_else(|| { + CheckErrorKind::Expects("size() overflowed on a constructed type.".into()) + }) } fn max_depth(&self) -> u8 { @@ -1501,7 +1512,7 @@ impl TupleTypeSignature { /// Tuple Size: /// size( btreemap ) + type_size /// size( btreemap ) = 2*map.len() + sum(names) + sum(values) - fn inner_size(&self) -> Result, CheckErrors> { + fn inner_size(&self) -> Result, CheckErrorKind> { let Some(mut total_size) = u32::try_from(self.type_map.len()) .ok() .and_then(|x| x.checked_mul(2)) diff --git a/clarity/fuzz/fuzz_targets/fuzz_sanitize.rs b/clarity/fuzz/fuzz_targets/fuzz_sanitize.rs index a4fd207c57f..7b509750abe 100644 --- a/clarity/fuzz/fuzz_targets/fuzz_sanitize.rs +++ b/clarity/fuzz/fuzz_targets/fuzz_sanitize.rs @@ -29,7 +29,7 @@ use clarity::vm::ClarityName; use clarity::vm::representations::ContractName; use clarity::vm::types::serialization::SerializationError; use stacks_common::types::StacksEpochId; -use clarity::vm::analysis::CheckErrors; +use clarity::vm::analysis::CheckErrorKind; use clarity::vm::types::StringSubtype; use libfuzzer_sys::arbitrary; @@ -131,9 +131,9 @@ impl arbitrary::Arbitrary<'_> for FuzzClarityValue { } } -pub fn strict_admits(me: &TypeSignature, x: &ClarityValue) -> Result { +pub fn strict_admits(me: &TypeSignature, x: &ClarityValue) -> Result { match me { - TypeSignature::NoType => Err(CheckErrors::CouldNotDetermineType), + TypeSignature::NoType => Err(CheckErrorKind::CouldNotDetermineType), TypeSignature::IntType => match x { ClarityValue::Int(_) => Ok(true), _ => Ok(false), @@ -238,7 +238,7 @@ pub fn strict_admits(me: &TypeSignature, x: &ClarityValue) -> Result Err(CheckErrors::TraitReferenceNotAllowed), + TypeSignature::TraitReferenceType(_) => Err(CheckErrorKind::TraitReferenceNotAllowed), } } @@ -274,7 +274,7 @@ fn fuzz_sanitize(input: ClarityValue) { deserialize_unsanitized.unwrap_err(); } else { let deser_value = match deserialize_unsanitized { - Err(SerializationError::BadTypeError(CheckErrors::TypeSignatureTooDeep)) => { + Err(SerializationError::BadTypeError(CheckErrorKind::TypeSignatureTooDeep)) => { // pre-2.4, deserializer could error on types deeper than a deserialization limit of 16. // with sanitization enabled (a 2.4-gated feature), these serializations are readable. ClarityValue::deserialize_read( @@ -294,7 +294,7 @@ fn fuzz_sanitize(input: ClarityValue) { true ) { Ok(x) => x, - Err(SerializationError::BadTypeError(CheckErrors::TypeSignatureTooDeep)) => { + Err(SerializationError::BadTypeError(CheckErrorKind::TypeSignatureTooDeep)) => { assert!(!did_strict_admit, "Unsanitized inputs may fail to deserialize, but they must have needed sanitization"); // check that the sanitized value *is* readable let serialized = sanitized_value.serialize_to_vec().expect("serialize sanitized"); @@ -303,7 +303,7 @@ fn fuzz_sanitize(input: ClarityValue) { Some(&computed_type), false ) { - Err(SerializationError::BadTypeError(CheckErrors::TypeSignatureTooDeep)) => { + Err(SerializationError::BadTypeError(CheckErrorKind::TypeSignatureTooDeep)) => { // pre-2.4, deserializer could error on legal types deeper than a deserialization limit of 16. // with sanitization enabled (a 2.4-gated feature), these serializations are readable. ClarityValue::deserialize_read( diff --git a/clarity/fuzz/fuzz_targets/fuzz_value_sanitize.rs b/clarity/fuzz/fuzz_targets/fuzz_value_sanitize.rs index 39def41c642..52c983daecb 100644 --- a/clarity/fuzz/fuzz_targets/fuzz_value_sanitize.rs +++ b/clarity/fuzz/fuzz_targets/fuzz_value_sanitize.rs @@ -19,7 +19,7 @@ #![no_main] use arbitrary::Arbitrary; -use clarity::vm::analysis::CheckErrors; +use clarity::vm::analysis::CheckErrorKind; use clarity::vm::representations::ContractName; use clarity::vm::types::signatures::SequenceSubtype; use clarity::vm::types::{ @@ -131,9 +131,9 @@ impl arbitrary::Arbitrary<'_> for FuzzClarityValue { } } -pub fn strict_admits(me: &TypeSignature, x: &ClarityValue) -> Result { +pub fn strict_admits(me: &TypeSignature, x: &ClarityValue) -> Result { match me { - TypeSignature::NoType => Err(CheckErrors::CouldNotDetermineType), + TypeSignature::NoType => Err(CheckErrorKind::CouldNotDetermineType), TypeSignature::IntType => match x { ClarityValue::Int(_) => Ok(true), _ => Ok(false), @@ -251,7 +251,7 @@ pub fn strict_admits(me: &TypeSignature, x: &ClarityValue) -> Result Err(CheckErrors::TraitReferenceNotAllowed), + | TypeSignature::TraitReferenceType(_) => Err(CheckErrorKind::TraitReferenceNotAllowed), } } diff --git a/clarity/src/vm/analysis/analysis_db.rs b/clarity/src/vm/analysis/analysis_db.rs index 390d3e9dbe0..62c28813ca0 100644 --- a/clarity/src/vm/analysis/analysis_db.rs +++ b/clarity/src/vm/analysis/analysis_db.rs @@ -20,7 +20,7 @@ use clarity_types::representations::ClarityName; use clarity_types::types::{QualifiedContractIdentifier, TraitIdentifier}; use stacks_common::types::StacksEpochId; -use crate::vm::analysis::errors::{CheckError, CheckErrors}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError}; use crate::vm::analysis::type_checker::ContractAnalysis; use crate::vm::database::{ ClarityBackingStore, ClarityDeserializable, ClaritySerializable, RollbackWrapper, @@ -46,16 +46,16 @@ impl<'a> AnalysisDatabase<'a> { pub fn execute(&mut self, f: F) -> Result where F: FnOnce(&mut Self) -> Result, - E: From, + E: From, { self.begin(); let result = f(self).or_else(|e| { self.roll_back() - .map_err(|e| CheckErrors::Expects(format!("{e:?}")))?; + .map_err(|e| CheckErrorKind::Expects(format!("{e:?}")))?; Err(e) })?; self.commit() - .map_err(|e| CheckErrors::Expects(format!("{e:?}")))?; + .map_err(|e| CheckErrorKind::Expects(format!("{e:?}")))?; Ok(result) } @@ -63,16 +63,16 @@ impl<'a> AnalysisDatabase<'a> { self.store.nest(); } - pub fn commit(&mut self) -> Result<(), CheckError> { + pub fn commit(&mut self) -> Result<(), StaticCheckError> { self.store .commit() - .map_err(|e| CheckErrors::Expects(format!("{e:?}")).into()) + .map_err(|e| CheckErrorKind::Expects(format!("{e:?}")).into()) } - pub fn roll_back(&mut self) -> Result<(), CheckError> { + pub fn roll_back(&mut self) -> Result<(), StaticCheckError> { self.store .rollback() - .map_err(|e| CheckErrors::Expects(format!("{e:?}")).into()) + .map_err(|e| CheckErrorKind::Expects(format!("{e:?}")).into()) } pub fn storage_key() -> &'static str { @@ -99,16 +99,16 @@ impl<'a> AnalysisDatabase<'a> { pub fn load_contract_non_canonical( &mut self, contract_identifier: &QualifiedContractIdentifier, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { self.store .get_metadata(contract_identifier, AnalysisDatabase::storage_key()) // treat NoSuchContract error thrown by get_metadata as an Option::None -- - // the analysis will propagate that as a CheckError anyways. + // the analysis will propagate that as a StaticCheckError anyways. .ok() .flatten() .map(|x| { ContractAnalysis::deserialize(&x).map_err(|_| { - CheckErrors::Expects("Bad data deserialized from DB".into()).into() + CheckErrorKind::Expects("Bad data deserialized from DB".into()).into() }) }) .transpose() @@ -118,17 +118,17 @@ impl<'a> AnalysisDatabase<'a> { &mut self, contract_identifier: &QualifiedContractIdentifier, epoch: &StacksEpochId, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { Ok(self .store .get_metadata(contract_identifier, AnalysisDatabase::storage_key()) // treat NoSuchContract error thrown by get_metadata as an Option::None -- - // the analysis will propagate that as a CheckError anyways. + // the analysis will propagate that as a StaticCheckError anyways. .ok() .flatten() .map(|x| { ContractAnalysis::deserialize(&x) - .map_err(|_| CheckErrors::Expects("Bad data deserialized from DB".into())) + .map_err(|_| CheckErrorKind::Expects("Bad data deserialized from DB".into())) }) .transpose()? .map(|mut x| { @@ -141,29 +141,33 @@ impl<'a> AnalysisDatabase<'a> { &mut self, contract_identifier: &QualifiedContractIdentifier, contract: &ContractAnalysis, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { let key = AnalysisDatabase::storage_key(); if self.store.has_metadata_entry(contract_identifier, key) { - return Err(CheckErrors::ContractAlreadyExists(contract_identifier.to_string()).into()); + return Err( + CheckErrorKind::ContractAlreadyExists(contract_identifier.to_string()).into(), + ); } self.store .insert_metadata(contract_identifier, key, &contract.serialize()) - .map_err(|e| CheckErrors::Expects(format!("{e:?}")))?; + .map_err(|e| CheckErrorKind::Expects(format!("{e:?}")))?; Ok(()) } pub fn get_clarity_version( &mut self, contract_identifier: &QualifiedContractIdentifier, - ) -> Result { + ) -> Result { // TODO: this function loads the whole contract to obtain the function type. // but it doesn't need to -- rather this information can just be // stored as its own entry. the analysis cost tracking currently only // charges based on the function type size. let contract = self .load_contract_non_canonical(contract_identifier)? - .ok_or(CheckErrors::NoSuchContract(contract_identifier.to_string()))?; + .ok_or(CheckErrorKind::NoSuchContract( + contract_identifier.to_string(), + ))?; Ok(contract.clarity_version) } @@ -172,14 +176,16 @@ impl<'a> AnalysisDatabase<'a> { contract_identifier: &QualifiedContractIdentifier, function_name: &str, epoch: &StacksEpochId, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { // TODO: this function loads the whole contract to obtain the function type. // but it doesn't need to -- rather this information can just be // stored as its own entry. the analysis cost tracking currently only // charges based on the function type size. let contract = self .load_contract_non_canonical(contract_identifier)? - .ok_or(CheckErrors::NoSuchContract(contract_identifier.to_string()))?; + .ok_or(CheckErrorKind::NoSuchContract( + contract_identifier.to_string(), + ))?; Ok(contract .get_public_function_type(function_name) .map(|x| x.canonicalize(epoch))) @@ -190,14 +196,16 @@ impl<'a> AnalysisDatabase<'a> { contract_identifier: &QualifiedContractIdentifier, function_name: &str, epoch: &StacksEpochId, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { // TODO: this function loads the whole contract to obtain the function type. // but it doesn't need to -- rather this information can just be // stored as its own entry. the analysis cost tracking currently only // charges based on the function type size. let contract = self .load_contract_non_canonical(contract_identifier)? - .ok_or(CheckErrors::NoSuchContract(contract_identifier.to_string()))?; + .ok_or(CheckErrorKind::NoSuchContract( + contract_identifier.to_string(), + ))?; Ok(contract .get_read_only_function_type(function_name) .map(|x| x.canonicalize(epoch))) @@ -208,14 +216,16 @@ impl<'a> AnalysisDatabase<'a> { contract_identifier: &QualifiedContractIdentifier, trait_name: &str, epoch: &StacksEpochId, - ) -> Result>, CheckError> { + ) -> Result>, StaticCheckError> { // TODO: this function loads the whole contract to obtain the function type. // but it doesn't need to -- rather this information can just be // stored as its own entry. the analysis cost tracking currently only // charges based on the function type size. let contract = self .load_contract_non_canonical(contract_identifier)? - .ok_or(CheckErrors::NoSuchContract(contract_identifier.to_string()))?; + .ok_or(CheckErrorKind::NoSuchContract( + contract_identifier.to_string(), + ))?; Ok(contract.get_defined_trait(trait_name).map(|trait_map| { trait_map .iter() @@ -227,10 +237,12 @@ impl<'a> AnalysisDatabase<'a> { pub fn get_implemented_traits( &mut self, contract_identifier: &QualifiedContractIdentifier, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { let contract = self .load_contract_non_canonical(contract_identifier)? - .ok_or(CheckErrors::NoSuchContract(contract_identifier.to_string()))?; + .ok_or(CheckErrorKind::NoSuchContract( + contract_identifier.to_string(), + ))?; Ok(contract.implemented_traits) } diff --git a/clarity/src/vm/analysis/arithmetic_checker/mod.rs b/clarity/src/vm/analysis/arithmetic_checker/mod.rs index 0d12aed24a6..fba0ce69fc5 100644 --- a/clarity/src/vm/analysis/arithmetic_checker/mod.rs +++ b/clarity/src/vm/analysis/arithmetic_checker/mod.rs @@ -16,7 +16,9 @@ use clarity_types::representations::ClarityName; -pub use super::errors::{check_argument_count, check_arguments_at_least, CheckError, CheckErrors}; +pub use super::errors::{ + check_argument_count, check_arguments_at_least, CheckErrorKind, StaticCheckError, +}; use crate::vm::analysis::types::ContractAnalysis; use crate::vm::functions::define::{DefineFunctions, DefineFunctionsParsed}; use crate::vm::functions::NativeFunctions; diff --git a/clarity/src/vm/analysis/contract_interface_builder/mod.rs b/clarity/src/vm/analysis/contract_interface_builder/mod.rs index 26c71f695b9..5fc0169c5cb 100644 --- a/clarity/src/vm/analysis/contract_interface_builder/mod.rs +++ b/clarity/src/vm/analysis/contract_interface_builder/mod.rs @@ -19,16 +19,16 @@ use std::collections::{BTreeMap, BTreeSet}; use stacks_common::types::StacksEpochId; use crate::vm::analysis::types::ContractAnalysis; -use crate::vm::analysis::CheckError; +use crate::vm::analysis::StaticCheckError; use crate::vm::types::signatures::CallableSubtype; use crate::vm::types::{ FixedFunction, FunctionArg, FunctionType, TupleTypeSignature, TypeSignature, }; -use crate::vm::{CheckErrors, ClarityName, ClarityVersion}; +use crate::vm::{CheckErrorKind, ClarityName, ClarityVersion}; pub fn build_contract_interface( contract_analysis: &ContractAnalysis, -) -> Result { +) -> Result { let mut contract_interface = ContractInterface::new(contract_analysis.epoch, contract_analysis.clarity_version); @@ -267,7 +267,7 @@ impl ContractInterfaceFunction { fn from_map( map: &BTreeMap, access: ContractInterfaceFunctionAccess, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { map.iter() .map(|(name, function_type)| { Ok(ContractInterfaceFunction { @@ -278,7 +278,7 @@ impl ContractInterfaceFunction { FunctionType::Fixed(FixedFunction { returns, .. }) => { ContractInterfaceAtomType::from_type_signature(returns) } - _ => return Err(CheckErrors::Expects( + _ => return Err(CheckErrorKind::Expects( "Contract functions should only have fixed function return types!" .into(), ) @@ -290,7 +290,7 @@ impl ContractInterfaceFunction { ContractInterfaceFunctionArg::from_function_args(args) } _ => { - return Err(CheckErrors::Expects( + return Err(CheckErrorKind::Expects( "Contract functions should only have fixed function arguments!" .into(), ) @@ -400,9 +400,9 @@ impl ContractInterface { } } - pub fn serialize(&self) -> Result { + pub fn serialize(&self) -> Result { serde_json::to_string(self).map_err(|_| { - CheckErrors::Expects("Failed to serialize contract interface".into()).into() + CheckErrorKind::Expects("Failed to serialize contract interface".into()).into() }) } } diff --git a/clarity/src/vm/analysis/errors.rs b/clarity/src/vm/analysis/errors.rs index f7ce7072f38..7bf7faabc13 100644 --- a/clarity/src/vm/analysis/errors.rs +++ b/clarity/src/vm/analysis/errors.rs @@ -15,6 +15,6 @@ // along with this program. If not, see . pub use clarity_types::errors::analysis::{ - check_argument_count, check_arguments_at_least, check_arguments_at_most, CheckError, - CheckErrors, SyntaxBindingError, SyntaxBindingErrorType, + check_argument_count, check_arguments_at_least, check_arguments_at_most, CheckErrorKind, + StaticCheckError, SyntaxBindingError, SyntaxBindingErrorType, }; diff --git a/clarity/src/vm/analysis/mod.rs b/clarity/src/vm/analysis/mod.rs index 63790ecd87d..2ae4e1c79a8 100644 --- a/clarity/src/vm/analysis/mod.rs +++ b/clarity/src/vm/analysis/mod.rs @@ -28,7 +28,7 @@ use stacks_common::types::StacksEpochId; pub use self::analysis_db::AnalysisDatabase; use self::arithmetic_checker::ArithmeticOnlyChecker; use self::contract_interface_builder::build_contract_interface; -pub use self::errors::{CheckError, CheckErrors}; +pub use self::errors::{CheckErrorKind, StaticCheckError}; use self::read_only_checker::ReadOnlyChecker; use self::trait_checker::TraitChecker; use self::type_checker::v2_05::TypeChecker as TypeChecker2_05; @@ -52,10 +52,10 @@ pub fn mem_type_check( snippet: &str, version: ClarityVersion, epoch: StacksEpochId, -) -> Result<(Option, ContractAnalysis), CheckError> { +) -> Result<(Option, ContractAnalysis), StaticCheckError> { let contract_identifier = QualifiedContractIdentifier::transient(); let contract = build_ast(&contract_identifier, snippet, &mut (), version, epoch) - .map_err(|e| CheckErrors::Expects(format!("Failed to build AST: {e}")))? + .map_err(|e| CheckErrorKind::Expects(format!("Failed to build AST: {e}")))? .expressions; let mut marf = MemoryBackingStore::new(); @@ -76,11 +76,11 @@ pub fn mem_type_check( let first_type = x .type_map .as_ref() - .ok_or_else(|| CheckErrors::Expects("Should be non-empty".into()))? + .ok_or_else(|| CheckErrorKind::Expects("Should be non-empty".into()))? .get_type_expected( x.expressions .last() - .ok_or_else(|| CheckErrors::Expects("Should be non-empty".into()))?, + .ok_or_else(|| CheckErrorKind::Expects("Should be non-empty".into()))?, ) .cloned(); Ok((first_type, x)) @@ -99,7 +99,7 @@ pub fn type_check( insert_contract: bool, epoch: &StacksEpochId, version: &ClarityVersion, -) -> Result { +) -> Result { run_analysis( contract_identifier, expressions, @@ -125,7 +125,7 @@ pub fn run_analysis( epoch: StacksEpochId, version: ClarityVersion, build_type_map: bool, -) -> Result> { +) -> Result> { let mut contract_analysis = ContractAnalysis::new( contract_identifier.clone(), expressions.to_vec(), @@ -151,7 +151,7 @@ pub fn run_analysis( TypeChecker2_1::run_pass(&epoch, &mut contract_analysis, db, build_type_map) } StacksEpochId::Epoch10 => { - return Err(CheckErrors::Expects( + return Err(CheckErrorKind::Expects( "Epoch 1.0 is not a valid epoch for analysis".into(), ) .into()) diff --git a/clarity/src/vm/analysis/read_only_checker/mod.rs b/clarity/src/vm/analysis/read_only_checker/mod.rs index f3e243a27a5..0c62c80e4dd 100644 --- a/clarity/src/vm/analysis/read_only_checker/mod.rs +++ b/clarity/src/vm/analysis/read_only_checker/mod.rs @@ -21,7 +21,8 @@ use clarity_types::types::{PrincipalData, Value}; use stacks_common::types::StacksEpochId; pub use super::errors::{ - check_argument_count, check_arguments_at_least, CheckError, CheckErrors, SyntaxBindingError, + check_argument_count, check_arguments_at_least, CheckErrorKind, StaticCheckError, + SyntaxBindingError, }; use super::AnalysisDatabase; use crate::vm::analysis::types::{AnalysisPass, ContractAnalysis}; @@ -54,7 +55,7 @@ impl AnalysisPass for ReadOnlyChecker<'_, '_> { epoch: &StacksEpochId, contract_analysis: &mut ContractAnalysis, analysis_db: &mut AnalysisDatabase, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { let mut command = ReadOnlyChecker::new(analysis_db, epoch, &contract_analysis.clarity_version); command.run(contract_analysis)?; @@ -81,9 +82,9 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { /// Returns successfully iff this function is read-only correct. /// /// # Errors - /// - `CheckErrors::WriteAttemptedInReadOnly` + /// - `CheckErrorKind::WriteAttemptedInReadOnly` /// - Contract parsing errors - pub fn run(&mut self, contract_analysis: &ContractAnalysis) -> Result<(), CheckError> { + pub fn run(&mut self, contract_analysis: &ContractAnalysis) -> Result<(), StaticCheckError> { // Iterate over all the top-level statements in a contract. for exp in contract_analysis.expressions.iter() { let mut result = self.check_top_level_expression(exp); @@ -105,12 +106,12 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { /// Returns successfully iff this function is read-only correct. /// /// # Errors - /// - CheckErrors::WriteAttemptedInReadOnly + /// - CheckErrorKind::WriteAttemptedInReadOnly /// - Contract parsing errors fn check_top_level_expression( &mut self, expression: &SymbolicExpression, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { use crate::vm::functions::define::DefineFunctionsParsed::*; if let Some(define_type) = DefineFunctionsParsed::try_parse(expression)? { match define_type { @@ -135,7 +136,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { let (function_name, is_read_only) = self.check_define_function(signature, body)?; if !is_read_only { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } else { self.defined_functions.insert(function_name, is_read_only); } @@ -168,19 +169,22 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { &mut self, signature: &[SymbolicExpression], body: &SymbolicExpression, - ) -> Result<(ClarityName, bool), CheckError> { + ) -> Result<(ClarityName, bool), StaticCheckError> { let function_name = signature .first() - .ok_or(CheckErrors::DefineFunctionBadSignature)? + .ok_or(CheckErrorKind::DefineFunctionBadSignature)? .match_atom() - .ok_or(CheckErrors::BadFunctionName)?; + .ok_or(CheckErrorKind::BadFunctionName)?; let is_read_only = self.check_read_only(body)?; Ok((function_name.clone(), is_read_only)) } - fn check_reads_only_valid(&mut self, expr: &SymbolicExpression) -> Result<(), CheckError> { + fn check_reads_only_valid( + &mut self, + expr: &SymbolicExpression, + ) -> Result<(), StaticCheckError> { use crate::vm::functions::define::DefineFunctionsParsed::*; if let Some(define_type) = DefineFunctionsParsed::try_parse(expr)? { match define_type { @@ -203,7 +207,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { ReadOnlyFunction { signature, body } => { let (f_name, is_read_only) = self.check_define_function(signature, body)?; if !is_read_only { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } else { self.defined_functions.insert(f_name, is_read_only); } @@ -225,7 +229,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { /// (1) for whether or not they are valid with respect to read-only requirements. /// (2) if valid, returns whether or not they are read only. /// Note that because of (1), this function _cannot_ short-circuit on read-only. - fn check_read_only(&mut self, expr: &SymbolicExpression) -> Result { + fn check_read_only(&mut self, expr: &SymbolicExpression) -> Result { match expr.expr { AtomValue(_) | LiteralValue(_) | Atom(_) | TraitReference(_, _) | Field(_) => Ok(true), List(ref expression) => self.check_expression_application_is_read_only(expression), @@ -242,7 +246,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { fn check_each_expression_is_read_only( &mut self, expressions: &[SymbolicExpression], - ) -> Result { + ) -> Result { let mut result = true; for expression in expressions.iter() { let expr_read_only = self.check_read_only(expression)?; @@ -265,7 +269,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { &mut self, function: &str, args: &[SymbolicExpression], - ) -> Option> { + ) -> Option> { NativeFunctions::lookup_by_name_at_version(function, &self.clarity_version) .map(|function| self.check_native_function_is_read_only(&function, args)) } @@ -278,7 +282,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { &mut self, function: &NativeFunctions, args: &[SymbolicExpression], - ) -> Result { + ) -> Result { use crate::vm::functions::NativeFunctions::*; match function { @@ -392,7 +396,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { let is_block_arg_read_only = self.check_read_only(&args[0])?; let closure_read_only = self.check_read_only(&args[1])?; if !closure_read_only { - return Err(CheckErrors::AtBlockClosureMustBeReadOnly.into()); + return Err(CheckErrorKind::AtBlockClosureMustBeReadOnly.into()); } Ok(is_block_arg_read_only) } @@ -409,17 +413,17 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { Let => { check_arguments_at_least(2, args)?; - let binding_list = args[0].match_list().ok_or(CheckErrors::BadLetSyntax)?; + let binding_list = args[0].match_list().ok_or(CheckErrorKind::BadLetSyntax)?; for (i, pair) in binding_list.iter().enumerate() { let pair_expression = pair.match_list().ok_or_else(|| { - CheckError::with_expression( + StaticCheckError::with_expression( SyntaxBindingError::let_binding_not_list(i).into(), pair, ) })?; if pair_expression.len() != 2 { - return Err(CheckError::with_expression( + return Err(StaticCheckError::with_expression( SyntaxBindingError::let_binding_invalid_length(i).into(), pair, )); @@ -461,13 +465,13 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { TupleCons => { for (i, pair) in args.iter().enumerate() { let pair_expression = pair.match_list().ok_or_else(|| { - CheckError::with_expression( + StaticCheckError::with_expression( SyntaxBindingError::tuple_cons_not_list(i).into(), pair, ) })?; if pair_expression.len() != 2 { - return Err(CheckError::with_expression( + return Err(StaticCheckError::with_expression( SyntaxBindingError::tuple_cons_invalid_length(i).into(), pair, )); @@ -484,7 +488,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { let function_name = args[1] .match_atom() - .ok_or(CheckErrors::ContractCallExpectName)?; + .ok_or(CheckErrorKind::ContractCallExpectName)?; let is_function_read_only = match &args[0].expr { SymbolicExpressionType::LiteralValue(Value::Principal( @@ -503,7 +507,11 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { // As such dynamic dispatch is currently forbidden. false } - _ => return Err(CheckError::new(CheckErrors::ContractCallExpectName)), + _ => { + return Err(StaticCheckError::new( + CheckErrorKind::ContractCallExpectName, + )) + } }; self.check_each_expression_is_read_only(&args[2..]) @@ -519,7 +527,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { let allowances = args[1] .match_list() - .ok_or(CheckErrors::ExpectedListOfAllowances( + .ok_or(CheckErrorKind::ExpectedListOfAllowances( "restrict-assets?".into(), 2, ))?; @@ -537,7 +545,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { let allowances = args[0] .match_list() - .ok_or(CheckErrors::ExpectedListOfAllowances( + .ok_or(CheckErrorKind::ExpectedListOfAllowances( "as-contract?".into(), 1, ))?; @@ -558,20 +566,20 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { /// Returns `true` iff the function application is read-only. /// /// # Errors - /// - `CheckErrors::NonFunctionApplication` if there is no first expression, or if the first + /// - `CheckErrorKind::NonFunctionApplication` if there is no first expression, or if the first /// expression is not a `ClarityName`. - /// - `CheckErrors::UnknownFunction` if the first expression does not name a known function. + /// - `CheckErrorKind::UnknownFunction` if the first expression does not name a known function. fn check_expression_application_is_read_only( &mut self, expressions: &[SymbolicExpression], - ) -> Result { + ) -> Result { let (function_name, args) = expressions .split_first() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; let function_name = function_name .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; if let Some(mut result) = self.try_check_native_function_is_read_only(function_name, args) { if let Err(ref mut check_err) = result { @@ -582,7 +590,7 @@ impl<'a, 'b> ReadOnlyChecker<'a, 'b> { let is_function_read_only = *self .defined_functions .get(function_name) - .ok_or(CheckErrors::UnknownFunction(function_name.to_string()))?; + .ok_or(CheckErrorKind::UnknownFunction(function_name.to_string()))?; self.check_each_expression_is_read_only(args) .map(|args_read_only| args_read_only && is_function_read_only) } diff --git a/clarity/src/vm/analysis/read_only_checker/tests.rs b/clarity/src/vm/analysis/read_only_checker/tests.rs index 585bea62cdc..5b985b7b2f2 100644 --- a/clarity/src/vm/analysis/read_only_checker/tests.rs +++ b/clarity/src/vm/analysis/read_only_checker/tests.rs @@ -21,7 +21,7 @@ use rstest_reuse::{self, *}; use stacks_common::types::StacksEpochId; use crate::vm::analysis::type_checker::v2_1::tests::mem_type_check; -use crate::vm::analysis::{type_check, CheckErrors}; +use crate::vm::analysis::{type_check, CheckErrorKind}; use crate::vm::ast::parse; use crate::vm::database::MemoryBackingStore; use crate::vm::tests::test_clarity_versions; @@ -34,11 +34,11 @@ fn test_argument_count_violations() { ( "(define-private (foo-bar) (at-block))", - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), ), ( "(define-private (foo-bar) (map-get?))", - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), ), ]; @@ -72,7 +72,7 @@ fn test_at_block_violations() { for contract in examples.iter() { let err = mem_type_check(contract).unwrap_err(); eprintln!("{err}"); - assert_eq!(*err.err, CheckErrors::AtBlockClosureMustBeReadOnly) + assert_eq!(*err.err, CheckErrorKind::AtBlockClosureMustBeReadOnly) } } @@ -163,7 +163,7 @@ fn test_simple_read_only_violations() { for contract in bad_contracts.iter() { let err = mem_type_check(contract).unwrap_err(); - assert_eq!(*err.err, CheckErrors::WriteAttemptedInReadOnly) + assert_eq!(*err.err, CheckErrorKind::WriteAttemptedInReadOnly) } } @@ -180,7 +180,7 @@ fn test_nested_writing_closure() { for contract in bad_contracts.iter() { let err = mem_type_check(contract).unwrap_err(); - assert_eq!(*err.err, CheckErrors::AtBlockClosureMustBeReadOnly) + assert_eq!(*err.err, CheckErrorKind::AtBlockClosureMustBeReadOnly) } } @@ -231,7 +231,7 @@ fn test_contract_call_read_only_violations( ) }) .unwrap_err(); - assert_eq!(*err.err, CheckErrors::WriteAttemptedInReadOnly); + assert_eq!(*err.err, CheckErrorKind::WriteAttemptedInReadOnly); db.execute(|db| { type_check( diff --git a/clarity/src/vm/analysis/trait_checker/mod.rs b/clarity/src/vm/analysis/trait_checker/mod.rs index 491fe81c24c..a2563de2d47 100644 --- a/clarity/src/vm/analysis/trait_checker/mod.rs +++ b/clarity/src/vm/analysis/trait_checker/mod.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use stacks_common::types::StacksEpochId; -use crate::vm::analysis::errors::{CheckError, CheckErrors}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError}; use crate::vm::analysis::types::{AnalysisPass, ContractAnalysis}; use crate::vm::analysis::AnalysisDatabase; @@ -28,7 +28,7 @@ impl AnalysisPass for TraitChecker { epoch: &StacksEpochId, contract_analysis: &mut ContractAnalysis, analysis_db: &mut AnalysisDatabase, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { let mut command = TraitChecker::new(epoch); command.run(contract_analysis, analysis_db)?; Ok(()) @@ -44,18 +44,18 @@ impl TraitChecker { &mut self, contract_analysis: &ContractAnalysis, analysis_db: &mut AnalysisDatabase, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { for trait_identifier in &contract_analysis.implemented_traits { let trait_name = trait_identifier.name.to_string(); let contract_defining_trait = analysis_db .load_contract(&trait_identifier.contract_identifier, &self.epoch)? - .ok_or(CheckErrors::TraitReferenceUnknown( + .ok_or(CheckErrorKind::TraitReferenceUnknown( trait_identifier.name.to_string(), ))?; let trait_definition = contract_defining_trait .get_defined_trait(&trait_name) - .ok_or(CheckErrors::TraitReferenceUnknown( + .ok_or(CheckErrorKind::TraitReferenceUnknown( trait_identifier.name.to_string(), ))?; diff --git a/clarity/src/vm/analysis/trait_checker/tests.rs b/clarity/src/vm/analysis/trait_checker/tests.rs index 305781f9593..c103f7a6eaa 100644 --- a/clarity/src/vm/analysis/trait_checker/tests.rs +++ b/clarity/src/vm/analysis/trait_checker/tests.rs @@ -20,9 +20,9 @@ use rstest::rstest; use rstest_reuse::{self, *}; use stacks_common::types::StacksEpochId; -use crate::vm::analysis::errors::CheckErrors; -use crate::vm::analysis::{type_check, CheckError}; -use crate::vm::ast::errors::ParseErrors; +use crate::vm::analysis::errors::CheckErrorKind; +use crate::vm::analysis::{type_check, StaticCheckError}; +use crate::vm::ast::errors::ParseErrorKind; use crate::vm::ast::{build_ast, parse}; use crate::vm::database::MemoryBackingStore; use crate::vm::tests::test_clarity_versions; @@ -98,7 +98,7 @@ fn test_incomplete_impl_trait_1(#[case] version: ClarityVersion, #[case] epoch: }) .unwrap_err(); match *err.err { - CheckErrors::BadTraitImplementation(_, _) => {} + CheckErrorKind::BadTraitImplementation(_, _) => {} _ => panic!("{err:?}"), } } @@ -125,7 +125,7 @@ fn test_incomplete_impl_trait_2(#[case] version: ClarityVersion, #[case] epoch: }) .unwrap_err(); match *err.err { - CheckErrors::BadTraitImplementation(_, _) => {} + CheckErrorKind::BadTraitImplementation(_, _) => {} _ => panic!("{err:?}"), } } @@ -149,7 +149,7 @@ fn test_impl_trait_arg_admission_1(#[case] version: ClarityVersion, #[case] epoc }) .unwrap_err(); match *err.err { - CheckErrors::BadTraitImplementation(_, _) => {} + CheckErrorKind::BadTraitImplementation(_, _) => {} _ => panic!("{err:?}"), } } @@ -289,7 +289,7 @@ fn test_get_trait_reference_from_tuple( }) .unwrap_err(); match *err.err { - CheckErrors::ContractCallExpectName => {} + CheckErrorKind::ContractCallExpectName => {} _ => panic!("{err:?}"), } } @@ -332,7 +332,7 @@ fn test_dynamic_dispatch_by_defining_and_impl_trait( }) .unwrap_err(); match *err.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err:?}"), } } @@ -359,7 +359,7 @@ fn test_define_map_storing_trait_references( .unwrap_err(); match *err.err { - ParseErrors::TraitReferenceNotAllowed => {} + ParseErrorKind::TraitReferenceNotAllowed => {} _ => panic!("{err:?}"), } } @@ -383,7 +383,7 @@ fn test_cycle_in_traits_1_contract(#[case] version: ClarityVersion, #[case] epoc ) .unwrap_err(); match *err.err { - ParseErrors::CircularReference(_) => {} + ParseErrorKind::CircularReference(_) => {} _ => panic!("{err:?}"), } } @@ -434,7 +434,7 @@ fn test_cycle_in_traits_2_contracts(#[case] version: ClarityVersion, #[case] epo }) .unwrap_err(); match *err.err { - CheckErrors::NoSuchContract(_) => {} + CheckErrorKind::NoSuchContract(_) => {} _ => panic!("{err:?}"), } } @@ -487,7 +487,7 @@ fn test_dynamic_dispatch_unknown_method( }) .unwrap_err(); match *err.err { - CheckErrors::TraitMethodUnknown(_, _) => {} + CheckErrorKind::TraitMethodUnknown(_, _) => {} _ => panic!("{err:?}"), } } @@ -671,7 +671,7 @@ fn test_dynamic_dispatch_collision_trait( ) .unwrap_err(); match *err.err { - ParseErrors::NameAlreadyUsed(_) => {} + ParseErrorKind::NameAlreadyUsed(_) => {} _ => panic!("{err:?}"), } } @@ -700,7 +700,7 @@ fn test_dynamic_dispatch_collision_defined_trait( ) .unwrap_err(); match *err.err { - ParseErrors::NameAlreadyUsed(_) => {} + ParseErrorKind::NameAlreadyUsed(_) => {} _ => panic!("{err:?}"), } } @@ -740,7 +740,7 @@ fn test_dynamic_dispatch_collision_imported_trait( ) .unwrap_err(); match *err.err { - ParseErrors::NameAlreadyUsed(_) => {} + ParseErrorKind::NameAlreadyUsed(_) => {} _ => panic!("{err:?}"), } } @@ -812,7 +812,7 @@ fn test_dynamic_dispatch_importing_non_existant_trait( }) .unwrap_err(); match *err.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err:?}"), } } @@ -1099,13 +1099,13 @@ fn test_dynamic_dispatch_including_wrong_nested_trait( .unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, actual) if epoch < StacksEpochId::Epoch21 => { + CheckErrorKind::TypeError(expected, actual) if epoch < StacksEpochId::Epoch21 => { match (&*expected, &*actual) { (TypeSignature::TraitReferenceType(_), TypeSignature::TraitReferenceType(_)) => {} _ => panic!("unexpected TypeSignature: {expected:?} {actual:?}"), } } - CheckErrors::TypeError(expected, actual) + CheckErrorKind::TypeError(expected, actual) if epoch >= StacksEpochId::Epoch21 && version < ClarityVersion::Clarity2 => { match (&*expected, &*actual) { @@ -1113,7 +1113,7 @@ fn test_dynamic_dispatch_including_wrong_nested_trait( _ => panic!("unexpected TypeSignature: {expected:?} {actual:?}"), } } - CheckErrors::TraitReferenceUnknown(name) => assert_eq!(name.as_str(), "trait-a"), + CheckErrorKind::TraitReferenceUnknown(name) => assert_eq!(name.as_str(), "trait-a"), _ => panic!("{err:?}"), } } @@ -1167,7 +1167,7 @@ fn test_dynamic_dispatch_mismatched_args( }) .unwrap_err(); match *err.err { - CheckErrors::TypeError(_, _) => {} + CheckErrorKind::TypeError(_, _) => {} _ => panic!("{err:?}"), } } @@ -1221,7 +1221,7 @@ fn test_dynamic_dispatch_mismatched_returns( }) .unwrap_err(); match *err.err { - CheckErrors::BadTraitImplementation(_, _) => {} + CheckErrorKind::BadTraitImplementation(_, _) => {} _ => panic!("{err:?}"), } } @@ -1257,7 +1257,7 @@ fn test_bad_call_with_trait(#[case] version: ClarityVersion, #[case] epoch: Stac }) .unwrap_err(); match *err.err { - CheckErrors::TypeError(_, _) => {} + CheckErrorKind::TypeError(_, _) => {} _ => panic!("{err:?}"), } } @@ -1466,7 +1466,7 @@ fn test_dynamic_dispatch_pass_bound_principal_as_trait_in_user_defined_functions match result { Err(err) if version == ClarityVersion::Clarity1 => { match *err.err { - CheckErrors::TypeError(_, _) => {} + CheckErrorKind::TypeError(_, _) => {} _ => panic!("{err:?}"), }; } @@ -1560,7 +1560,7 @@ fn test_contract_of_wrong_type(#[case] version: ClarityVersion, #[case] epoch: S }) .unwrap_err(); match *err_principal.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err_principal:?}"), } let err_int = db @@ -1570,7 +1570,7 @@ fn test_contract_of_wrong_type(#[case] version: ClarityVersion, #[case] epoch: S }) .unwrap_err(); match *err_int.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err_int:?}"), } let err_uint = db @@ -1580,7 +1580,7 @@ fn test_contract_of_wrong_type(#[case] version: ClarityVersion, #[case] epoch: S }) .unwrap_err(); match *err_uint.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err_uint:?}"), } let err_bool = db @@ -1590,7 +1590,7 @@ fn test_contract_of_wrong_type(#[case] version: ClarityVersion, #[case] epoch: S }) .unwrap_err(); match *err_bool.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err_bool:?}"), } let err_list = db @@ -1600,7 +1600,7 @@ fn test_contract_of_wrong_type(#[case] version: ClarityVersion, #[case] epoch: S }) .unwrap_err(); match *err_list.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err_list:?}"), } let err_buff = db @@ -1610,7 +1610,7 @@ fn test_contract_of_wrong_type(#[case] version: ClarityVersion, #[case] epoch: S }) .unwrap_err(); match *err_buff.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err_buff:?}"), } let err_tuple = db @@ -1620,7 +1620,7 @@ fn test_contract_of_wrong_type(#[case] version: ClarityVersion, #[case] epoch: S }) .unwrap_err(); match *err_tuple.err { - CheckErrors::TraitReferenceUnknown(_) => {} + CheckErrorKind::TraitReferenceUnknown(_) => {} _ => panic!("{err_tuple:?}"), } } @@ -1818,8 +1818,8 @@ fn test_trait_contract_not_found(#[case] version: ClarityVersion, #[case] epoch: &version, ) }) { - Err(CheckError { err, .. }) if version < ClarityVersion::Clarity2 => match *err { - CheckErrors::NoSuchContract(contract) => { + Err(StaticCheckError { err, .. }) if version < ClarityVersion::Clarity2 => match *err { + CheckErrorKind::NoSuchContract(contract) => { assert!(contract.ends_with(".trait-contract")) } _ => panic!("{version}: unexpected NoSuchContract error"), diff --git a/clarity/src/vm/analysis/type_checker/contexts.rs b/clarity/src/vm/analysis/type_checker/contexts.rs index ddc34d8b8b5..50f8cd16104 100644 --- a/clarity/src/vm/analysis/type_checker/contexts.rs +++ b/clarity/src/vm/analysis/type_checker/contexts.rs @@ -18,7 +18,7 @@ use std::collections::{HashMap, HashSet}; use stacks_common::types::StacksEpochId; -use crate::vm::analysis::errors::{CheckError, CheckErrors}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError}; use crate::vm::types::signatures::CallableSubtype; use crate::vm::types::{TraitIdentifier, TypeSignature}; use crate::vm::{ClarityName, ClarityVersion, SymbolicExpression, MAX_CONTEXT_DEPTH}; @@ -64,18 +64,22 @@ impl TypeMap { &mut self, expr: &SymbolicExpression, type_sig: TypeSignature, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { match self.map { TypeMapDataType::Map(ref mut map) => { if map.insert(expr.id, type_sig).is_some() { - Err(CheckError::new(CheckErrors::TypeAlreadyAnnotatedFailure)) + Err(StaticCheckError::new( + CheckErrorKind::TypeAlreadyAnnotatedFailure, + )) } else { Ok(()) } } TypeMapDataType::Set(ref mut map) => { if !map.insert(expr.id) { - Err(CheckError::new(CheckErrors::TypeAlreadyAnnotatedFailure)) + Err(StaticCheckError::new( + CheckErrorKind::TypeAlreadyAnnotatedFailure, + )) } else { Ok(()) } @@ -103,9 +107,11 @@ impl TypingContext<'_> { } } - pub fn extend(&self) -> Result, CheckError> { + pub fn extend(&self) -> Result, StaticCheckError> { if self.depth >= MAX_CONTEXT_DEPTH { - Err(CheckError::new(CheckErrors::MaxContextDepthReached)) + Err(StaticCheckError::new( + CheckErrorKind::MaxContextDepthReached, + )) } else { Ok(TypingContext { epoch: self.epoch, diff --git a/clarity/src/vm/analysis/type_checker/mod.rs b/clarity/src/vm/analysis/type_checker/mod.rs index d33c7c87e67..7305d63d08e 100644 --- a/clarity/src/vm/analysis/type_checker/mod.rs +++ b/clarity/src/vm/analysis/type_checker/mod.rs @@ -20,7 +20,7 @@ pub mod v2_1; use stacks_common::types::StacksEpochId; -use super::errors::{CheckError, CheckErrors}; +use super::errors::{CheckErrorKind, StaticCheckError}; pub use super::types::{AnalysisPass, ContractAnalysis}; use super::AnalysisDatabase; use crate::vm::costs::CostTracker; @@ -34,7 +34,7 @@ impl FunctionType { args: &[TypeSignature], epoch: StacksEpochId, clarity_version: ClarityVersion, - ) -> Result { + ) -> Result { match epoch { StacksEpochId::Epoch20 | StacksEpochId::Epoch2_05 => { self.check_args_2_05(accounting, args) @@ -49,7 +49,7 @@ impl FunctionType { | StacksEpochId::Epoch32 | StacksEpochId::Epoch33 => self.check_args_2_1(accounting, args, clarity_version), StacksEpochId::Epoch10 => { - Err(CheckErrors::Expects("Epoch10 is not supported".into()).into()) + Err(CheckErrorKind::Expects("Epoch10 is not supported".into()).into()) } } } @@ -60,7 +60,7 @@ impl FunctionType { func_args: &[Value], epoch: StacksEpochId, clarity_version: ClarityVersion, - ) -> Result { + ) -> Result { match epoch { StacksEpochId::Epoch20 | StacksEpochId::Epoch2_05 => { self.check_args_by_allowing_trait_cast_2_05(db, func_args) @@ -77,7 +77,7 @@ impl FunctionType { self.check_args_by_allowing_trait_cast_2_1(db, clarity_version, func_args) } StacksEpochId::Epoch10 => { - Err(CheckErrors::Expects("Epoch10 is not supported".into()).into()) + Err(CheckErrorKind::Expects("Epoch10 is not supported".into()).into()) } } } diff --git a/clarity/src/vm/analysis/type_checker/v2_05/contexts.rs b/clarity/src/vm/analysis/type_checker/v2_05/contexts.rs index 4af94d41a79..684c7ff872b 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/contexts.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/contexts.rs @@ -16,7 +16,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; -use crate::vm::analysis::errors::{CheckError, CheckErrors}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError}; use crate::vm::analysis::types::ContractAnalysis; use crate::vm::representations::ClarityName; use crate::vm::types::signatures::FunctionSignature; @@ -57,7 +57,7 @@ impl ContractContext { } } - pub fn check_name_used(&self, name: &str) -> Result<(), CheckError> { + pub fn check_name_used(&self, name: &str) -> Result<(), StaticCheckError> { if self.variable_types.contains_key(name) || self.persisted_variable_types.contains_key(name) || self.private_function_types.contains_key(name) @@ -67,7 +67,7 @@ impl ContractContext { || self.traits.contains_key(name) || self.map_types.contains_key(name) { - Err(CheckError::new(CheckErrors::NameAlreadyUsed( + Err(StaticCheckError::new(CheckErrorKind::NameAlreadyUsed( name.to_string(), ))) } else { @@ -75,7 +75,7 @@ impl ContractContext { } } - fn check_function_type(&mut self, f_name: &str) -> Result<(), CheckError> { + fn check_function_type(&mut self, f_name: &str) -> Result<(), StaticCheckError> { self.check_name_used(f_name)?; Ok(()) } @@ -92,7 +92,7 @@ impl ContractContext { &mut self, name: ClarityName, func_type: FunctionType, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_function_type(&name)?; self.public_function_types.insert(name, func_type); Ok(()) @@ -102,7 +102,7 @@ impl ContractContext { &mut self, name: ClarityName, func_type: FunctionType, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_function_type(&name)?; self.read_only_function_types.insert(name, func_type); Ok(()) @@ -112,7 +112,7 @@ impl ContractContext { &mut self, name: ClarityName, func_type: FunctionType, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_function_type(&name)?; self.private_function_types.insert(name, func_type); Ok(()) @@ -122,7 +122,7 @@ impl ContractContext { &mut self, map_name: ClarityName, map_type: (TypeSignature, TypeSignature), - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_name_used(&map_name)?; self.map_types.insert(map_name, map_type); Ok(()) @@ -132,7 +132,7 @@ impl ContractContext { &mut self, const_name: ClarityName, var_type: TypeSignature, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_name_used(&const_name)?; self.variable_types.insert(const_name, var_type); Ok(()) @@ -142,13 +142,13 @@ impl ContractContext { &mut self, var_name: ClarityName, var_type: TypeSignature, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_name_used(&var_name)?; self.persisted_variable_types.insert(var_name, var_type); Ok(()) } - pub fn add_ft(&mut self, token_name: ClarityName) -> Result<(), CheckError> { + pub fn add_ft(&mut self, token_name: ClarityName) -> Result<(), StaticCheckError> { self.check_name_used(&token_name)?; self.fungible_tokens.insert(token_name); Ok(()) @@ -158,7 +158,7 @@ impl ContractContext { &mut self, token_name: ClarityName, token_type: TypeSignature, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_name_used(&token_name)?; self.non_fungible_tokens.insert(token_name, token_type); Ok(()) @@ -168,7 +168,7 @@ impl ContractContext { &mut self, trait_name: ClarityName, trait_signature: BTreeMap, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.traits.insert(trait_name, trait_signature); Ok(()) } diff --git a/clarity/src/vm/analysis/type_checker/v2_05/mod.rs b/clarity/src/vm/analysis/type_checker/v2_05/mod.rs index 12686fea8ba..da3872048d9 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/mod.rs @@ -27,7 +27,8 @@ pub use self::natives::{SimpleNativeFunction, TypedNativeFunction}; use super::contexts::{TypeMap, TypingContext}; use super::ContractAnalysis; pub use crate::vm::analysis::errors::{ - check_argument_count, check_arguments_at_least, CheckError, CheckErrors, SyntaxBindingErrorType, + check_argument_count, check_arguments_at_least, CheckErrorKind, StaticCheckError, + SyntaxBindingErrorType, }; use crate::vm::analysis::AnalysisDatabase; use crate::vm::costs::cost_functions::ClarityCostFunction; @@ -114,7 +115,7 @@ impl TypeChecker<'_, '_> { contract_analysis: &mut ContractAnalysis, analysis_db: &mut AnalysisDatabase, build_type_map: bool, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { let cost_track = contract_analysis.take_contract_cost_tracker(); let mut command = TypeChecker::new(analysis_db, cost_track, build_type_map); // run the analysis, and replace the cost tracker whether or not the @@ -139,14 +140,14 @@ impl FunctionType { &self, accounting: &mut T, args: &[TypeSignature], - ) -> Result { + ) -> Result { match self { FunctionType::Variadic(expected_type, return_type) => { check_arguments_at_least(1, args)?; for found_type in args.iter() { analysis_typecheck_cost(accounting, expected_type, found_type)?; if !expected_type.admits_type(&StacksEpochId::Epoch2_05, found_type)? { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(found_type.clone()), ) @@ -164,7 +165,7 @@ impl FunctionType { { analysis_typecheck_cost(accounting, expected_type, found_type)?; if !expected_type.admits_type(&StacksEpochId::Epoch2_05, found_type)? { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(found_type.clone()), ) @@ -183,7 +184,7 @@ impl FunctionType { } } Err( - CheckErrors::UnionTypeError(arg_types.clone(), Box::new(found_type.clone())) + CheckErrorKind::UnionTypeError(arg_types.clone(), Box::new(found_type.clone())) .into(), ) } @@ -198,12 +199,12 @@ impl FunctionType { } let (first, rest) = args .split_first() - .ok_or(CheckErrors::RequiresAtLeastArguments(1, args.len()))?; + .ok_or(CheckErrorKind::RequiresAtLeastArguments(1, args.len()))?; analysis_typecheck_cost(accounting, &TypeSignature::IntType, first)?; let return_type = match first { TypeSignature::IntType => Ok(TypeSignature::IntType), TypeSignature::UIntType => Ok(TypeSignature::UIntType), - _ => Err(CheckErrors::UnionTypeError( + _ => Err(CheckErrorKind::UnionTypeError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(first.clone()), )), @@ -211,7 +212,7 @@ impl FunctionType { for found_type in rest.iter() { analysis_typecheck_cost(accounting, &TypeSignature::IntType, found_type)?; if found_type != &return_type { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(return_type), Box::new(found_type.clone()), ) @@ -227,7 +228,7 @@ impl FunctionType { analysis_typecheck_cost(accounting, &TypeSignature::IntType, second)?; if first != &TypeSignature::IntType && first != &TypeSignature::UIntType { - return Err(CheckErrors::UnionTypeError( + return Err(CheckErrorKind::UnionTypeError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(first.clone()), ) @@ -235,7 +236,7 @@ impl FunctionType { } if first != second { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(first.clone()), Box::new(second.clone()), ) @@ -244,9 +245,10 @@ impl FunctionType { Ok(TypeSignature::BoolType) } - FunctionType::Binary(_, _, _) => { - Err(CheckErrors::Expects("Binary type should not be reached in 2.05".into()).into()) - } + FunctionType::Binary(_, _, _) => Err(CheckErrorKind::Expects( + "Binary type should not be reached in 2.05".into(), + ) + .into()), } } @@ -254,10 +256,10 @@ impl FunctionType { &self, db: &mut AnalysisDatabase, func_args: &[Value], - ) -> Result { + ) -> Result { let (expected_args, returns) = match self { FunctionType::Fixed(FixedFunction { args, returns }) => (args, returns), - _ => return Err(CheckErrors::Expects("Unexpected function type".into()).into()), + _ => return Err(CheckErrorKind::Expects("Unexpected function type".into()).into()), }; check_argument_count(expected_args.len(), func_args)?; @@ -269,7 +271,7 @@ impl FunctionType { ) => { let contract_to_check = db .load_contract(contract, &StacksEpochId::Epoch2_05)? - .ok_or_else(|| CheckErrors::NoSuchContract(contract.name.to_string()))?; + .ok_or_else(|| CheckErrorKind::NoSuchContract(contract.name.to_string()))?; let trait_definition = db .get_defined_trait( &trait_id.contract_identifier, @@ -277,9 +279,9 @@ impl FunctionType { &StacksEpochId::Epoch2_05, ) .map_err(|_| { - CheckErrors::NoSuchContract(trait_id.contract_identifier.to_string()) + CheckErrorKind::NoSuchContract(trait_id.contract_identifier.to_string()) })? - .ok_or(CheckErrors::NoSuchContract( + .ok_or(CheckErrorKind::NoSuchContract( trait_id.contract_identifier.to_string(), ))?; contract_to_check.check_trait_compliance( @@ -291,7 +293,7 @@ impl FunctionType { (expected_type, value) => { if !expected_type.admits(&StacksEpochId::Epoch2_05, value)? { let actual_type = TypeSignature::type_of(value)?; - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(actual_type), ) @@ -306,7 +308,7 @@ impl FunctionType { fn trait_type_size( trait_sig: &BTreeMap, -) -> Result { +) -> Result { let mut total_size = 0; for (_func_name, value) in trait_sig.iter() { total_size = total_size.cost_overflow_add(value.total_type_size()?)?; @@ -314,7 +316,7 @@ fn trait_type_size( Ok(total_size) } -fn type_reserved_variable(variable_name: &str) -> Result, CheckError> { +fn type_reserved_variable(variable_name: &str) -> Result, StaticCheckError> { if let Some(variable) = NativeVariables::lookup_by_name_at_version(variable_name, &ClarityVersion::Clarity1) { @@ -325,13 +327,13 @@ fn type_reserved_variable(variable_name: &str) -> Result, BlockHeight => TypeSignature::UIntType, BurnBlockHeight => TypeSignature::UIntType, NativeNone => TypeSignature::new_option(no_type()) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, NativeTrue => TypeSignature::BoolType, NativeFalse => TypeSignature::BoolType, TotalLiquidMicroSTX => TypeSignature::UIntType, Regtest => TypeSignature::BoolType, TxSponsor | Mainnet | ChainId | StacksBlockHeight | TenureHeight | StacksBlockTime | CurrentContract => { - return Err(CheckErrors::Expects( + return Err(CheckErrorKind::Expects( "tx-sponsor, mainnet, chain-id, stacks-block-height, tenure-height, stacks-block-time, and current-contract should not reach here in 2.05".into(), ) .into()) @@ -372,7 +374,10 @@ impl<'a, 'b> TypeChecker<'a, 'b> { self.cost_track } - pub fn track_return_type(&mut self, return_type: TypeSignature) -> Result<(), CheckError> { + pub fn track_return_type( + &mut self, + return_type: TypeSignature, + ) -> Result<(), StaticCheckError> { runtime_cost( ClarityCostFunction::AnalysisTypeCheck, self, @@ -388,7 +393,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &return_type, ) .map_err(|_| { - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( Box::new(expected_type), Box::new(return_type), ) @@ -407,7 +412,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { } } - pub fn run(&mut self, contract_analysis: &ContractAnalysis) -> Result<(), CheckError> { + pub fn run(&mut self, contract_analysis: &ContractAnalysis) -> Result<(), StaticCheckError> { // charge for the eventual storage cost of the analysis -- // it is linear in the size of the AST. let mut size: u64 = 0; @@ -419,7 +424,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { } Err(e) => Err(e), })? - .ok_or_else(|| CheckErrors::Expects("Expected a depth result".into()))?; + .ok_or_else(|| CheckErrorKind::Expects("Expected a depth result".into()))?; } runtime_cost(ClarityCostFunction::AnalysisStorage, self, size)?; @@ -449,7 +454,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { expr: &SymbolicExpression, context: &TypingContext, expected_type: &TypeSignature, - ) -> Result { + ) -> Result { if let ( LiteralValue(Value::Principal(PrincipalData::Contract(ref contract_identifier))), TypeSignature::TraitReferenceType(trait_identifier), @@ -458,7 +463,9 @@ impl<'a, 'b> TypeChecker<'a, 'b> { let contract_to_check = self .db .load_contract(contract_identifier, &StacksEpochId::Epoch2_05)? - .ok_or(CheckErrors::NoSuchContract(contract_identifier.to_string()))?; + .ok_or(CheckErrorKind::NoSuchContract( + contract_identifier.to_string(), + ))?; let contract_defining_trait = self .db @@ -466,13 +473,13 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &trait_identifier.contract_identifier, &StacksEpochId::Epoch2_05, )? - .ok_or(CheckErrors::NoSuchContract( + .ok_or(CheckErrorKind::NoSuchContract( trait_identifier.contract_identifier.to_string(), ))?; let trait_definition = contract_defining_trait .get_defined_trait(&trait_identifier.name) - .ok_or(CheckErrors::NoSuchTrait( + .ok_or(CheckErrorKind::NoSuchTrait( trait_identifier.contract_identifier.to_string(), trait_identifier.name.to_string(), ))?; @@ -489,8 +496,8 @@ impl<'a, 'b> TypeChecker<'a, 'b> { analysis_typecheck_cost(self, expected_type, &actual_type)?; if !expected_type.admits_type(&StacksEpochId::Epoch2_05, &actual_type)? { - let mut err: CheckError = - CheckErrors::TypeError(Box::new(expected_type.clone()), Box::new(actual_type)) + let mut err: StaticCheckError = + CheckErrorKind::TypeError(Box::new(expected_type.clone()), Box::new(actual_type)) .into(); err.set_expression(expr); Err(err) @@ -504,7 +511,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, expr: &SymbolicExpression, context: &TypingContext, - ) -> Result { + ) -> Result { runtime_cost(ClarityCostFunction::AnalysisVisit, self, 0)?; let mut result = self.inner_type_check(expr, context); @@ -522,16 +529,16 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, args: &[SymbolicExpression], context: &TypingContext, - ) -> Result { + ) -> Result { let mut types_returned = self.type_check_all(args, context)?; - let last_return = types_returned - .pop() - .ok_or(CheckError::new(CheckErrors::CheckerImplementationFailure))?; + let last_return = types_returned.pop().ok_or(StaticCheckError::new( + CheckErrorKind::CheckerImplementationFailure, + ))?; for type_return in types_returned.iter() { if type_return.is_response_type() { - return Err(CheckErrors::UncheckedIntermediaryResponses.into()); + return Err(CheckErrorKind::UncheckedIntermediaryResponses.into()); } } Ok(last_return) @@ -541,7 +548,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, args: &[SymbolicExpression], context: &TypingContext, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { let mut result = Vec::with_capacity(args.len()); for arg in args.iter() { // don't use map here, since type_check has side-effects. @@ -555,7 +562,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { func_type: &FunctionType, args: &[SymbolicExpression], context: &TypingContext, - ) -> Result { + ) -> Result { let typed_args = self.type_check_all(args, context)?; func_type.check_args(self, &typed_args, context.epoch, context.clarity_version) } @@ -571,14 +578,14 @@ impl<'a, 'b> TypeChecker<'a, 'b> { signature: &[SymbolicExpression], body: &SymbolicExpression, context: &TypingContext, - ) -> Result<(ClarityName, FixedFunction), CheckError> { + ) -> Result<(ClarityName, FixedFunction), StaticCheckError> { let (function_name, args) = signature .split_first() - .ok_or(CheckErrors::RequiresAtLeastArguments(1, 0))?; + .ok_or(CheckErrorKind::RequiresAtLeastArguments(1, 0))?; let function_name = function_name .match_atom() - .ok_or(CheckErrors::BadFunctionName)?; - let args = parse_name_type_pairs::<(), CheckError>( + .ok_or(CheckErrorKind::BadFunctionName)?; + let args = parse_name_type_pairs::<(), StaticCheckError>( StacksEpochId::Epoch2_05, args, SyntaxBindingErrorType::Eval, @@ -586,7 +593,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { )?; if self.function_return_tracker.is_some() { - return Err(CheckErrors::Expects( + return Err(CheckErrorKind::Expects( "Interpreter error: Previous function define left dirty typecheck state.".into(), ) .into()); @@ -628,7 +635,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &return_type, ) .map_err(|_| { - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( Box::new(expected.clone()), Box::new(return_type), ) @@ -661,16 +668,16 @@ impl<'a, 'b> TypeChecker<'a, 'b> { map_name: &ClarityName, key_type: &SymbolicExpression, value_type: &SymbolicExpression, - ) -> Result<(ClarityName, (TypeSignature, TypeSignature)), CheckError> { + ) -> Result<(ClarityName, (TypeSignature, TypeSignature)), StaticCheckError> { self.type_map.set_type(key_type, no_type())?; self.type_map.set_type(value_type, no_type())?; // should we set the type of the subexpressions of the signature to no-type as well? let key_type = TypeSignature::parse_type_repr(StacksEpochId::Epoch2_05, key_type, &mut ()) - .map_err(|_| CheckErrors::BadMapTypeDefinition)?; + .map_err(|_| CheckErrorKind::BadMapTypeDefinition)?; let value_type = TypeSignature::parse_type_repr(StacksEpochId::Epoch2_05, value_type, &mut ()) - .map_err(|_| CheckErrors::BadMapTypeDefinition)?; + .map_err(|_| CheckErrorKind::BadMapTypeDefinition)?; Ok((map_name.clone(), (key_type, value_type))) } @@ -681,7 +688,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { function: &str, args: &[SymbolicExpression], context: &TypingContext, - ) -> Option> { + ) -> Option> { if let Some(ref native_function) = NativeFunctions::lookup_by_name_at_version(function, &ClarityVersion::Clarity1) { @@ -699,22 +706,22 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, expression: &[SymbolicExpression], context: &TypingContext, - ) -> Result { + ) -> Result { let (function_name, args) = expression .split_first() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; self.type_map.set_type(function_name, no_type())?; let function_name = function_name .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; if let Some(type_result) = self.try_native_function_check(function_name, args, context) { type_result } else { let function = match self.get_function_type(function_name) { Some(FunctionType::Fixed(function)) => Ok(function), - _ => Err(CheckErrors::UnknownFunction(function_name.to_string())), + _ => Err(CheckErrorKind::UnknownFunction(function_name.to_string())), }?; for (expected_type, found_type) in function.args.iter().map(|x| &x.signature).zip(args) @@ -730,7 +737,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, name: &str, context: &TypingContext, - ) -> Result { + ) -> Result { runtime_cost(ClarityCostFunction::AnalysisLookupVariableConst, self, 0)?; if let Some(type_result) = type_reserved_variable(name)? { @@ -744,7 +751,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { // be undefined. This early error prevents a cost function error // due to `context.depth` being 0. if context.depth == 0 { - return Err(CheckErrors::UndefinedVariable(name.to_string()).into()); + return Err(CheckErrorKind::UndefinedVariable(name.to_string()).into()); } runtime_cost( @@ -756,7 +763,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { if let Some(type_result) = context.lookup_variable_type(name) { Ok(type_result.clone()) } else { - Err(CheckErrors::UndefinedVariable(name.to_string()).into()) + Err(CheckErrorKind::UndefinedVariable(name.to_string()).into()) } } } @@ -765,13 +772,13 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, expr: &SymbolicExpression, context: &TypingContext, - ) -> Result { + ) -> Result { let type_sig = match expr.expr { AtomValue(ref value) | LiteralValue(ref value) => TypeSignature::type_of(value)?, Atom(ref name) => self.lookup_variable(name, context)?, List(ref expression) => self.type_check_function_application(expression, context)?, TraitReference(_, _) | Field(_) => { - return Err(CheckErrors::UnexpectedTraitOrFieldReference.into()); + return Err(CheckErrorKind::UnexpectedTraitOrFieldReference.into()); } }; @@ -789,7 +796,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { var_name: &ClarityName, var_type: &SymbolicExpression, context: &mut TypingContext, - ) -> Result<(ClarityName, TypeSignature), CheckError> { + ) -> Result<(ClarityName, TypeSignature), StaticCheckError> { let var_type = self.type_check(var_type, context)?; Ok((var_name.clone(), var_type)) } @@ -800,10 +807,10 @@ impl<'a, 'b> TypeChecker<'a, 'b> { var_type: &SymbolicExpression, initial: &SymbolicExpression, context: &mut TypingContext, - ) -> Result<(ClarityName, TypeSignature), CheckError> { + ) -> Result<(ClarityName, TypeSignature), StaticCheckError> { let expected_type = TypeSignature::parse_type_repr::<()>(StacksEpochId::Epoch2_05, var_type, &mut ()) - .map_err(|_e| CheckErrors::DefineVariableBadSignature)?; + .map_err(|_e| CheckErrorKind::DefineVariableBadSignature)?; self.type_check_expects(initial, context, &expected_type)?; @@ -815,7 +822,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { token_name: &ClarityName, bound: Option<&SymbolicExpression>, context: &mut TypingContext, - ) -> Result { + ) -> Result { if let Some(bound) = bound { self.type_check_expects(bound, context, &TypeSignature::UIntType)?; } @@ -828,10 +835,10 @@ impl<'a, 'b> TypeChecker<'a, 'b> { asset_name: &ClarityName, nft_type: &SymbolicExpression, _context: &mut TypingContext, - ) -> Result<(ClarityName, TypeSignature), CheckError> { + ) -> Result<(ClarityName, TypeSignature), StaticCheckError> { let asset_type = TypeSignature::parse_type_repr::<()>(StacksEpochId::Epoch2_05, nft_type, &mut ()) - .map_err(|_| CheckErrors::DefineNFTBadSignature)?; + .map_err(|_| CheckErrorKind::DefineNFTBadSignature)?; Ok((asset_name.clone(), asset_type)) } @@ -841,7 +848,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { trait_name: &ClarityName, function_types: &[SymbolicExpression], _context: &mut TypingContext, - ) -> Result<(ClarityName, BTreeMap), CheckError> { + ) -> Result<(ClarityName, BTreeMap), StaticCheckError> { let trait_signature = TypeSignature::parse_trait_type_repr( function_types, &mut (), @@ -857,7 +864,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, expression: &SymbolicExpression, context: &mut TypingContext, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { if let Some(define_type) = DefineFunctionsParsed::try_parse(expression)? { match define_type { DefineFunctionsParsed::Constant { name, value } => { @@ -895,7 +902,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { .add_public_function_type(f_name, FunctionType::Fixed(f_type))?; return Ok(Some(())); } else { - return Err(CheckErrors::PublicFunctionMustReturnResponse(Box::new( + return Err(CheckErrorKind::PublicFunctionMustReturnResponse(Box::new( f_type.returns, )) .into()); @@ -1002,7 +1009,9 @@ impl<'a, 'b> TypeChecker<'a, 'b> { None => { // still had to do a db read, even if it didn't exist! runtime_cost(ClarityCostFunction::AnalysisUseTraitEntry, self, 1)?; - return Err(CheckErrors::TraitReferenceUnknown(name.to_string()).into()); + return Err( + CheckErrorKind::TraitReferenceUnknown(name.to_string()).into() + ); } } } diff --git a/clarity/src/vm/analysis/type_checker/v2_05/natives/assets.rs b/clarity/src/vm/analysis/type_checker/v2_05/natives/assets.rs index 13f967e6af3..74680694340 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/natives/assets.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/natives/assets.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use super::{TypeChecker, TypingContext}; -use crate::vm::analysis::errors::{check_argument_count, CheckError, CheckErrors}; +use crate::vm::analysis::errors::{check_argument_count, CheckErrorKind, StaticCheckError}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; use crate::vm::representations::SymbolicExpression; @@ -25,16 +25,16 @@ pub fn check_special_get_owner( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_asset_type = checker .contract_context .get_nft_type(asset_name) .cloned() - .ok_or_else(|| CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or_else(|| CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -53,13 +53,13 @@ pub fn check_special_get_balance( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; if !checker.contract_context.ft_exists(asset_name) { - return Err(CheckErrors::NoSuchFT(asset_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(asset_name.to_string()).into()); } runtime_cost(ClarityCostFunction::AnalysisTypeLookup, checker, 1)?; @@ -74,16 +74,16 @@ pub fn check_special_mint_asset( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; let expected_asset_type = checker .contract_context .get_nft_type(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))? + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))? .clone(); // this clone shouldn't be strictly necessary, but to use `type_check_expects` with this, it would have to be. runtime_cost( @@ -105,10 +105,10 @@ pub fn check_special_mint_token( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_amount: TypeSignature = TypeSignature::UIntType; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; @@ -119,7 +119,7 @@ pub fn check_special_mint_token( checker.type_check_expects(&args[2], context, &expected_owner_type)?; if !checker.contract_context.ft_exists(asset_name) { - return Err(CheckErrors::NoSuchFT(asset_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(asset_name.to_string()).into()); } Ok(TypeSignature::ResponseType(Box::new(( @@ -132,16 +132,16 @@ pub fn check_special_transfer_asset( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; let expected_asset_type = checker .contract_context .get_nft_type(token_name) - .ok_or(CheckErrors::NoSuchNFT(token_name.to_string()))? + .ok_or(CheckErrorKind::NoSuchNFT(token_name.to_string()))? .clone(); runtime_cost( @@ -164,10 +164,10 @@ pub fn check_special_transfer_token( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_amount: TypeSignature = TypeSignature::UIntType; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; @@ -179,7 +179,7 @@ pub fn check_special_transfer_token( checker.type_check_expects(&args[3], context, &expected_owner_type)?; // recipient if !checker.contract_context.ft_exists(token_name) { - return Err(CheckErrors::NoSuchFT(token_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(token_name.to_string()).into()); } Ok(TypeSignature::ResponseType(Box::new(( @@ -192,13 +192,13 @@ pub fn check_special_get_token_supply( checker: &mut TypeChecker, args: &[SymbolicExpression], _context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; if !checker.contract_context.ft_exists(asset_name) { - return Err(CheckErrors::NoSuchFT(asset_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(asset_name.to_string()).into()); } runtime_cost(ClarityCostFunction::AnalysisTypeLookup, checker, 1)?; @@ -210,16 +210,16 @@ pub fn check_special_burn_asset( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; let expected_asset_type = checker .contract_context .get_nft_type(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))? + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))? .clone(); // this clone shouldn't be strictly necessary, but to use `type_check_expects` with this, it would have to be. runtime_cost( @@ -241,10 +241,10 @@ pub fn check_special_burn_token( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_amount: TypeSignature = TypeSignature::UIntType; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; @@ -255,7 +255,7 @@ pub fn check_special_burn_token( checker.type_check_expects(&args[2], context, &expected_owner_type)?; if !checker.contract_context.ft_exists(asset_name) { - return Err(CheckErrors::NoSuchFT(asset_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(asset_name.to_string()).into()); } Ok(TypeSignature::ResponseType(Box::new(( diff --git a/clarity/src/vm/analysis/type_checker/v2_05/natives/maps.rs b/clarity/src/vm/analysis/type_checker/v2_05/natives/maps.rs index ccbf880e179..e454e424f10 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/natives/maps.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/natives/maps.rs @@ -17,7 +17,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::analysis::type_checker::v2_05::{ - check_arguments_at_least, CheckError, CheckErrors, TypeChecker, TypingContext, + check_arguments_at_least, CheckErrorKind, StaticCheckError, TypeChecker, TypingContext, }; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{analysis_typecheck_cost, runtime_cost}; @@ -28,17 +28,17 @@ pub fn check_special_fetch_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::BadMapName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::BadMapName)?; let key_type = checker.type_check(&args[1], context)?; let (expected_key_type, value_type) = checker .contract_context .get_map_type(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -55,7 +55,7 @@ pub fn check_special_fetch_entry( let option_type = TypeSignature::new_option(value_type.clone())?; if !expected_key_type.admits_type(&StacksEpochId::Epoch2_05, &key_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_key_type.clone()), Box::new(key_type), ))) @@ -68,17 +68,17 @@ pub fn check_special_delete_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::BadMapName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::BadMapName)?; let key_type = checker.type_check(&args[1], context)?; let (expected_key_type, _) = checker .contract_context .get_map_type(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -88,7 +88,7 @@ pub fn check_special_delete_entry( analysis_typecheck_cost(&mut checker.cost_track, expected_key_type, &key_type)?; if !expected_key_type.admits_type(&StacksEpochId::Epoch2_05, &key_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_key_type.clone()), Box::new(key_type), ))) @@ -101,10 +101,10 @@ fn check_set_or_insert_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(3, args)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::BadMapName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::BadMapName)?; let key_type = checker.type_check(&args[1], context)?; let value_type = checker.type_check(&args[2], context)?; @@ -112,7 +112,7 @@ fn check_set_or_insert_entry( let (expected_key_type, expected_value_type) = checker .contract_context .get_map_type(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -129,12 +129,12 @@ fn check_set_or_insert_entry( analysis_typecheck_cost(&mut checker.cost_track, expected_value_type, &value_type)?; if !expected_key_type.admits_type(&StacksEpochId::Epoch2_05, &key_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_key_type.clone()), Box::new(key_type), ))) } else if !expected_value_type.admits_type(&StacksEpochId::Epoch2_05, &value_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_value_type.clone()), Box::new(value_type), ))) @@ -147,7 +147,7 @@ pub fn check_special_set_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_set_or_insert_entry(checker, args, context) } @@ -155,6 +155,6 @@ pub fn check_special_insert_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_set_or_insert_entry(checker, args, context) } diff --git a/clarity/src/vm/analysis/type_checker/v2_05/natives/mod.rs b/clarity/src/vm/analysis/type_checker/v2_05/natives/mod.rs index 059434f3937..3cbe844478e 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/natives/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/natives/mod.rs @@ -17,7 +17,7 @@ use stacks_common::types::StacksEpochId; use super::{check_argument_count, check_arguments_at_least, no_type, TypeChecker, TypingContext}; -use crate::vm::analysis::errors::{CheckError, CheckErrors, SyntaxBindingErrorType}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError, SyntaxBindingErrorType}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{analysis_typecheck_cost, runtime_cost}; use crate::vm::diagnostic::DiagnosableError; @@ -45,7 +45,7 @@ pub struct SpecialNativeFunction( &mut TypeChecker, &[SymbolicExpression], &TypingContext, - ) -> Result, + ) -> Result, ); pub struct SimpleNativeFunction(pub FunctionType); @@ -53,7 +53,7 @@ fn check_special_list_cons( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { let typed_args = checker.type_check_all(args, context)?; for type_arg in typed_args.iter() { runtime_cost( @@ -70,7 +70,7 @@ fn check_special_print( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; checker.type_check(&args[0], context) } @@ -79,7 +79,7 @@ fn check_special_as_contract( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; checker.type_check(&args[0], context) } @@ -88,7 +88,7 @@ fn check_special_at_block( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_32)?; checker.type_check(&args[1], context) @@ -98,7 +98,7 @@ fn check_special_begin( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; checker.type_check_consecutive_statements(args, context) @@ -108,7 +108,7 @@ fn inner_handle_tuple_get( tuple_type_sig: &TupleTypeSignature, field_to_get: &str, checker: &mut TypeChecker, -) -> Result { +) -> Result { runtime_cost( ClarityCostFunction::AnalysisCheckTupleGet, checker, @@ -117,7 +117,7 @@ fn inner_handle_tuple_get( let return_type = tuple_type_sig .field_type(field_to_get) - .ok_or(CheckError::new(CheckErrors::NoSuchTupleField( + .ok_or(StaticCheckError::new(CheckErrorKind::NoSuchTupleField( field_to_get.to_string(), tuple_type_sig.clone(), )))? @@ -129,10 +129,12 @@ fn check_special_get( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let field_to_get = args[0].match_atom().ok_or(CheckErrors::BadTupleFieldName)?; + let field_to_get = args[0] + .match_atom() + .ok_or(CheckErrorKind::BadTupleFieldName)?; let argument_type = checker.type_check(&args[1], context)?; @@ -144,10 +146,10 @@ fn check_special_get( let option_type = TypeSignature::new_option(inner_type)?; Ok(option_type) } else { - Err(CheckErrors::ExpectedTuple(value_type_sig).into()) + Err(CheckErrorKind::ExpectedTuple(value_type_sig).into()) } } else { - Err(CheckErrors::ExpectedTuple(Box::new(argument_type)).into()) + Err(CheckErrorKind::ExpectedTuple(Box::new(argument_type)).into()) } } @@ -155,19 +157,19 @@ fn check_special_merge( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let res = checker.type_check(&args[0], context)?; let mut base = match res { TypeSignature::TupleType(tuple_sig) => Ok(tuple_sig), - _ => Err(CheckErrors::ExpectedTuple(Box::new(res.clone()))), + _ => Err(CheckErrorKind::ExpectedTuple(Box::new(res.clone()))), }?; let res = checker.type_check(&args[1], context)?; let mut update = match res { TypeSignature::TupleType(tuple_sig) => Ok(tuple_sig), - _ => Err(CheckErrors::ExpectedTuple(Box::new(res.clone()))), + _ => Err(CheckErrorKind::ExpectedTuple(Box::new(res.clone()))), }?; runtime_cost( ClarityCostFunction::AnalysisCheckTupleMerge, @@ -183,7 +185,7 @@ pub fn check_special_tuple_cons( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; let len = args.len(); @@ -208,7 +210,7 @@ pub fn check_special_tuple_cons( )?; let tuple_signature = TupleTypeSignature::try_from(tuple_type_data) - .map_err(|e| CheckErrors::BadTupleConstruction(e.message()))?; + .map_err(|e| CheckErrorKind::BadTupleConstruction(e.message()))?; Ok(TypeSignature::TupleType(tuple_signature)) } @@ -217,12 +219,12 @@ fn check_special_let( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; let binding_list = args[0] .match_list() - .ok_or(CheckError::new(CheckErrors::BadLetSyntax))?; + .ok_or(StaticCheckError::new(CheckErrorKind::BadLetSyntax))?; let mut out_context = context.extend()?; @@ -234,7 +236,7 @@ fn check_special_let( |var_name, var_sexp| { checker.contract_context.check_name_used(var_name)?; if out_context.lookup_variable_type(var_name).is_some() { - return Err(CheckError::new(CheckErrors::NameAlreadyUsed( + return Err(StaticCheckError::new(CheckErrorKind::NameAlreadyUsed( var_name.to_string(), ))); } @@ -260,17 +262,17 @@ fn check_special_fetch_var( checker: &mut TypeChecker, args: &[SymbolicExpression], _context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let var_name = args[0] .match_atom() - .ok_or(CheckError::new(CheckErrors::BadMapName))?; + .ok_or(StaticCheckError::new(CheckErrorKind::BadMapName))?; let value_type = checker .contract_context .get_persisted_variable_type(var_name) - .ok_or(CheckError::new(CheckErrors::NoSuchDataVariable( + .ok_or(StaticCheckError::new(CheckErrorKind::NoSuchDataVariable( var_name.to_string(), )))?; @@ -287,17 +289,17 @@ fn check_special_set_var( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let var_name = args[0].match_atom().ok_or(CheckErrors::BadMapName)?; + let var_name = args[0].match_atom().ok_or(CheckErrorKind::BadMapName)?; let value_type = checker.type_check(&args[1], context)?; let expected_value_type = checker .contract_context .get_persisted_variable_type(var_name) - .ok_or(CheckErrors::NoSuchDataVariable(var_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchDataVariable(var_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -307,7 +309,7 @@ fn check_special_set_var( analysis_typecheck_cost(&mut checker.cost_track, &value_type, expected_value_type)?; if !expected_value_type.admits_type(&StacksEpochId::Epoch2_05, &value_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_value_type.clone()), Box::new(value_type), ))) @@ -320,7 +322,7 @@ fn check_special_equals( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; let arg_types = checker.type_check_all(args, context)?; @@ -329,7 +331,7 @@ fn check_special_equals( for x_type in arg_types.into_iter() { analysis_typecheck_cost(checker, &x_type, &arg_type)?; arg_type = TypeSignature::least_supertype(&StacksEpochId::Epoch2_05, &x_type, &arg_type) - .map_err(|_| CheckErrors::TypeError(Box::new(x_type), Box::new(arg_type)))?; + .map_err(|_| CheckErrorKind::TypeError(Box::new(x_type), Box::new(arg_type)))?; } Ok(TypeSignature::BoolType) @@ -339,7 +341,7 @@ fn check_special_if( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BoolType)?; @@ -352,7 +354,7 @@ fn check_special_if( analysis_typecheck_cost(checker, expr1, expr2)?; TypeSignature::least_supertype(&StacksEpochId::Epoch2_05, expr1, expr2).map_err(|_| { - CheckErrors::IfArmsMustMatch(Box::new(expr1.clone()), Box::new(expr2.clone())).into() + CheckErrorKind::IfArmsMustMatch(Box::new(expr1.clone()), Box::new(expr2.clone())).into() }) } @@ -360,12 +362,12 @@ fn check_contract_call( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let func_name = args[1] - .match_atom() - .ok_or(CheckError::new(CheckErrors::ContractCallExpectName))?; + let func_name = args[1].match_atom().ok_or(StaticCheckError::new( + CheckErrorKind::ContractCallExpectName, + ))?; checker.type_map.set_type(&args[1], no_type())?; let expected_sig = match &args[0].expr { @@ -389,7 +391,7 @@ fn check_contract_call( { Ok(function) } else { - Err(CheckError::new(CheckErrors::NoSuchPublicFunction( + Err(StaticCheckError::new(CheckErrorKind::NoSuchPublicFunction( contract_identifier.to_string(), func_name.to_string(), ))) @@ -412,7 +414,7 @@ fn check_contract_call( Some(trait_id) => trait_id, _ => { return Err( - CheckErrors::TraitReferenceUnknown(trait_instance.to_string()).into(), + CheckErrorKind::TraitReferenceUnknown(trait_instance.to_string()).into(), ); } }; @@ -420,12 +422,12 @@ fn check_contract_call( runtime_cost(ClarityCostFunction::AnalysisLookupFunction, checker, 0)?; let trait_signature = checker.contract_context.get_trait(&trait_id.name).ok_or( - CheckErrors::TraitReferenceUnknown(trait_id.name.to_string()), + CheckErrorKind::TraitReferenceUnknown(trait_id.name.to_string()), )?; let func_signature = trait_signature .get(func_name) - .ok_or(CheckErrors::TraitMethodUnknown( + .ok_or(CheckErrorKind::TraitMethodUnknown( trait_id.name.to_string(), func_name.to_string(), ))?; @@ -438,7 +440,11 @@ fn check_contract_call( func_signature.clone() } - _ => return Err(CheckError::new(CheckErrors::ContractCallExpectName)), + _ => { + return Err(StaticCheckError::new( + CheckErrorKind::ContractCallExpectName, + )) + } }; check_argument_count(expected_sig.args.len(), &args[2..])?; @@ -453,17 +459,21 @@ fn check_contract_of( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let trait_instance = match &args[0].expr { SymbolicExpressionType::Atom(trait_instance) => trait_instance, - _ => return Err(CheckError::new(CheckErrors::ContractOfExpectsTrait)), + _ => { + return Err(StaticCheckError::new( + CheckErrorKind::ContractOfExpectsTrait, + )) + } }; let trait_id = match context.lookup_trait_reference_type(trait_instance) { Some(trait_id) => trait_id, - _ => return Err(CheckErrors::TraitReferenceUnknown(trait_instance.to_string()).into()), + _ => return Err(CheckErrorKind::TraitReferenceUnknown(trait_instance.to_string()).into()), }; runtime_cost(ClarityCostFunction::ContractOf, checker, 1)?; @@ -471,7 +481,7 @@ fn check_contract_of( checker .contract_context .get_trait(&trait_id.name) - .ok_or_else(|| CheckErrors::TraitReferenceUnknown(trait_id.name.to_string()))?; + .ok_or_else(|| CheckErrorKind::TraitReferenceUnknown(trait_id.name.to_string()))?; Ok(TypeSignature::PrincipalType) } @@ -480,12 +490,12 @@ fn check_principal_of( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_33)?; Ok( TypeSignature::new_response(TypeSignature::PrincipalType, TypeSignature::UIntType) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, ) } @@ -493,13 +503,13 @@ fn check_secp256k1_recover( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_32)?; checker.type_check_expects(&args[1], context, &TypeSignature::BUFFER_65)?; Ok( TypeSignature::new_response(TypeSignature::BUFFER_33, TypeSignature::UIntType) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, ) } @@ -507,7 +517,7 @@ fn check_secp256k1_verify( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_32)?; checker.type_check_expects(&args[1], context, &TypeSignature::BUFFER_65)?; @@ -519,20 +529,20 @@ fn check_get_block_info( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let block_info_prop_str = args[0] - .match_atom() - .ok_or(CheckError::new(CheckErrors::GetBlockInfoExpectPropertyName))?; + let block_info_prop_str = args[0].match_atom().ok_or(StaticCheckError::new( + CheckErrorKind::GetBlockInfoExpectPropertyName, + ))?; let block_info_prop = BlockInfoProperty::lookup_by_name_at_version( block_info_prop_str, &ClarityVersion::Clarity1, ) - .ok_or(CheckError::new(CheckErrors::NoSuchBlockInfoProperty( - block_info_prop_str.to_string(), - )))?; + .ok_or(StaticCheckError::new( + CheckErrorKind::NoSuchBlockInfoProperty(block_info_prop_str.to_string()), + ))?; checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; @@ -545,7 +555,7 @@ impl TypedNativeFunction { checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, - ) -> Result { + ) -> Result { use self::TypedNativeFunction::{Simple, Special}; match self { Special(SpecialNativeFunction(check)) => check(checker, args, context), @@ -557,7 +567,7 @@ impl TypedNativeFunction { pub fn type_native_function( function: &NativeFunctions, - ) -> Result { + ) -> Result { use self::TypedNativeFunction::{Simple, Special}; use crate::vm::functions::NativeFunctions::*; let out = match function { @@ -579,7 +589,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::IntType, ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -590,7 +600,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::UIntType, ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -601,7 +611,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::BoolType, ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -654,7 +664,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("owner".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -666,7 +676,7 @@ impl TypedNativeFunction { FunctionArg::new( TypeSignature::UIntType, ClarityName::try_from("amount".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -674,7 +684,7 @@ impl TypedNativeFunction { FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("sender".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -682,7 +692,7 @@ impl TypedNativeFunction { FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("recipient".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -692,14 +702,14 @@ impl TypedNativeFunction { TypeSignature::BoolType, TypeSignature::UIntType, ) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, }))), StxBurn => Simple(SimpleNativeFunction(FunctionType::Fixed(FixedFunction { args: vec![ FunctionArg::new( TypeSignature::UIntType, ClarityName::try_from("amount".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -707,7 +717,7 @@ impl TypedNativeFunction { FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("sender".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -717,7 +727,7 @@ impl TypedNativeFunction { TypeSignature::BoolType, TypeSignature::UIntType, ) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, }))), GetTokenBalance => Special(SpecialNativeFunction(&assets::check_special_get_balance)), GetAssetOwner => Special(SpecialNativeFunction(&assets::check_special_get_owner)), @@ -815,7 +825,7 @@ impl TypedNativeFunction { | AllowanceWithStacking | AllowanceAll | Secp256r1Verify => { - return Err(CheckErrors::Expects( + return Err(CheckErrorKind::Expects( "Clarity 2+ keywords should not show up in 2.05".into(), )); } diff --git a/clarity/src/vm/analysis/type_checker/v2_05/natives/options.rs b/clarity/src/vm/analysis/type_checker/v2_05/natives/options.rs index 1cf9b301a7d..73a4d87f649 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/natives/options.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/natives/options.rs @@ -19,8 +19,8 @@ use clarity_types::types::TypeSignature; use stacks_common::types::StacksEpochId; use crate::vm::analysis::type_checker::v2_05::{ - check_argument_count, check_arguments_at_least, no_type, CheckError, CheckErrors, TypeChecker, - TypingContext, + check_argument_count, check_arguments_at_least, no_type, CheckErrorKind, StaticCheckError, + TypeChecker, TypingContext, }; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{analysis_typecheck_cost, runtime_cost}; @@ -30,7 +30,7 @@ pub fn check_special_okay( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::AnalysisOptionCons, checker, 0)?; @@ -44,7 +44,7 @@ pub fn check_special_some( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::AnalysisOptionCons, checker, 0)?; @@ -58,7 +58,7 @@ pub fn check_special_error( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::AnalysisOptionCons, checker, 0)?; @@ -72,7 +72,7 @@ pub fn check_special_is_response( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -82,7 +82,7 @@ pub fn check_special_is_response( if let TypeSignature::ResponseType(_types) = input { Ok(TypeSignature::BoolType) } else { - Err(CheckErrors::ExpectedResponseType(Box::new(input)).into()) + Err(CheckErrorKind::ExpectedResponseType(Box::new(input)).into()) } } @@ -90,7 +90,7 @@ pub fn check_special_is_optional( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -100,7 +100,7 @@ pub fn check_special_is_optional( if let TypeSignature::OptionalType(_type) = input { Ok(TypeSignature::BoolType) } else { - Err(CheckErrors::ExpectedOptionalType(Box::new(input)).into()) + Err(CheckErrorKind::ExpectedOptionalType(Box::new(input)).into()) } } @@ -108,7 +108,7 @@ pub fn check_special_default_to( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let default = checker.type_check(&args[0], context)?; @@ -120,11 +120,11 @@ pub fn check_special_default_to( let contained_type = *input_type; TypeSignature::least_supertype(&StacksEpochId::Epoch2_05, &default, &contained_type) .map_err(|_| { - CheckErrors::DefaultTypesMustMatch(Box::new(default), Box::new(contained_type)) + CheckErrorKind::DefaultTypesMustMatch(Box::new(default), Box::new(contained_type)) .into() }) } else { - Err(CheckErrors::ExpectedOptionalType(Box::new(input)).into()) + Err(CheckErrorKind::ExpectedOptionalType(Box::new(input)).into()) } } @@ -132,7 +132,7 @@ pub fn check_special_asserts( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BoolType)?; @@ -146,13 +146,13 @@ pub fn check_special_asserts( fn inner_unwrap( input: TypeSignature, checker: &mut TypeChecker, -) -> Result { +) -> Result { runtime_cost(ClarityCostFunction::AnalysisOptionCheck, checker, 0)?; match input { TypeSignature::OptionalType(input_type) => { if input_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseOkType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseOkType.into()) } else { Ok(*input_type) } @@ -160,30 +160,30 @@ fn inner_unwrap( TypeSignature::ResponseType(response_type) => { let ok_type = response_type.0; if ok_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseOkType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseOkType.into()) } else { Ok(ok_type) } } - _ => Err(CheckErrors::ExpectedOptionalOrResponseType(Box::new(input)).into()), + _ => Err(CheckErrorKind::ExpectedOptionalOrResponseType(Box::new(input)).into()), } } fn inner_unwrap_err( input: TypeSignature, checker: &mut TypeChecker, -) -> Result { +) -> Result { runtime_cost(ClarityCostFunction::AnalysisOptionCheck, checker, 0)?; if let TypeSignature::ResponseType(response_type) = input { let err_type = response_type.1; if err_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseErrType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseErrType.into()) } else { Ok(err_type) } } else { - Err(CheckErrors::ExpectedResponseType(Box::new(input)).into()) + Err(CheckErrorKind::ExpectedResponseType(Box::new(input)).into()) } } @@ -191,7 +191,7 @@ pub fn check_special_unwrap_or_ret( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let input = checker.type_check(&args[0], context)?; @@ -206,7 +206,7 @@ pub fn check_special_unwrap_err_or_ret( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let input = checker.type_check(&args[0], context)?; @@ -221,7 +221,7 @@ pub fn check_special_try_ret( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -231,7 +231,7 @@ pub fn check_special_try_ret( match input { TypeSignature::OptionalType(input_type) => { if input_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseOkType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseOkType.into()) } else { checker.track_return_type(TypeSignature::new_option(TypeSignature::NoType)?)?; Ok(*input_type) @@ -240,9 +240,9 @@ pub fn check_special_try_ret( TypeSignature::ResponseType(response_type) => { let (ok_type, err_type) = *response_type; if ok_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseOkType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseOkType.into()) } else if err_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseErrType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseErrType.into()) } else { checker.track_return_type(TypeSignature::new_response( TypeSignature::NoType, @@ -251,7 +251,7 @@ pub fn check_special_try_ret( Ok(ok_type) } } - _ => Err(CheckErrors::ExpectedOptionalOrResponseType(Box::new(input)).into()), + _ => Err(CheckErrorKind::ExpectedOptionalOrResponseType(Box::new(input)).into()), } } @@ -259,7 +259,7 @@ pub fn check_special_unwrap( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -271,7 +271,7 @@ pub fn check_special_unwrap_err( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -285,7 +285,7 @@ fn eval_with_new_binding( bind_type: TypeSignature, checker: &mut TypeChecker, context: &TypingContext, -) -> Result { +) -> Result { let mut inner_context = context.extend()?; runtime_cost( @@ -297,7 +297,7 @@ fn eval_with_new_binding( checker.contract_context.check_name_used(&bind_name)?; if inner_context.lookup_variable_type(&bind_name).is_some() { - return Err(CheckErrors::NameAlreadyUsed(bind_name.into()).into()); + return Err(CheckErrorKind::NameAlreadyUsed(bind_name.into()).into()); } inner_context.variable_types.insert(bind_name, bind_type); @@ -310,22 +310,24 @@ fn check_special_match_opt( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { if args.len() != 3 { - Err(CheckErrors::BadMatchOptionSyntax(Box::new( - CheckErrors::IncorrectArgumentCount(4, args.len() + 1), + Err(CheckErrorKind::BadMatchOptionSyntax(Box::new( + CheckErrorKind::IncorrectArgumentCount(4, args.len() + 1), )))?; } let bind_name = args[0] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchOptionSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchOptionSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let some_branch = &args[1]; let none_branch = &args[2]; if option_type.is_no_type() { - return Err(CheckErrors::CouldNotDetermineMatchTypes.into()); + return Err(CheckErrorKind::CouldNotDetermineMatchTypes.into()); } let some_branch_type = @@ -340,7 +342,7 @@ fn check_special_match_opt( &none_branch_type, ) .map_err(|_| { - CheckErrors::MatchArmsMustMatch(Box::new(some_branch_type), Box::new(none_branch_type)) + CheckErrorKind::MatchArmsMustMatch(Box::new(some_branch_type), Box::new(none_branch_type)) .into() }) } @@ -350,28 +352,32 @@ fn check_special_match_resp( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { if args.len() != 4 { - Err(CheckErrors::BadMatchResponseSyntax(Box::new( - CheckErrors::IncorrectArgumentCount(5, args.len() + 1), + Err(CheckErrorKind::BadMatchResponseSyntax(Box::new( + CheckErrorKind::IncorrectArgumentCount(5, args.len() + 1), )))?; } let ok_bind_name = args[0] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let ok_branch = &args[1]; let err_bind_name = args[2] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let err_branch = &args[3]; let (ok_type, err_type) = resp_type; if ok_type.is_no_type() || err_type.is_no_type() { - return Err(CheckErrors::CouldNotDetermineMatchTypes.into()); + return Err(CheckErrorKind::CouldNotDetermineMatchTypes.into()); } let ok_branch_type = eval_with_new_binding(ok_branch, ok_bind_name, ok_type, checker, context)?; @@ -382,7 +388,7 @@ fn check_special_match_resp( TypeSignature::least_supertype(&StacksEpochId::Epoch2_05, &ok_branch_type, &err_branch_type) .map_err(|_| { - CheckErrors::MatchArmsMustMatch(Box::new(ok_branch_type), Box::new(err_branch_type)) + CheckErrorKind::MatchArmsMustMatch(Box::new(ok_branch_type), Box::new(err_branch_type)) .into() }) } @@ -391,7 +397,7 @@ pub fn check_special_match( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -403,6 +409,6 @@ pub fn check_special_match( TypeSignature::ResponseType(resp_type) => { check_special_match_resp(*resp_type, checker, &args[1..], context) } - _ => Err(CheckErrors::BadMatchInput(Box::new(input)).into()), + _ => Err(CheckErrorKind::BadMatchInput(Box::new(input)).into()), } } diff --git a/clarity/src/vm/analysis/type_checker/v2_05/natives/sequences.rs b/clarity/src/vm/analysis/type_checker/v2_05/natives/sequences.rs index 9881bf9448e..8b03807c7a9 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/natives/sequences.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/natives/sequences.rs @@ -18,7 +18,7 @@ use stacks_common::types::StacksEpochId; use super::{SimpleNativeFunction, TypedNativeFunction}; use crate::vm::analysis::type_checker::v2_05::{ - check_argument_count, check_arguments_at_least, CheckError, CheckErrors, TypeChecker, + check_argument_count, check_arguments_at_least, CheckErrorKind, StaticCheckError, TypeChecker, TypingContext, }; use crate::vm::costs::cost_functions::ClarityCostFunction; @@ -34,7 +34,7 @@ use crate::vm::ClarityVersion; fn get_simple_native_or_user_define( function_name: &str, checker: &mut TypeChecker, -) -> Result { +) -> Result { runtime_cost(ClarityCostFunction::AnalysisLookupFunction, checker, 0)?; if let Some(ref native_function) = NativeFunctions::lookup_by_name_at_version(function_name, &ClarityVersion::Clarity1) @@ -44,11 +44,14 @@ fn get_simple_native_or_user_define( { Ok(function_type) } else { - Err(CheckErrors::IllegalOrUnknownFunctionApplication(function_name.to_string()).into()) + Err( + CheckErrorKind::IllegalOrUnknownFunctionApplication(function_name.to_string()) + .into(), + ) } } else { checker.get_function_type(function_name).ok_or( - CheckErrors::IllegalOrUnknownFunctionApplication(function_name.to_string()).into(), + CheckErrorKind::IllegalOrUnknownFunctionApplication(function_name.to_string()).into(), ) } } @@ -57,12 +60,12 @@ pub fn check_special_map( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; let function_name = args[0] .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; // we will only lookup native or defined functions here. // you _cannot_ map a special function. let function_type = get_simple_native_or_user_define(function_name, checker)?; @@ -98,7 +101,7 @@ pub fn check_special_map( // However that could lead to confusions when combining certain types: // ex: (map concat (list "hello " "hi ") "world") would fail, because // strings are handled as sequences. - return Err(CheckErrors::ExpectedSequence(Box::new(argument_type)).into()); + return Err(CheckErrorKind::ExpectedSequence(Box::new(argument_type)).into()); } }; func_args.push(entry_type); @@ -107,19 +110,19 @@ pub fn check_special_map( let mapped_type = function_type.check_args(checker, &func_args, context.epoch, context.clarity_version)?; TypeSignature::list_of(mapped_type, min_args) - .map_err(|_| CheckErrors::ConstructedListTooLarge.into()) + .map_err(|_| CheckErrorKind::ConstructedListTooLarge.into()) } pub fn check_special_filter( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let function_name = args[0] .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; // we will only lookup native or defined functions here. // you _cannot_ map a special function. let function_type = get_simple_native_or_user_define(function_name, checker)?; @@ -130,7 +133,7 @@ pub fn check_special_filter( { let input_type = match argument_type { TypeSignature::SequenceType(ref sequence_type) => Ok(sequence_type.unit_type()), - _ => Err(CheckErrors::ExpectedSequence(Box::new( + _ => Err(CheckErrorKind::ExpectedSequence(Box::new( argument_type.clone(), ))), }?; @@ -143,7 +146,7 @@ pub fn check_special_filter( )?; if TypeSignature::BoolType != filter_type { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(TypeSignature::BoolType), Box::new(filter_type), ) @@ -158,12 +161,12 @@ pub fn check_special_fold( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; let function_name = args[0] .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; // we will only lookup native or defined functions here. // you _cannot_ fold a special function. let function_type = get_simple_native_or_user_define(function_name, checker)?; @@ -173,7 +176,7 @@ pub fn check_special_fold( let input_type = match argument_type { TypeSignature::SequenceType(sequence_type) => Ok(sequence_type.unit_type()), - _ => Err(CheckErrors::ExpectedSequence(Box::new(argument_type))), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(argument_type))), }?; let initial_value_type = checker.type_check(&args[2], context)?; @@ -205,7 +208,7 @@ pub fn check_special_concat( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let lhs_type = checker.type_check(&args[0], context)?; @@ -231,29 +234,29 @@ pub fn check_special_concat( )?; let new_len = lhs_max_len .checked_add(rhs_max_len) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; TypeSignature::list_of(list_entry_type, new_len)? } (BufferType(lhs_len), BufferType(rhs_len)) => { let size: u32 = u32::from(lhs_len) .checked_add(u32::from(rhs_len)) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; TypeSignature::SequenceType(BufferType(size.try_into()?)) } (StringType(ASCII(lhs_len)), StringType(ASCII(rhs_len))) => { let size: u32 = u32::from(lhs_len) .checked_add(u32::from(rhs_len)) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; TypeSignature::SequenceType(StringType(ASCII(size.try_into()?))) } (StringType(UTF8(lhs_len)), StringType(UTF8(rhs_len))) => { let size: u32 = u32::from(lhs_len) .checked_add(u32::from(rhs_len)) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; TypeSignature::SequenceType(StringType(UTF8(size.try_into()?))) } (_, _) => { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(lhs_type.clone()), Box::new(rhs_type.clone()), ) @@ -261,7 +264,7 @@ pub fn check_special_concat( } } } - _ => return Err(CheckErrors::ExpectedSequence(Box::new(lhs_type.clone())).into()), + _ => return Err(CheckErrorKind::ExpectedSequence(Box::new(lhs_type.clone())).into()), }; Ok(res) } @@ -270,7 +273,7 @@ pub fn check_special_append( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; @@ -290,11 +293,11 @@ pub fn check_special_append( )?; let new_len = lhs_max_len .checked_add(1) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; let return_type = TypeSignature::list_of(list_entry_type, new_len)?; Ok(return_type) } - _ => Err(CheckErrors::ExpectedListApplication.into()), + _ => Err(CheckErrorKind::ExpectedListApplication.into()), } } @@ -302,14 +305,14 @@ pub fn check_special_as_max_len( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let expected_len = match args[1].expr { SymbolicExpressionType::LiteralValue(Value::UInt(expected_len)) => expected_len, _ => { let expected_len_type = checker.type_check(&args[1], context)?; - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(expected_len_type), ) @@ -325,7 +328,8 @@ pub fn check_special_as_max_len( .type_map .set_type(&args[1], TypeSignature::UIntType)?; - let expected_len = u32::try_from(expected_len).map_err(|_e| CheckErrors::MaxLengthOverflow)?; + let expected_len = + u32::try_from(expected_len).map_err(|_e| CheckErrorKind::MaxLengthOverflow)?; let sequence = checker.type_check(&args[0], context)?; runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; @@ -351,7 +355,7 @@ pub fn check_special_as_max_len( StringUTF8Length::try_from(expected_len)?, )))), )), - _ => Err(CheckErrors::ExpectedSequence(Box::new(sequence)).into()), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(sequence)).into()), } } @@ -359,7 +363,7 @@ pub fn check_special_len( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let collection_type = checker.type_check(&args[0], context)?; @@ -367,7 +371,7 @@ pub fn check_special_len( match collection_type { TypeSignature::SequenceType(_) => Ok(()), - _ => Err(CheckErrors::ExpectedSequence(Box::new(collection_type))), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(collection_type))), }?; Ok(TypeSignature::UIntType) @@ -377,7 +381,7 @@ pub fn check_special_element_at( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let _index_type = checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; @@ -396,16 +400,16 @@ pub fn check_special_element_at( TypeSignature::SequenceType(StringType(ASCII(_))) => Ok(TypeSignature::OptionalType( Box::new(TypeSignature::SequenceType(StringType(ASCII( BufferLength::try_from(1u32) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, )))), )), TypeSignature::SequenceType(StringType(UTF8(_))) => Ok(TypeSignature::OptionalType( Box::new(TypeSignature::SequenceType(StringType(UTF8( StringUTF8Length::try_from(1u32) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, )))), )), - _ => Err(CheckErrors::ExpectedSequence(Box::new(collection_type)).into()), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(collection_type)).into()), } } @@ -413,7 +417,7 @@ pub fn check_special_index_of( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; @@ -421,7 +425,7 @@ pub fn check_special_index_of( let expected_input_type = match list_type { TypeSignature::SequenceType(ref sequence_type) => Ok(sequence_type.unit_type()), - _ => Err(CheckErrors::ExpectedSequence(Box::new(list_type))), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(list_type))), }?; checker.type_check_expects(&args[1], context, &expected_input_type)?; diff --git a/clarity/src/vm/analysis/type_checker/v2_05/tests/assets.rs b/clarity/src/vm/analysis/type_checker/v2_05/tests/assets.rs index 75dbc4928f5..39e52b274d2 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/tests/assets.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/tests/assets.rs @@ -16,7 +16,7 @@ use stacks_common::types::StacksEpochId; -use crate::vm::analysis::errors::CheckErrors; +use crate::vm::analysis::errors::CheckErrorKind; use crate::vm::ast::parse; use crate::vm::database::MemoryBackingStore; use crate::vm::tooling::mem_type_check; @@ -193,108 +193,108 @@ fn test_bad_asset_usage() { ]; let expected = [ - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::BadTokenName, - CheckErrors::BadTokenName, - CheckErrors::TypeError( + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::BadTokenName, + CheckErrorKind::BadTokenName, + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::IntType), ), - CheckErrors::BadTokenName, - CheckErrors::NoSuchNFT("stackoos".to_string()), - CheckErrors::TypeError( + CheckErrorKind::BadTokenName, + CheckErrorKind::NoSuchNFT("stackoos".to_string()), + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(string_ascii_type(15)), ), - CheckErrors::BadTokenName, - CheckErrors::NoSuchNFT("stackoos".to_string()), - CheckErrors::TypeError( + CheckErrorKind::BadTokenName, + CheckErrorKind::NoSuchNFT("stackoos".to_string()), + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(string_ascii_type(15)), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::BadTokenName, - CheckErrors::TypeError( + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::BadTokenName, + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::BoolType), ), - CheckErrors::BadTokenName, - CheckErrors::NoSuchNFT("stackoos".to_string()), - CheckErrors::TypeError( + CheckErrorKind::BadTokenName, + CheckErrorKind::NoSuchNFT("stackoos".to_string()), + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(TypeSignature::UIntType), ), - CheckErrors::BadTokenName, - CheckErrors::TypeError( + CheckErrorKind::BadTokenName, + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::BadTokenName, - CheckErrors::TypeError( + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::BadTokenName, + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::BoolType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::BoolType), ), - CheckErrors::DefineNFTBadSignature, - CheckErrors::TypeError( + CheckErrorKind::DefineNFTBadSignature, + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::TypeError( + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::IntType), ), diff --git a/clarity/src/vm/analysis/type_checker/v2_05/tests/contracts.rs b/clarity/src/vm/analysis/type_checker/v2_05/tests/contracts.rs index 6d37d068376..6b6c5137276 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/tests/contracts.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/tests/contracts.rs @@ -19,7 +19,7 @@ use stacks_common::types::StacksEpochId; use {assert_json_diff, serde_json}; use crate::vm::analysis::contract_interface_builder::build_contract_interface; -use crate::vm::analysis::errors::CheckErrors; +use crate::vm::analysis::errors::CheckErrorKind; use crate::vm::analysis::{mem_type_check, type_check}; use crate::vm::ast::parse; use crate::vm::database::MemoryBackingStore; @@ -492,7 +492,7 @@ fn test_names_tokens_contracts_bad() { ) }) .unwrap_err(); - assert!(matches!(*err.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*err.err, CheckErrorKind::TypeError(_, _))); } #[test] @@ -534,7 +534,7 @@ fn test_bad_map_usage() { for contract in tests.iter() { let err = mem_type_check(contract, ClarityVersion::Clarity1, StacksEpochId::Epoch2_05) .unwrap_err(); - assert!(matches!(*err.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*err.err, CheckErrorKind::TypeError(_, _))); } assert!(matches!( @@ -545,7 +545,7 @@ fn test_bad_map_usage() { ) .unwrap_err() .err, - CheckErrors::UnionTypeError(_, _) + CheckErrorKind::UnionTypeError(_, _) )); } @@ -663,7 +663,10 @@ fn test_expects() { ) .unwrap_err(); eprintln!("unmatched_return_types returned check error: {err}"); - assert!(matches!(*err.err, CheckErrors::ReturnTypesMustMatch(_, _))); + assert!(matches!( + *err.err, + CheckErrorKind::ReturnTypesMustMatch(_, _) + )); } let err = mem_type_check( @@ -673,7 +676,10 @@ fn test_expects() { ) .unwrap_err(); eprintln!("bad_default_types returned check error: {err}"); - assert!(matches!(*err.err, CheckErrors::DefaultTypesMustMatch(_, _))); + assert!(matches!( + *err.err, + CheckErrorKind::DefaultTypesMustMatch(_, _) + )); let err = mem_type_check( notype_response_type, @@ -684,7 +690,7 @@ fn test_expects() { eprintln!("notype_response_type returned check error: {err}"); assert!(matches!( *err.err, - CheckErrors::CouldNotDetermineResponseErrType + CheckErrorKind::CouldNotDetermineResponseErrType )); let err = mem_type_check( @@ -696,6 +702,6 @@ fn test_expects() { eprintln!("notype_response_type_2 returned check error: {err}"); assert!(matches!( *err.err, - CheckErrors::CouldNotDetermineResponseOkType + CheckErrorKind::CouldNotDetermineResponseOkType )); } diff --git a/clarity/src/vm/analysis/type_checker/v2_05/tests/mod.rs b/clarity/src/vm/analysis/type_checker/v2_05/tests/mod.rs index f0cfe1068a5..db7cdf7810f 100644 --- a/clarity/src/vm/analysis/type_checker/v2_05/tests/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_05/tests/mod.rs @@ -16,10 +16,10 @@ use stacks_common::types::StacksEpochId; -use crate::vm::analysis::errors::{CheckError, CheckErrors, SyntaxBindingError}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError, SyntaxBindingError}; use crate::vm::analysis::mem_type_check; use crate::vm::ast::build_ast; -use crate::vm::ast::errors::ParseErrors; +use crate::vm::ast::errors::ParseErrorKind; use crate::vm::types::SequenceSubtype::*; use crate::vm::types::StringSubtype::*; use crate::vm::types::TypeSignature::{BoolType, IntType, PrincipalType, UIntType}; @@ -30,7 +30,7 @@ use crate::vm::ClarityVersion; mod assets; mod contracts; -fn type_check_helper(exp: &str) -> Result { +fn type_check_helper(exp: &str) -> Result { mem_type_check(exp, ClarityVersion::Clarity1, StacksEpochId::Epoch2_05) .map(|(type_sig_opt, _)| type_sig_opt.unwrap()) } @@ -69,10 +69,10 @@ fn test_get_block_info() { "(get-block-info? time)", ]; let bad_expected = [ - CheckErrors::NoSuchBlockInfoProperty("none".to_string()), - CheckErrors::TypeError(Box::new(UIntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::RequiresAtLeastArguments(2, 1), + CheckErrorKind::NoSuchBlockInfoProperty("none".to_string()), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::RequiresAtLeastArguments(2, 1), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -113,10 +113,10 @@ fn test_define_trait() { "(define-trait)", ]; let bad_expected = [ - CheckErrors::InvalidTypeDescription, - CheckErrors::DefineTraitBadSignature, - CheckErrors::DefineTraitBadSignature, - CheckErrors::InvalidTypeDescription, + CheckErrorKind::InvalidTypeDescription, + CheckErrorKind::DefineTraitBadSignature, + CheckErrorKind::DefineTraitBadSignature, + CheckErrorKind::InvalidTypeDescription, ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { @@ -125,8 +125,8 @@ fn test_define_trait() { let bad = ["(define-trait trait-1)", "(define-trait)"]; let bad_expected = [ - ParseErrors::DefineTraitBadSignature, - ParseErrors::DefineTraitBadSignature, + ParseErrorKind::DefineTraitBadSignature, + ParseErrorKind::DefineTraitBadSignature, ]; let contract_identifier = QualifiedContractIdentifier::transient(); @@ -152,10 +152,10 @@ fn test_use_trait() { "(use-trait)", ]; let bad_expected = [ - ParseErrors::ImportTraitBadSignature, - ParseErrors::ImportTraitBadSignature, - ParseErrors::ImportTraitBadSignature, - ParseErrors::ImportTraitBadSignature, + ParseErrorKind::ImportTraitBadSignature, + ParseErrorKind::ImportTraitBadSignature, + ParseErrorKind::ImportTraitBadSignature, + ParseErrorKind::ImportTraitBadSignature, ]; let contract_identifier = QualifiedContractIdentifier::transient(); @@ -176,8 +176,8 @@ fn test_use_trait() { fn test_impl_trait() { let bad = ["(impl-trait trait-1)", "(impl-trait)"]; let bad_expected = [ - ParseErrors::ImplTraitBadSignature, - ParseErrors::ImplTraitBadSignature, + ParseErrorKind::ImplTraitBadSignature, + ParseErrorKind::ImplTraitBadSignature, ]; let contract_identifier = QualifiedContractIdentifier::transient(); @@ -216,16 +216,16 @@ fn test_stx_ops() { "(stx-get-balance 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR)" ]; let bad_expected = [ - CheckErrors::IncorrectArgumentCount(3, 2), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(UIntType)), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(BoolType)), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(BoolType)), - CheckErrors::IncorrectArgumentCount(2, 3), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(BoolType)), - CheckErrors::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(UIntType)), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(BoolType)), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(BoolType)), + CheckErrorKind::IncorrectArgumentCount(2, 3), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(BoolType)), + CheckErrorKind::IncorrectArgumentCount(1, 2), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -291,7 +291,7 @@ fn test_destructuring_opts() { let bad = [ ( "(unwrap-err! (some 2) 2)", - CheckErrors::ExpectedResponseType(Box::new(TypeSignature::from_string( + CheckErrorKind::ExpectedResponseType(Box::new(TypeSignature::from_string( "(optional int)", ClarityVersion::Clarity1, StacksEpochId::Epoch2_05, @@ -299,88 +299,90 @@ fn test_destructuring_opts() { ), ( "(unwrap! (err 3) 2)", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(unwrap-err-panic (ok 3))", - CheckErrors::CouldNotDetermineResponseErrType, + CheckErrorKind::CouldNotDetermineResponseErrType, ), ( "(unwrap-panic none)", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(define-private (foo) (if (> 1 0) none none)) (unwrap-panic (foo))", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(unwrap-panic (err 3))", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(match none inner-value (/ 1 0) (+ 1 8))", - CheckErrors::CouldNotDetermineMatchTypes, + CheckErrorKind::CouldNotDetermineMatchTypes, ), ( "(match (ok 1) ok-val (/ ok-val 0) err-val (+ err-val 7))", - CheckErrors::CouldNotDetermineMatchTypes, + CheckErrorKind::CouldNotDetermineMatchTypes, ), ( "(match (err 1) ok-val (/ ok-val 0) err-val (+ err-val 7))", - CheckErrors::CouldNotDetermineMatchTypes, + CheckErrorKind::CouldNotDetermineMatchTypes, ), ( "(define-private (foo) (if (> 1 0) (ok 1) (err u8))) (match (foo) ok-val (+ 1 ok-val) err-val (/ err-val u0))", - CheckErrors::MatchArmsMustMatch( + CheckErrorKind::MatchArmsMustMatch( Box::new(TypeSignature::IntType), Box::new(TypeSignature::UIntType), ), ), ( "(match (some 1) inner-value (+ 1 inner-value) (> 1 28))", - CheckErrors::MatchArmsMustMatch( + CheckErrorKind::MatchArmsMustMatch( Box::new(TypeSignature::IntType), Box::new(TypeSignature::BoolType), ), ), ( "(match (some 1) inner-value (+ 1 inner-value))", - CheckErrors::BadMatchOptionSyntax(Box::new(CheckErrors::IncorrectArgumentCount(4, 3))), + CheckErrorKind::BadMatchOptionSyntax(Box::new(CheckErrorKind::IncorrectArgumentCount( + 4, 3, + ))), ), ( "(match (ok 1) inner-value (+ 1 inner-value))", - CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::IncorrectArgumentCount( - 5, 3, - ))), + CheckErrorKind::BadMatchResponseSyntax(Box::new( + CheckErrorKind::IncorrectArgumentCount(5, 3), + )), ), ( "(match (ok 1) 1 (+ 1 1) err-val (+ 2 err-val))", - CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)), + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)), ), ( "(match (ok 1) ok-val (+ 1 1) (+ 3 4) (+ 2 err-val))", - CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)), + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)), ), ( "(match (some 1) 2 (+ 1 1) (+ 3 4))", - CheckErrors::BadMatchOptionSyntax(Box::new(CheckErrors::ExpectedName)), + CheckErrorKind::BadMatchOptionSyntax(Box::new(CheckErrorKind::ExpectedName)), ), - ("(match)", CheckErrors::RequiresAtLeastArguments(1, 0)), + ("(match)", CheckErrorKind::RequiresAtLeastArguments(1, 0)), ( "(match 1 ok-val (/ ok-val 0) err-val (+ err-val 7))", - CheckErrors::BadMatchInput(Box::new(TypeSignature::IntType)), + CheckErrorKind::BadMatchInput(Box::new(TypeSignature::IntType)), ), ( "(default-to 3 5)", - CheckErrors::ExpectedOptionalType(Box::new(TypeSignature::IntType)), + CheckErrorKind::ExpectedOptionalType(Box::new(TypeSignature::IntType)), ), ( "(define-private (foo (x int)) (match (some 3) x (+ x 2) 5))", - CheckErrors::NameAlreadyUsed("x".to_string()), + CheckErrorKind::NameAlreadyUsed("x".to_string()), ), ( "(define-private (t1 (x uint)) (if (> x u1) (ok x) (err false))) @@ -388,7 +390,7 @@ fn test_destructuring_opts() { (if (> x u4) (err u3) (ok (+ u2 (try! (t1 x))))))", - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( Box::new( TypeSignature::new_response(TypeSignature::NoType, TypeSignature::BoolType) .unwrap(), @@ -403,7 +405,7 @@ fn test_destructuring_opts() { "(define-private (t1 (x uint)) (if (> x u1) (ok x) (err false))) (define-private (t2 (x uint)) (> u2 (try! (t1 x))))", - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( Box::new( TypeSignature::new_response(TypeSignature::NoType, TypeSignature::BoolType) .unwrap(), @@ -413,18 +415,24 @@ fn test_destructuring_opts() { ), ( "(try! (ok 3))", - CheckErrors::CouldNotDetermineResponseErrType, + CheckErrorKind::CouldNotDetermineResponseErrType, + ), + ( + "(try! none)", + CheckErrorKind::CouldNotDetermineResponseOkType, ), - ("(try! none)", CheckErrors::CouldNotDetermineResponseOkType), ( "(try! (err 3))", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(try! 3)", - CheckErrors::ExpectedOptionalOrResponseType(Box::new(TypeSignature::IntType)), + CheckErrorKind::ExpectedOptionalOrResponseType(Box::new(TypeSignature::IntType)), + ), + ( + "(try! (ok 3) 4)", + CheckErrorKind::IncorrectArgumentCount(1, 2), ), - ("(try! (ok 3) 4)", CheckErrors::IncorrectArgumentCount(1, 2)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -451,14 +459,14 @@ fn test_at_block() { let bad = [ ( "(at-block (sha512 u0) u1)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_32), Box::new(TypeSignature::BUFFER_64), ), ), ( "(at-block (sha256 u0) u1 u2)", - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), ), ]; @@ -478,7 +486,7 @@ fn test_at_block() { fn test_trait_reference_unknown() { let bad = [( "(+ 1 )", - ParseErrors::TraitReferenceUnknown("kvstore".to_string()), + ParseErrorKind::TraitReferenceUnknown("kvstore".to_string()), )]; let contract_identifier = QualifiedContractIdentifier::transient(); @@ -499,7 +507,7 @@ fn test_trait_reference_unknown() { fn test_unexpected_use_of_field_or_trait_reference() { let bad = [( "(+ 1 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR.contract.field)", - CheckErrors::UnexpectedTraitOrFieldReference, + CheckErrorKind::UnexpectedTraitOrFieldReference, )]; for (bad_test, expected) in bad.iter() { @@ -524,12 +532,12 @@ fn test_simple_arithmetic_checks() { "(and (or true false) (+ 1 2 3))", ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::RequiresAtLeastArguments(1, 0), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::UndefinedVariable("x".to_string()), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::RequiresAtLeastArguments(1, 0), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::UndefinedVariable("x".to_string()), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -590,14 +598,14 @@ fn test_simple_hash_checks() { for bad_test in bad_types.iter() { assert!(matches!( *type_check_helper(bad_test).unwrap_err().err, - CheckErrors::UnionTypeError(_, _) + CheckErrorKind::UnionTypeError(_, _) )); } for bad_test in invalid_args.iter() { assert!(matches!( *type_check_helper(bad_test).unwrap_err().err, - CheckErrors::IncorrectArgumentCount(_, _) + CheckErrorKind::IncorrectArgumentCount(_, _) )); } } @@ -620,10 +628,10 @@ fn test_simple_ifs() { ]; let bad_expected = [ - CheckErrors::IfArmsMustMatch(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IfArmsMustMatch(Box::new(ascii_type(1)), Box::new(BoolType)), - CheckErrors::IncorrectArgumentCount(3, 0), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IfArmsMustMatch(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IfArmsMustMatch(Box::new(ascii_type(1)), Box::new(BoolType)), + CheckErrorKind::IncorrectArgumentCount(3, 0), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -656,9 +664,9 @@ fn test_simple_lets() { ]; let bad_expected = [ - CheckErrors::BadSyntaxBinding(SyntaxBindingError::let_binding_invalid_length(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::let_binding_not_atom(0)), - CheckErrors::TypeError( + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::let_binding_invalid_length(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::let_binding_not_atom(0)), + CheckErrorKind::TypeError( Box::new(TypeSignature::IntType), Box::new(TypeSignature::UIntType), ), @@ -713,26 +721,26 @@ fn test_index_of() { ]; let bad_expected = [ - CheckErrors::ExpectedSequence(Box::new(TypeSignature::IntType)), - CheckErrors::TypeError( + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::IntType)), + CheckErrorKind::TypeError( Box::new(TypeSignature::IntType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_MIN), Box::new(TypeSignature::STRING_ASCII_MIN), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::STRING_UTF8_MIN), Box::new(TypeSignature::STRING_ASCII_MIN), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::STRING_ASCII_MIN), Box::new(TypeSignature::STRING_UTF8_MIN), ), - CheckErrors::CouldNotDetermineType, - CheckErrors::CouldNotDetermineType, - CheckErrors::CouldNotDetermineType, + CheckErrorKind::CouldNotDetermineType, + CheckErrorKind::CouldNotDetermineType, + CheckErrorKind::CouldNotDetermineType, ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { @@ -761,11 +769,11 @@ fn test_element_at() { let bad = ["(element-at (list 1 2 3 4 5) 100)", "(element-at 3 u100)"]; let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::ExpectedSequence(Box::new(TypeSignature::IntType)), + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -797,12 +805,12 @@ fn test_eqs() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::TypeError( + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::TypeError( Box::new(TypeSignature::list_of(IntType, 1).unwrap()), Box::new(IntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::from_string( "(optional bool)", ClarityVersion::Clarity1, @@ -844,9 +852,9 @@ fn test_asserts() { ]; let bad_expected = [ - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 3), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -910,23 +918,23 @@ fn test_lists() { "(map + (list 1 2 3 4 5) (list true true true true true))", ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(BoolType), Box::new(buff_type(20))), - CheckErrors::TypeError(Box::new(BoolType), Box::new(buff_type(20))), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 3), - CheckErrors::UnknownFunction("ynot".to_string()), - CheckErrors::IllegalOrUnknownFunctionApplication("if".to_string()), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), - CheckErrors::ExpectedSequence(Box::new(UIntType)), - CheckErrors::ExpectedSequence(Box::new(IntType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(buff_type(20))), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(buff_type(20))), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 3), + CheckErrorKind::UnknownFunction("ynot".to_string()), + CheckErrorKind::IllegalOrUnknownFunctionApplication("if".to_string()), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), + CheckErrorKind::ExpectedSequence(Box::new(UIntType)), + CheckErrorKind::ExpectedSequence(Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -967,20 +975,20 @@ fn test_buff() { "(len 1)", ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(BoolType), Box::new(buff_type(20))), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 3), - CheckErrors::UnknownFunction("ynot".to_string()), - CheckErrors::IllegalOrUnknownFunctionApplication("if".to_string()), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), - CheckErrors::ExpectedSequence(Box::new(UIntType)), - CheckErrors::ExpectedSequence(Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(buff_type(20))), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 3), + CheckErrorKind::UnknownFunction("ynot".to_string()), + CheckErrorKind::IllegalOrUnknownFunctionApplication("if".to_string()), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), + CheckErrorKind::ExpectedSequence(Box::new(UIntType)), + CheckErrorKind::ExpectedSequence(Box::new(IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1055,9 +1063,9 @@ fn test_native_as_max_len() { "(as-max-len? 0x01 u1048577)", ]; let bad_expected = [ - CheckErrors::ValueTooLarge, - CheckErrors::ValueTooLarge, - CheckErrors::ValueTooLarge, + CheckErrorKind::ValueTooLarge, + CheckErrorKind::ValueTooLarge, + CheckErrorKind::ValueTooLarge, ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1101,9 +1109,9 @@ fn test_native_append() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(IntType), Box::new(UIntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(UIntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 1), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1129,9 +1137,9 @@ fn test_native_concat() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(IntType), Box::new(UIntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(UIntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 1), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1227,8 +1235,8 @@ fn test_tuples() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1258,7 +1266,7 @@ fn test_empty_tuple_should_fail() { ) .unwrap_err() .err, - CheckErrors::EmptyTuplesNotAllowed + CheckErrorKind::EmptyTuplesNotAllowed ); } @@ -1354,9 +1362,9 @@ fn test_simple_uints() { let bad = ["(> u1 1)", "(to-uint true)", "(to-int false)"]; let bad_expected = [ - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(BoolType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1417,7 +1425,7 @@ fn test_response_inference() { ]; let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::from_string( "(response bool int)", ClarityVersion::Clarity1, @@ -1425,8 +1433,8 @@ fn test_response_inference() { )), Box::new(BoolType), ), - CheckErrors::ReturnTypesMustMatch(Box::new(IntType), Box::new(BoolType)), - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::ReturnTypesMustMatch(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::CouldNotDetermineResponseOkType, ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1564,7 +1572,7 @@ fn test_options() { .unwrap_err() .err { - CheckErrors::TypeError(t1, t2) => { + CheckErrorKind::TypeError(t1, t2) => { *t1 == TypeSignature::from_string( "(optional bool)", ClarityVersion::Clarity1, @@ -1716,7 +1724,7 @@ fn test_missing_value_on_declaration_should_fail() { .unwrap_err(); assert!(matches!( *res.err, - CheckErrors::IncorrectArgumentCount(_, _) + CheckErrorKind::IncorrectArgumentCount(_, _) )); } @@ -1732,7 +1740,7 @@ fn test_mismatching_type_on_declaration_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } #[test] @@ -1753,7 +1761,7 @@ fn test_mismatching_type_on_update_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } #[test] @@ -1770,7 +1778,7 @@ fn test_direct_access_to_persisted_var_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } #[test] @@ -1790,7 +1798,7 @@ fn test_data_var_shadowed_by_let_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -1808,7 +1816,7 @@ fn test_mutating_unknown_data_var_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NoSuchDataVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::NoSuchDataVariable(_))); } #[test] @@ -1824,7 +1832,7 @@ fn test_accessing_unknown_data_var_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NoSuchDataVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::NoSuchDataVariable(_))); } #[test] @@ -1840,7 +1848,7 @@ fn test_let_shadowed_by_let_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -1857,7 +1865,7 @@ fn test_let_shadowed_by_nested_let_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -1875,7 +1883,7 @@ fn test_define_constant_shadowed_by_let_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -1892,7 +1900,7 @@ fn test_define_constant_shadowed_by_argument_should_fail() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -2114,7 +2122,7 @@ fn test_fetch_entry_mismatching_type_signatures() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } } @@ -2134,7 +2142,7 @@ fn test_fetch_entry_unbound_variables() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } } @@ -2186,7 +2194,7 @@ fn test_insert_entry_mismatching_type_signatures() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } } @@ -2209,7 +2217,7 @@ fn test_insert_entry_unbound_variables() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } } @@ -2259,7 +2267,7 @@ fn test_delete_entry_mismatching_type_signatures() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } } @@ -2279,7 +2287,7 @@ fn test_delete_entry_unbound_variables() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } } @@ -2333,7 +2341,7 @@ fn test_set_entry_mismatching_type_signatures() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } } @@ -2356,7 +2364,7 @@ fn test_set_entry_unbound_variables() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } } @@ -2491,7 +2499,7 @@ fn test_buff_negative_len() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert_eq!(*res.err, CheckErrors::ValueOutOfBounds); + assert_eq!(*res.err, CheckErrorKind::ValueOutOfBounds); } #[test] @@ -2505,7 +2513,7 @@ fn test_string_ascii_negative_len() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert_eq!(*res.err, CheckErrors::ValueOutOfBounds); + assert_eq!(*res.err, CheckErrorKind::ValueOutOfBounds); } #[test] @@ -2519,5 +2527,5 @@ fn test_string_utf8_negative_len() { StacksEpochId::Epoch2_05, ) .unwrap_err(); - assert_eq!(*res.err, CheckErrors::ValueOutOfBounds); + assert_eq!(*res.err, CheckErrorKind::ValueOutOfBounds); } 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 d226f33e074..7632ea305bb 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/contexts.rs @@ -16,7 +16,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; -use crate::vm::analysis::errors::{CheckError, CheckErrors}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError}; use crate::vm::analysis::type_checker::is_reserved_word; use crate::vm::analysis::types::ContractAnalysis; use crate::vm::representations::ClarityName; @@ -167,9 +167,11 @@ impl ContractContext { &self.contract_identifier == other } - pub fn check_name_used(&self, name: &str) -> Result<(), CheckError> { + pub fn check_name_used(&self, name: &str) -> Result<(), StaticCheckError> { if is_reserved_word(name, self.clarity_version) { - return Err(CheckError::new(CheckErrors::ReservedWord(name.to_string()))); + return Err(StaticCheckError::new(CheckErrorKind::ReservedWord( + name.to_string(), + ))); } if self.variable_types.contains_key(name) @@ -181,7 +183,7 @@ impl ContractContext { || self.traits.is_name_used(name) || self.map_types.contains_key(name) { - Err(CheckError::new(CheckErrors::NameAlreadyUsed( + Err(StaticCheckError::new(CheckErrorKind::NameAlreadyUsed( name.to_string(), ))) } else { @@ -189,7 +191,7 @@ impl ContractContext { } } - fn check_function_type(&mut self, f_name: &str) -> Result<(), CheckError> { + fn check_function_type(&mut self, f_name: &str) -> Result<(), StaticCheckError> { self.check_name_used(f_name)?; Ok(()) } @@ -206,7 +208,7 @@ impl ContractContext { &mut self, name: ClarityName, func_type: FunctionType, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_function_type(&name)?; self.public_function_types.insert(name, func_type); Ok(()) @@ -216,7 +218,7 @@ impl ContractContext { &mut self, name: ClarityName, func_type: FunctionType, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_function_type(&name)?; self.read_only_function_types.insert(name, func_type); Ok(()) @@ -226,7 +228,7 @@ impl ContractContext { &mut self, name: ClarityName, func_type: FunctionType, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_function_type(&name)?; self.private_function_types.insert(name, func_type); Ok(()) @@ -236,7 +238,7 @@ impl ContractContext { &mut self, map_name: ClarityName, map_type: (TypeSignature, TypeSignature), - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_name_used(&map_name)?; self.map_types.insert(map_name, map_type); Ok(()) @@ -246,7 +248,7 @@ impl ContractContext { &mut self, const_name: ClarityName, var_type: TypeSignature, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_name_used(&const_name)?; self.variable_types.insert(const_name, var_type); Ok(()) @@ -256,13 +258,13 @@ impl ContractContext { &mut self, var_name: ClarityName, var_type: TypeSignature, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_name_used(&var_name)?; self.persisted_variable_types.insert(var_name, var_type); Ok(()) } - pub fn add_ft(&mut self, token_name: ClarityName) -> Result<(), CheckError> { + pub fn add_ft(&mut self, token_name: ClarityName) -> Result<(), StaticCheckError> { self.check_name_used(&token_name)?; self.fungible_tokens.insert(token_name); Ok(()) @@ -272,7 +274,7 @@ impl ContractContext { &mut self, token_name: ClarityName, token_type: TypeSignature, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.check_name_used(&token_name)?; self.non_fungible_tokens.insert(token_name, token_type); Ok(()) @@ -282,7 +284,7 @@ impl ContractContext { &mut self, trait_name: ClarityName, trait_signature: BTreeMap, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { if self.clarity_version >= ClarityVersion::Clarity3 { self.check_name_used(&trait_name)?; } @@ -300,7 +302,7 @@ impl ContractContext { alias: ClarityName, trait_id: TraitIdentifier, trait_signature: BTreeMap, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { if self.clarity_version >= ClarityVersion::Clarity3 { self.check_name_used(&alias)?; } diff --git a/clarity/src/vm/analysis/type_checker/v2_1/mod.rs b/clarity/src/vm/analysis/type_checker/v2_1/mod.rs index 0aaf5c36fed..66d7e4a6c8c 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/mod.rs @@ -26,8 +26,8 @@ pub use self::natives::{SimpleNativeFunction, TypedNativeFunction}; use super::contexts::{TypeMap, TypingContext}; use super::ContractAnalysis; pub use crate::vm::analysis::errors::{ - check_argument_count, check_arguments_at_least, check_arguments_at_most, CheckError, - CheckErrors, SyntaxBindingErrorType, + check_argument_count, check_arguments_at_least, check_arguments_at_most, CheckErrorKind, + StaticCheckError, SyntaxBindingErrorType, }; use crate::vm::analysis::AnalysisDatabase; use crate::vm::costs::cost_functions::ClarityCostFunction; @@ -128,7 +128,7 @@ impl TypeChecker<'_, '_> { contract_analysis: &mut ContractAnalysis, analysis_db: &mut AnalysisDatabase, build_type_map: bool, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { let cost_track = contract_analysis.take_contract_cost_tracker(); let mut command = TypeChecker::new( epoch, @@ -168,9 +168,9 @@ pub fn compute_typecheck_cost( ) } -pub fn check_argument_len(expected: usize, args_len: usize) -> Result<(), CheckErrors> { +pub fn check_argument_len(expected: usize, args_len: usize) -> Result<(), CheckErrorKind> { if args_len != expected { - Err(CheckErrors::IncorrectArgumentCount(expected, args_len)) + Err(CheckErrorKind::IncorrectArgumentCount(expected, args_len)) } else { Ok(()) } @@ -186,7 +186,7 @@ impl FunctionType { accumulated_type: Option<&TypeSignature>, ) -> ( Option>, - Result, CheckError>, + Result, StaticCheckError>, ) { match self { // variadic stops checking cost at the first error... @@ -199,7 +199,7 @@ impl FunctionType { if !admitted { return ( cost, - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(arg_type.clone()), ) @@ -218,7 +218,7 @@ impl FunctionType { let return_type = match arg_type { TypeSignature::IntType => Ok(Some(TypeSignature::IntType)), TypeSignature::UIntType => Ok(Some(TypeSignature::UIntType)), - _ => Err(CheckErrors::UnionTypeError( + _ => Err(CheckErrorKind::UnionTypeError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(arg_type.clone()), ) @@ -227,10 +227,10 @@ impl FunctionType { (cost, return_type) } else { let return_type = accumulated_type - .ok_or_else(|| CheckErrors::Expects("Failed to set accumulated type for arg indices >= 1 in variadic arithmetic".into()).into()); + .ok_or_else(|| CheckErrorKind::Expects("Failed to set accumulated type for arg indices >= 1 in variadic arithmetic".into()).into()); let check_result = return_type.and_then(|return_type| { if arg_type != return_type { - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(return_type.clone()), Box::new(arg_type.clone()), ) @@ -253,7 +253,10 @@ impl FunctionType { // note: argument count will be wrong? return ( None, - Err(CheckErrors::IncorrectArgumentCount(arg_types.len(), arg_index).into()), + Err( + CheckErrorKind::IncorrectArgumentCount(arg_types.len(), arg_index) + .into(), + ), ); } (None, Ok(None)) @@ -266,7 +269,7 @@ impl FunctionType { if arg_index >= 1 { return ( None, - Err(CheckErrors::IncorrectArgumentCount(1, arg_index).into()), + Err(CheckErrorKind::IncorrectArgumentCount(1, arg_index).into()), ); } (None, Ok(None)) @@ -277,7 +280,7 @@ impl FunctionType { if arg_index >= 2 { return ( None, - Err(CheckErrors::IncorrectArgumentCount(2, arg_index).into()), + Err(CheckErrorKind::IncorrectArgumentCount(2, arg_index).into()), ); } (None, Ok(None)) @@ -290,14 +293,14 @@ impl FunctionType { accounting: &mut T, args: &[TypeSignature], clarity_version: ClarityVersion, - ) -> Result { + ) -> Result { match self { FunctionType::Variadic(expected_type, return_type) => { check_arguments_at_least(1, args)?; for found_type in args.iter() { analysis_typecheck_cost(accounting, expected_type, found_type)?; if !expected_type.admits_type(&StacksEpochId::Epoch21, found_type)? { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(found_type.clone()), ) @@ -315,7 +318,7 @@ impl FunctionType { { analysis_typecheck_cost(accounting, expected_type, found_type)?; if !expected_type.admits_type(&StacksEpochId::Epoch21, found_type)? { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(found_type.clone()), ) @@ -334,7 +337,7 @@ impl FunctionType { } } Err( - CheckErrors::UnionTypeError(arg_types.clone(), Box::new(found_type.clone())) + CheckErrorKind::UnionTypeError(arg_types.clone(), Box::new(found_type.clone())) .into(), ) } @@ -363,12 +366,12 @@ impl FunctionType { } let (first, rest) = args .split_first() - .ok_or(CheckErrors::RequiresAtLeastArguments(1, args.len()))?; + .ok_or(CheckErrorKind::RequiresAtLeastArguments(1, args.len()))?; analysis_typecheck_cost(accounting, &TypeSignature::IntType, first)?; let return_type = match first { TypeSignature::IntType => Ok(TypeSignature::IntType), TypeSignature::UIntType => Ok(TypeSignature::UIntType), - _ => Err(CheckErrors::UnionTypeError( + _ => Err(CheckErrorKind::UnionTypeError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(first.clone()), )), @@ -376,7 +379,7 @@ impl FunctionType { for found_type in rest.iter() { analysis_typecheck_cost(accounting, &TypeSignature::IntType, found_type)?; if found_type != &return_type { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(return_type.clone()), Box::new(found_type.clone()), ) @@ -410,7 +413,7 @@ impl FunctionType { }; if !first_type_supported { - return Err(CheckErrors::UnionTypeError( + return Err(CheckErrorKind::UnionTypeError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -452,7 +455,7 @@ impl FunctionType { }; if !pair_of_types_matches { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(first.clone()), Box::new(second.clone()), ) @@ -473,7 +476,7 @@ impl FunctionType { value: &Value, depth: u8, clarity_version: ClarityVersion, - ) -> Result { + ) -> Result { if clarity_version >= ClarityVersion::Clarity2 { // In Clarity2, we recurse into complex data types self.clarity2_principal_to_callable_type(value, depth) @@ -495,9 +498,9 @@ impl FunctionType { &self, value: &Value, depth: u8, - ) -> Result { + ) -> Result { if depth > MAX_TYPE_DEPTH { - return Err(CheckErrors::TypeSignatureTooDeep.into()); + return Err(CheckErrorKind::TypeSignatureTooDeep.into()); } Ok(match value { @@ -564,10 +567,10 @@ impl FunctionType { db: &mut AnalysisDatabase, clarity_version: ClarityVersion, func_args: &[Value], - ) -> Result { + ) -> Result { let (expected_args, returns) = match self { FunctionType::Fixed(FixedFunction { args, returns }) => (args, returns), - _ => return Err(CheckErrors::Expects("Unexpected function type".into()).into()), + _ => return Err(CheckErrorKind::Expects("Unexpected function type".into()).into()), }; check_argument_count(expected_args.len(), func_args)?; @@ -581,7 +584,7 @@ impl FunctionType { let contract_to_check = db .load_contract(contract, &StacksEpochId::Epoch21)? .ok_or_else(|| { - CheckErrors::NoSuchContract(contract.name.to_string()) + CheckErrorKind::NoSuchContract(contract.name.to_string()) })?; let trait_definition = db .get_defined_trait( @@ -589,8 +592,8 @@ impl FunctionType { &trait_id.name, &StacksEpochId::Epoch21, ) - .map_err(|_| CheckErrors::Expects("Failed to get trait".into()))? - .ok_or(CheckErrors::NoSuchContract( + .map_err(|_| CheckErrorKind::Expects("Failed to get trait".into()))? + .ok_or(CheckErrorKind::NoSuchContract( trait_id.contract_identifier.to_string(), ))?; contract_to_check.check_trait_compliance( @@ -602,7 +605,7 @@ impl FunctionType { (expected_type, value) => { if !expected_type.admits(&StacksEpochId::Epoch21, value)? { let actual_type = TypeSignature::type_of(value)?; - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(actual_type.clone()), ) @@ -636,12 +639,12 @@ fn check_function_arg_signature( cost_tracker: &mut T, expected_sig: &FunctionArgSignature, actual_type: &TypeSignature, -) -> Result<(), CheckError> { +) -> Result<(), StaticCheckError> { match expected_sig { FunctionArgSignature::Single(expected_type) => { analysis_typecheck_cost(cost_tracker, expected_type, actual_type)?; if !expected_type.admits_type(&StacksEpochId::Epoch21, actual_type)? { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(actual_type.clone()), ) @@ -658,7 +661,7 @@ fn check_function_arg_signature( } } if !admitted { - return Err(CheckErrors::UnionTypeError( + return Err(CheckErrorKind::UnionTypeError( expected_types.clone(), Box::new(actual_type.clone()), ) @@ -724,7 +727,7 @@ pub fn clarity2_trait_check_trait_compliance( expected_trait_identifier: &TraitIdentifier, expected_trait: &BTreeMap, tracker: &mut T, -) -> Result<(), CheckError> { +) -> Result<(), StaticCheckError> { // Shortcut for the simple case when the two traits are the same. if actual_trait_identifier == expected_trait_identifier { return Ok(()); @@ -739,14 +742,14 @@ pub fn clarity2_trait_check_trait_compliance( func, tracker, ) { - return Err(CheckErrors::IncompatibleTrait( + return Err(CheckErrorKind::IncompatibleTrait( Box::new(expected_trait_identifier.clone()), Box::new(actual_trait_identifier.clone()), ) .into()); } } else { - return Err(CheckErrors::IncompatibleTrait( + return Err(CheckErrorKind::IncompatibleTrait( Box::new(expected_trait_identifier.clone()), Box::new(actual_trait_identifier.clone()), ) @@ -765,9 +768,9 @@ fn clarity2_inner_type_check_type( expected_type: &TypeSignature, depth: u8, tracker: &mut T, -) -> Result { +) -> Result { if depth > MAX_TYPE_DEPTH { - return Err(CheckErrors::TypeSignatureTooDeep.into()); + return Err(CheckErrorKind::TypeSignatureTooDeep.into()); } // Recurse into values to check embedded traits properly @@ -820,7 +823,7 @@ fn clarity2_inner_type_check_type( tracker, )?; } else { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(actual_type.clone()), ) @@ -832,7 +835,7 @@ fn clarity2_inner_type_check_type( TypeSignature::TupleType(expected_tuple_type), ) => { if expected_tuple_type.get_type_map().len() != atom_tuple_type.get_type_map().len() { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(actual_type.clone()), ) @@ -852,7 +855,7 @@ fn clarity2_inner_type_check_type( )?; } None => { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(actual_type.clone()), ) @@ -898,7 +901,9 @@ fn clarity2_inner_type_check_type( } None => { runtime_cost(ClarityCostFunction::AnalysisFetchContractEntry, tracker, 1)?; - return Err(CheckErrors::NoSuchContract(contract_identifier.to_string()).into()); + return Err( + CheckErrorKind::NoSuchContract(contract_identifier.to_string()).into(), + ); } }; let expected_trait = @@ -928,7 +933,7 @@ fn clarity2_inner_type_check_type( (TypeSignature::NoType, _) => (), (_, _) => { if !expected_type.admits_type(&StacksEpochId::Epoch21, actual_type)? { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(actual_type.clone()), ) @@ -944,13 +949,13 @@ fn clarity2_lookup_trait( contract_context: Option<&ContractContext>, trait_id: &TraitIdentifier, tracker: &mut T, -) -> Result, CheckError> { +) -> Result, StaticCheckError> { if let Some(contract_context) = contract_context { // If the trait is from this contract, then it must be in the context or it doesn't exist. if contract_context.is_contract(&trait_id.contract_identifier) { return Ok(contract_context .get_trait(trait_id) - .ok_or(CheckErrors::NoSuchTrait( + .ok_or(CheckErrorKind::NoSuchTrait( trait_id.contract_identifier.to_string(), trait_id.name.to_string(), ))? @@ -977,7 +982,7 @@ fn clarity2_lookup_trait( } Ok(None) => { runtime_cost(ClarityCostFunction::AnalysisUseTraitEntry, tracker, 1)?; - Err(CheckErrors::NoSuchTrait( + Err(CheckErrorKind::NoSuchTrait( trait_id.contract_identifier.to_string(), trait_id.name.to_string(), ) @@ -992,7 +997,7 @@ fn clarity2_lookup_trait( fn trait_type_size( trait_sig: &BTreeMap, -) -> Result { +) -> Result { let mut total_size = 0; for (_func_name, value) in trait_sig.iter() { total_size = total_size.cost_overflow_add(value.total_type_size()?)?; @@ -1000,7 +1005,7 @@ fn trait_type_size( Ok(total_size) } -fn contract_analysis_size(contract: &ContractAnalysis) -> Result { +fn contract_analysis_size(contract: &ContractAnalysis) -> Result { let mut total_size = contract.public_function_types.len() as u64; total_size = total_size.cost_overflow_add(contract.read_only_function_types.len() as u64)?; Ok(total_size) @@ -1009,20 +1014,20 @@ fn contract_analysis_size(contract: &ContractAnalysis) -> Result Result, CheckError> { +) -> Result, StaticCheckError> { if let Some(variable) = NativeVariables::lookup_by_name_at_version(variable_name, version) { use crate::vm::variables::NativeVariables::*; let var_type = match variable { TxSender => TypeSignature::PrincipalType, TxSponsor => TypeSignature::new_option(TypeSignature::PrincipalType) - .map_err(|_| CheckErrors::Expects("Bad construction".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad construction".into()))?, ContractCaller => TypeSignature::PrincipalType, BlockHeight => TypeSignature::UIntType, StacksBlockHeight => TypeSignature::UIntType, TenureHeight => TypeSignature::UIntType, BurnBlockHeight => TypeSignature::UIntType, NativeNone => TypeSignature::new_option(no_type()) - .map_err(|_| CheckErrors::Expects("Bad construction".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad construction".into()))?, NativeTrue => TypeSignature::BoolType, NativeFalse => TypeSignature::BoolType, TotalLiquidMicroSTX => TypeSignature::UIntType, @@ -1072,7 +1077,10 @@ impl<'a, 'b> TypeChecker<'a, 'b> { self.cost_track } - pub fn track_return_type(&mut self, return_type: TypeSignature) -> Result<(), CheckError> { + pub fn track_return_type( + &mut self, + return_type: TypeSignature, + ) -> Result<(), StaticCheckError> { runtime_cost( ClarityCostFunction::AnalysisTypeCheck, self, @@ -1088,7 +1096,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &return_type, ) .map_err(|_| { - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( Box::new(expected_type), Box::new(return_type), ) @@ -1107,7 +1115,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { } } - pub fn run(&mut self, contract_analysis: &ContractAnalysis) -> Result<(), CheckError> { + pub fn run(&mut self, contract_analysis: &ContractAnalysis) -> Result<(), StaticCheckError> { // charge for the eventual storage cost of the analysis -- // it is linear in the size of the AST. let mut size: u64 = 0; @@ -1119,7 +1127,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { } Err(e) => Err(e), })? - .ok_or_else(|| CheckErrors::Expects("Expected a depth result".into()))?; + .ok_or_else(|| CheckErrorKind::Expects("Expected a depth result".into()))?; } runtime_cost(ClarityCostFunction::AnalysisStorage, self, size)?; @@ -1148,7 +1156,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { expr: &SymbolicExpression, context: &TypingContext, expected_type: &TypeSignature, - ) -> Result { + ) -> Result { // Clarity 2 allows traits embedded in compound types and allows // implicit casts between compatible traits, while Clarity 1 does not. if self.clarity_version >= ClarityVersion::Clarity2 { @@ -1169,7 +1177,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, expr: &SymbolicExpression, context: &TypingContext, - ) -> Result { + ) -> Result { runtime_cost(ClarityCostFunction::AnalysisVisit, self, 0)?; let mut result = self.inner_type_check(expr, context); @@ -1189,14 +1197,14 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, args: &[SymbolicExpression], context: &TypingContext, - ) -> Result { + ) -> Result { let mut last_return = None; let mut return_failure = Ok(()); for ix in 0..args.len() { let type_return = self.type_check(&args[ix], context)?; if ix + 1 < args.len() { if type_return.is_response_type() { - return_failure = Err(CheckErrors::UncheckedIntermediaryResponses); + return_failure = Err(CheckErrorKind::UncheckedIntermediaryResponses); } } else { last_return = Some(type_return); @@ -1204,7 +1212,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { } let last_return = last_return - .ok_or_else(|| CheckError::new(CheckErrors::CheckerImplementationFailure))?; + .ok_or_else(|| StaticCheckError::new(CheckErrorKind::CheckerImplementationFailure))?; return_failure?; Ok(last_return) @@ -1214,7 +1222,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, args: &[SymbolicExpression], context: &TypingContext, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { let mut result = Vec::with_capacity(args.len()); for arg in args.iter() { // don't use map here, since type_check has side-effects. @@ -1230,7 +1238,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { context: &TypingContext, epoch: StacksEpochId, clarity_version: ClarityVersion, - ) -> Result { + ) -> Result { if epoch <= StacksEpochId::Epoch2_05 { let typed_args = self.type_check_all(args, context)?; return func_type.check_args(self, &typed_args, epoch, clarity_version); @@ -1267,9 +1275,9 @@ impl<'a, 'b> TypeChecker<'a, 'b> { } } if let Err(mut check_error) = check_result { - if let CheckErrors::IncorrectArgumentCount(expected, _actual) = *check_error.err { + if let CheckErrorKind::IncorrectArgumentCount(expected, _actual) = *check_error.err { check_error.err = - Box::new(CheckErrors::IncorrectArgumentCount(expected, args.len())); + Box::new(CheckErrorKind::IncorrectArgumentCount(expected, args.len())); check_error.diagnostic = Diagnostic::err(check_error.err.as_ref()); } // accumulate the checking costs @@ -1296,13 +1304,13 @@ impl<'a, 'b> TypeChecker<'a, 'b> { signature: &[SymbolicExpression], body: &SymbolicExpression, context: &TypingContext, - ) -> Result<(ClarityName, FixedFunction), CheckError> { + ) -> Result<(ClarityName, FixedFunction), StaticCheckError> { let (function_name, args) = signature .split_first() - .ok_or(CheckErrors::RequiresAtLeastArguments(1, 0))?; + .ok_or(CheckErrorKind::RequiresAtLeastArguments(1, 0))?; if self.epoch.limits_parameter_and_method_count() && args.len() > MAX_FUNCTION_PARAMETERS { - return Err(CheckErrors::TooManyFunctionParameters( + return Err(CheckErrorKind::TooManyFunctionParameters( args.len(), MAX_FUNCTION_PARAMETERS, ) @@ -1311,8 +1319,8 @@ impl<'a, 'b> TypeChecker<'a, 'b> { let function_name = function_name .match_atom() - .ok_or(CheckErrors::BadFunctionName)?; - let args = parse_name_type_pairs::<(), CheckError>( + .ok_or(CheckErrorKind::BadFunctionName)?; + let args = parse_name_type_pairs::<(), StaticCheckError>( StacksEpochId::Epoch21, args, SyntaxBindingErrorType::Eval, @@ -1320,7 +1328,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { )?; if self.function_return_tracker.is_some() { - return Err(CheckErrors::Expects( + return Err(CheckErrorKind::Expects( "Interpreter error: Previous function define left dirty typecheck state.".into(), ) .into()); @@ -1376,7 +1384,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &return_type, ) .map_err(|_| { - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( Box::new(expected.clone()), Box::new(return_type), ) @@ -1410,16 +1418,16 @@ impl<'a, 'b> TypeChecker<'a, 'b> { map_name: &ClarityName, key_type: &SymbolicExpression, value_type: &SymbolicExpression, - ) -> Result<(ClarityName, (TypeSignature, TypeSignature)), CheckError> { + ) -> Result<(ClarityName, (TypeSignature, TypeSignature)), StaticCheckError> { self.type_map.set_type(key_type, no_type())?; self.type_map.set_type(value_type, no_type())?; // should we set the type of the subexpressions of the signature to no-type as well? let key_type = TypeSignature::parse_type_repr(StacksEpochId::Epoch21, key_type, &mut ()) - .map_err(|_| CheckErrors::BadMapTypeDefinition)?; + .map_err(|_| CheckErrorKind::BadMapTypeDefinition)?; let value_type = TypeSignature::parse_type_repr(StacksEpochId::Epoch21, value_type, &mut ()) - .map_err(|_| CheckErrors::BadMapTypeDefinition)?; + .map_err(|_| CheckErrorKind::BadMapTypeDefinition)?; Ok((map_name.clone(), (key_type, value_type))) } @@ -1430,7 +1438,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { function: &str, args: &[SymbolicExpression], context: &TypingContext, - ) -> Option> { + ) -> Option> { if let Some(ref native_function) = NativeFunctions::lookup_by_name_at_version(function, &self.clarity_version) { @@ -1448,22 +1456,22 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, expression: &[SymbolicExpression], context: &TypingContext, - ) -> Result { + ) -> Result { let (function_name, args) = expression .split_first() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; self.type_map.set_type(function_name, no_type())?; let function_name = function_name .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; if let Some(type_result) = self.try_native_function_check(function_name, args, context) { type_result } else { let function = match self.get_function_type(function_name) { Some(FunctionType::Fixed(function)) => Ok(function), - _ => Err(CheckErrors::UnknownFunction(function_name.to_string())), + _ => Err(CheckErrorKind::UnknownFunction(function_name.to_string())), }?; for (expected_type, found_type) in function.args.iter().map(|x| &x.signature).zip(args) @@ -1479,7 +1487,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, name: &str, context: &TypingContext, - ) -> Result { + ) -> Result { runtime_cost(ClarityCostFunction::AnalysisLookupVariableConst, self, 0)?; if let Some(type_result) = type_reserved_variable(name, &self.clarity_version)? { @@ -1495,7 +1503,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { // be undefined. This early error prevents a cost function error // due to `context.depth` being 0. if context.depth == 0 { - return Err(CheckErrors::UndefinedVariable(name.to_string()).into()); + return Err(CheckErrorKind::UndefinedVariable(name.to_string()).into()); } runtime_cost( @@ -1507,7 +1515,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { if let Some(type_result) = context.lookup_variable_type(name) { Ok(type_result.clone()) } else { - Err(CheckErrors::UndefinedVariable(name.to_string()).into()) + Err(CheckErrorKind::UndefinedVariable(name.to_string()).into()) } } } @@ -1517,7 +1525,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { expr: &SymbolicExpression, context: &TypingContext, expected_type: &TypeSignature, - ) -> Result { + ) -> Result { if let ( LiteralValue(Value::Principal(PrincipalData::Contract(ref contract_identifier))), TypeSignature::CallableType(CallableSubtype::Trait(trait_identifier)), @@ -1526,7 +1534,9 @@ impl<'a, 'b> TypeChecker<'a, 'b> { let contract_to_check = self .db .load_contract(contract_identifier, &StacksEpochId::Epoch21)? - .ok_or(CheckErrors::NoSuchContract(contract_identifier.to_string()))?; + .ok_or(CheckErrorKind::NoSuchContract( + contract_identifier.to_string(), + ))?; let contract_defining_trait = self .db @@ -1534,13 +1544,13 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &trait_identifier.contract_identifier, &StacksEpochId::Epoch21, )? - .ok_or(CheckErrors::NoSuchContract( + .ok_or(CheckErrorKind::NoSuchContract( trait_identifier.contract_identifier.to_string(), ))?; let trait_definition = contract_defining_trait .get_defined_trait(&trait_identifier.name) - .ok_or(CheckErrors::NoSuchTrait( + .ok_or(CheckErrorKind::NoSuchTrait( trait_identifier.contract_identifier.to_string(), trait_identifier.name.to_string(), ))?; @@ -1557,7 +1567,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { analysis_typecheck_cost(self, expected_type, &actual_type)?; if !expected_type.admits_type(&StacksEpochId::Epoch21, &actual_type)? { - let mut err: CheckError = CheckErrors::TypeError( + let mut err: StaticCheckError = CheckErrorKind::TypeError( Box::new(expected_type.clone()), Box::new(actual_type.clone()), ) @@ -1574,14 +1584,14 @@ impl<'a, 'b> TypeChecker<'a, 'b> { expr: &SymbolicExpression, context: &TypingContext, expected_type: &TypeSignature, - ) -> Result { + ) -> Result { let mut expr_type = match expr.expr { AtomValue(ref value) => TypeSignature::type_of(value)?, LiteralValue(ref value) => TypeSignature::literal_type_of(value)?, Atom(ref name) => self.lookup_variable(name, context)?, List(ref expression) => self.type_check_function_application(expression, context)?, TraitReference(_, _) | Field(_) => { - return Err(CheckErrors::UnexpectedTraitOrFieldReference.into()); + return Err(CheckErrorKind::UnexpectedTraitOrFieldReference.into()); } }; @@ -1612,14 +1622,14 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, expr: &SymbolicExpression, context: &TypingContext, - ) -> Result { + ) -> Result { let expr_type = match expr.expr { AtomValue(ref value) => TypeSignature::type_of(value)?, LiteralValue(ref value) => TypeSignature::literal_type_of(value)?, Atom(ref name) => self.lookup_variable(name, context)?, List(ref expression) => self.type_check_function_application(expression, context)?, TraitReference(_, _) | Field(_) => { - return Err(CheckErrors::UnexpectedTraitOrFieldReference.into()); + return Err(CheckErrorKind::UnexpectedTraitOrFieldReference.into()); } }; @@ -1637,7 +1647,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { var_name: &ClarityName, var_type: &SymbolicExpression, context: &mut TypingContext, - ) -> Result<(ClarityName, TypeSignature), CheckError> { + ) -> Result<(ClarityName, TypeSignature), StaticCheckError> { let var_type = self.type_check(var_type, context)?; Ok((var_name.clone(), var_type)) } @@ -1648,10 +1658,10 @@ impl<'a, 'b> TypeChecker<'a, 'b> { var_type: &SymbolicExpression, initial: &SymbolicExpression, context: &mut TypingContext, - ) -> Result<(ClarityName, TypeSignature), CheckError> { + ) -> Result<(ClarityName, TypeSignature), StaticCheckError> { let expected_type = TypeSignature::parse_type_repr::<()>(StacksEpochId::Epoch21, var_type, &mut ()) - .map_err(|_e| CheckErrors::DefineVariableBadSignature)?; + .map_err(|_e| CheckErrorKind::DefineVariableBadSignature)?; self.type_check_expects(initial, context, &expected_type)?; @@ -1663,7 +1673,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { token_name: &ClarityName, bound: Option<&SymbolicExpression>, context: &mut TypingContext, - ) -> Result { + ) -> Result { if let Some(bound) = bound { self.type_check_expects(bound, context, &TypeSignature::UIntType)?; } @@ -1676,10 +1686,10 @@ impl<'a, 'b> TypeChecker<'a, 'b> { asset_name: &ClarityName, nft_type: &SymbolicExpression, _context: &mut TypingContext, - ) -> Result<(ClarityName, TypeSignature), CheckError> { + ) -> Result<(ClarityName, TypeSignature), StaticCheckError> { let asset_type = TypeSignature::parse_type_repr::<()>(StacksEpochId::Epoch21, nft_type, &mut ()) - .map_err(|_| CheckErrors::DefineNFTBadSignature)?; + .map_err(|_| CheckErrorKind::DefineNFTBadSignature)?; Ok((asset_name.clone(), asset_type)) } @@ -1689,7 +1699,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { trait_name: &ClarityName, function_types: &[SymbolicExpression], _context: &mut TypingContext, - ) -> Result<(ClarityName, BTreeMap), CheckError> { + ) -> Result<(ClarityName, BTreeMap), StaticCheckError> { let trait_signature = TypeSignature::parse_trait_type_repr( function_types, &mut (), @@ -1705,7 +1715,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { &mut self, expression: &SymbolicExpression, context: &mut TypingContext, - ) -> Result, CheckError> { + ) -> Result, StaticCheckError> { if let Some(define_type) = DefineFunctionsParsed::try_parse(expression)? { match define_type { DefineFunctionsParsed::Constant { name, value } => { @@ -1754,7 +1764,7 @@ impl<'a, 'b> TypeChecker<'a, 'b> { .add_public_function_type(f_name, FunctionType::Fixed(f_type))?; return Ok(Some(())); } else { - return Err(CheckErrors::PublicFunctionMustReturnResponse(Box::new( + return Err(CheckErrorKind::PublicFunctionMustReturnResponse(Box::new( f_type.returns, )) .into()); @@ -1897,7 +1907,9 @@ impl<'a, 'b> TypeChecker<'a, 'b> { None => { // still had to do a db read, even if it didn't exist! runtime_cost(ClarityCostFunction::AnalysisUseTraitEntry, self, 1)?; - return Err(CheckErrors::TraitReferenceUnknown(name.to_string()).into()); + return Err( + CheckErrorKind::TraitReferenceUnknown(name.to_string()).into() + ); } } } diff --git a/clarity/src/vm/analysis/type_checker/v2_1/natives/assets.rs b/clarity/src/vm/analysis/type_checker/v2_1/natives/assets.rs index fbd2e251c49..098300af775 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/natives/assets.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/natives/assets.rs @@ -17,7 +17,7 @@ use stacks_common::consts::TOKEN_TRANSFER_MEMO_LENGTH; use super::{TypeChecker, TypingContext}; -use crate::vm::analysis::errors::{check_argument_count, CheckError, CheckErrors}; +use crate::vm::analysis::errors::{check_argument_count, CheckErrorKind, StaticCheckError}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; use crate::vm::representations::SymbolicExpression; @@ -27,16 +27,16 @@ pub fn check_special_get_owner( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_asset_type = checker .contract_context .get_nft_type(asset_name) .cloned() - .ok_or_else(|| CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or_else(|| CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -55,13 +55,13 @@ pub fn check_special_get_balance( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; if !checker.contract_context.ft_exists(asset_name) { - return Err(CheckErrors::NoSuchFT(asset_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(asset_name.to_string()).into()); } runtime_cost(ClarityCostFunction::AnalysisTypeLookup, checker, 1)?; @@ -76,16 +76,16 @@ pub fn check_special_mint_asset( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; let expected_asset_type = checker .contract_context .get_nft_type(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))? + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))? .clone(); // this clone shouldn't be strictly necessary, but to use `type_check_expects` with this, it would have to be. runtime_cost( @@ -107,10 +107,10 @@ pub fn check_special_mint_token( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_amount: TypeSignature = TypeSignature::UIntType; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; @@ -121,7 +121,7 @@ pub fn check_special_mint_token( checker.type_check_expects(&args[2], context, &expected_owner_type)?; if !checker.contract_context.ft_exists(asset_name) { - return Err(CheckErrors::NoSuchFT(asset_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(asset_name.to_string()).into()); } Ok(TypeSignature::ResponseType(Box::new(( @@ -134,16 +134,16 @@ pub fn check_special_transfer_asset( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; let expected_asset_type = checker .contract_context .get_nft_type(token_name) - .ok_or(CheckErrors::NoSuchNFT(token_name.to_string()))? + .ok_or(CheckErrorKind::NoSuchNFT(token_name.to_string()))? .clone(); runtime_cost( @@ -166,10 +166,10 @@ pub fn check_special_transfer_token( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_amount: TypeSignature = TypeSignature::UIntType; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; @@ -181,7 +181,7 @@ pub fn check_special_transfer_token( checker.type_check_expects(&args[3], context, &expected_owner_type)?; // recipient if !checker.contract_context.ft_exists(token_name) { - return Err(CheckErrors::NoSuchFT(token_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(token_name.to_string()).into()); } Ok(TypeSignature::ResponseType(Box::new(( @@ -194,7 +194,7 @@ pub fn check_special_stx_transfer( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; let amount_type: TypeSignature = TypeSignature::UIntType; @@ -217,7 +217,7 @@ pub fn check_special_stx_transfer_memo( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; let amount_type: TypeSignature = TypeSignature::UIntType; @@ -225,7 +225,7 @@ pub fn check_special_stx_transfer_memo( let to_type: TypeSignature = TypeSignature::PrincipalType; let memo_type: TypeSignature = TypeSignature::SequenceType(SequenceSubtype::BufferType( BufferLength::try_from(TOKEN_TRANSFER_MEMO_LENGTH as u32) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, )); runtime_cost(ClarityCostFunction::AnalysisTypeLookup, checker, 0)?; @@ -245,13 +245,13 @@ pub fn check_special_get_token_supply( checker: &mut TypeChecker, args: &[SymbolicExpression], _context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; if !checker.contract_context.ft_exists(asset_name) { - return Err(CheckErrors::NoSuchFT(asset_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(asset_name.to_string()).into()); } runtime_cost(ClarityCostFunction::AnalysisTypeLookup, checker, 1)?; @@ -263,16 +263,16 @@ pub fn check_special_burn_asset( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; let expected_asset_type = checker .contract_context .get_nft_type(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))? + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))? .clone(); // this clone shouldn't be strictly necessary, but to use `type_check_expects` with this, it would have to be. runtime_cost( @@ -294,10 +294,10 @@ pub fn check_special_burn_token( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let expected_amount: TypeSignature = TypeSignature::UIntType; let expected_owner_type: TypeSignature = TypeSignature::PrincipalType; @@ -308,7 +308,7 @@ pub fn check_special_burn_token( checker.type_check_expects(&args[2], context, &expected_owner_type)?; if !checker.contract_context.ft_exists(asset_name) { - return Err(CheckErrors::NoSuchFT(asset_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchFT(asset_name.to_string()).into()); } Ok(TypeSignature::ResponseType(Box::new(( diff --git a/clarity/src/vm/analysis/type_checker/v2_1/natives/conversions.rs b/clarity/src/vm/analysis/type_checker/v2_1/natives/conversions.rs index 783104b3a9e..874084f16f6 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/natives/conversions.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/natives/conversions.rs @@ -1,11 +1,11 @@ -use clarity_types::errors::CheckErrors; +use clarity_types::errors::CheckErrorKind; use clarity_types::types::{StringSubtype, MAX_TO_ASCII_BUFFER_LEN}; use stacks_common::types::StacksEpochId; use super::TypeChecker; use crate::vm::analysis::read_only_checker::check_argument_count; use crate::vm::analysis::type_checker::contexts::TypingContext; -use crate::vm::analysis::CheckError; +use crate::vm::analysis::StaticCheckError; use crate::vm::types::{BufferLength, SequenceSubtype, TypeSignature, TypeSignatureExt as _}; use crate::vm::SymbolicExpression; @@ -18,14 +18,14 @@ pub fn check_special_to_consensus_buff( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input_type = checker.type_check(&args[0], context)?; let buffer_max_len = BufferLength::try_from(input_type.max_serialized_size()?)?; TypeSignature::new_option(TypeSignature::SequenceType(SequenceSubtype::BufferType( buffer_max_len, ))) - .map_err(CheckError::from) + .map_err(StaticCheckError::from) } /// `from-consensus-buff?` admits exactly two arguments: @@ -37,11 +37,11 @@ pub fn check_special_from_consensus_buff( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let result_type = TypeSignature::parse_type_repr(StacksEpochId::Epoch21, &args[0], checker)?; checker.type_check_expects(&args[1], context, &TypeSignature::BUFFER_MAX)?; - TypeSignature::new_option(result_type).map_err(CheckError::from) + TypeSignature::new_option(result_type).map_err(StaticCheckError::from) } /// `to-ascii?` admits exactly one argument, a value to convert to a @@ -58,11 +58,11 @@ pub fn check_special_to_ascii( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input_type = checker.type_check( args.first() - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, )?; @@ -92,12 +92,12 @@ pub fn check_special_to_ascii( TypeSignature::TO_ASCII_BUFFER_MAX, TypeSignature::STRING_UTF8_MAX, ]; - return Err(CheckErrors::UnionTypeError(types, input_type.into()).into()); + return Err(CheckErrorKind::UnionTypeError(types, input_type.into()).into()); } }; Ok( TypeSignature::new_response(result_type, TypeSignature::UIntType).map_err(|_| { - CheckErrors::Expects("FATAL: Legal Clarity response type marked invalid".into()) + CheckErrorKind::Expects("FATAL: Legal Clarity response type marked invalid".into()) })?, ) } diff --git a/clarity/src/vm/analysis/type_checker/v2_1/natives/maps.rs b/clarity/src/vm/analysis/type_checker/v2_1/natives/maps.rs index 2dbc2407983..0b95c44f86c 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/natives/maps.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/natives/maps.rs @@ -17,7 +17,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::analysis::type_checker::v2_1::{ - check_arguments_at_least, CheckError, CheckErrors, TypeChecker, TypingContext, + check_arguments_at_least, CheckErrorKind, StaticCheckError, TypeChecker, TypingContext, }; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{analysis_typecheck_cost, runtime_cost}; @@ -28,17 +28,17 @@ pub fn check_special_fetch_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::BadMapName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::BadMapName)?; let key_type = checker.type_check(&args[1], context)?; let (expected_key_type, value_type) = checker .contract_context .get_map_type(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -55,7 +55,7 @@ pub fn check_special_fetch_entry( let option_type = TypeSignature::new_option(value_type.clone())?; if !expected_key_type.admits_type(&StacksEpochId::Epoch21, &key_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_key_type.clone()), Box::new(key_type), ))) @@ -68,17 +68,17 @@ pub fn check_special_delete_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::BadMapName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::BadMapName)?; let key_type = checker.type_check(&args[1], context)?; let (expected_key_type, _) = checker .contract_context .get_map_type(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -88,7 +88,7 @@ pub fn check_special_delete_entry( analysis_typecheck_cost(&mut checker.cost_track, expected_key_type, &key_type)?; if !expected_key_type.admits_type(&StacksEpochId::Epoch21, &key_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_key_type.clone()), Box::new(key_type), ))) @@ -101,10 +101,10 @@ fn check_set_or_insert_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(3, args)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::BadMapName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::BadMapName)?; let key_type = checker.type_check(&args[1], context)?; let value_type = checker.type_check(&args[2], context)?; @@ -112,7 +112,7 @@ fn check_set_or_insert_entry( let (expected_key_type, expected_value_type) = checker .contract_context .get_map_type(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -129,12 +129,12 @@ fn check_set_or_insert_entry( analysis_typecheck_cost(&mut checker.cost_track, expected_value_type, &value_type)?; if !expected_key_type.admits_type(&StacksEpochId::Epoch21, &key_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_key_type.clone()), Box::new(key_type), ))) } else if !expected_value_type.admits_type(&StacksEpochId::Epoch21, &value_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_value_type.clone()), Box::new(value_type), ))) @@ -147,7 +147,7 @@ pub fn check_special_set_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_set_or_insert_entry(checker, args, context) } @@ -155,6 +155,6 @@ pub fn check_special_insert_entry( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_set_or_insert_entry(checker, args, context) } diff --git a/clarity/src/vm/analysis/type_checker/v2_1/natives/mod.rs b/clarity/src/vm/analysis/type_checker/v2_1/natives/mod.rs index 1f680abf5eb..267be5c9cb3 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/natives/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/natives/mod.rs @@ -20,7 +20,7 @@ use super::{ check_argument_count, check_arguments_at_least, check_arguments_at_most, compute_typecheck_cost, no_type, TypeChecker, TypingContext, }; -use crate::vm::analysis::errors::{CheckError, CheckErrors, SyntaxBindingErrorType}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError, SyntaxBindingErrorType}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{analysis_typecheck_cost, runtime_cost, CostErrors, CostTracker}; use crate::vm::diagnostic::DiagnosableError; @@ -54,7 +54,7 @@ pub struct SpecialNativeFunction( &mut TypeChecker, &[SymbolicExpression], &TypingContext, - ) -> Result, + ) -> Result, ); pub struct SimpleNativeFunction(pub FunctionType); @@ -62,7 +62,7 @@ fn check_special_list_cons( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { let mut result = Vec::with_capacity(args.len()); let mut entries_size: Option = Some(0); let mut costs = Vec::with_capacity(args.len()); @@ -76,7 +76,7 @@ fn check_special_list_cons( ClarityCostFunction::AnalysisListItemsCheck, &[ty_size.into()], ) - .map_err(CheckErrors::from) + .map_err(CheckErrorKind::from) }); costs.push(cost); @@ -97,7 +97,7 @@ fn check_special_list_cons( checker.add_cost(cost?)?; } if entries_size.is_none() { - return Err(CheckErrors::ValueTooLarge.into()); + return Err(CheckErrorKind::ValueTooLarge.into()); } let typed_args = result; TypeSignature::parent_list_type(&typed_args) @@ -109,7 +109,7 @@ fn check_special_print( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; checker.type_check(&args[0], context) } @@ -118,7 +118,7 @@ fn check_special_as_contract( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; checker.type_check(&args[0], context) } @@ -127,7 +127,7 @@ fn check_special_at_block( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_32)?; checker.type_check(&args[1], context) @@ -137,7 +137,7 @@ fn check_special_begin( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; checker.type_check_consecutive_statements(args, context) @@ -147,7 +147,7 @@ fn inner_handle_tuple_get( tuple_type_sig: &TupleTypeSignature, field_to_get: &str, checker: &mut TypeChecker, -) -> Result { +) -> Result { runtime_cost( ClarityCostFunction::AnalysisCheckTupleGet, checker, @@ -156,7 +156,7 @@ fn inner_handle_tuple_get( let return_type = tuple_type_sig .field_type(field_to_get) - .ok_or(CheckError::new(CheckErrors::NoSuchTupleField( + .ok_or(StaticCheckError::new(CheckErrorKind::NoSuchTupleField( field_to_get.to_string(), tuple_type_sig.clone(), )))? @@ -168,10 +168,12 @@ fn check_special_get( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let field_to_get = args[0].match_atom().ok_or(CheckErrors::BadTupleFieldName)?; + let field_to_get = args[0] + .match_atom() + .ok_or(CheckErrorKind::BadTupleFieldName)?; let argument_type = checker.type_check(&args[1], context)?; @@ -183,10 +185,10 @@ fn check_special_get( let option_type = TypeSignature::new_option(inner_type)?; Ok(option_type) } else { - Err(CheckErrors::ExpectedTuple(value_type_sig).into()) + Err(CheckErrorKind::ExpectedTuple(value_type_sig).into()) } } else { - Err(CheckErrors::ExpectedTuple(Box::new(argument_type)).into()) + Err(CheckErrorKind::ExpectedTuple(Box::new(argument_type)).into()) } } @@ -194,19 +196,19 @@ fn check_special_merge( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let res = checker.type_check(&args[0], context)?; let mut base = match res { TypeSignature::TupleType(tuple_sig) => Ok(tuple_sig), - _ => Err(CheckErrors::ExpectedTuple(Box::new(res.clone()))), + _ => Err(CheckErrorKind::ExpectedTuple(Box::new(res.clone()))), }?; let res = checker.type_check(&args[1], context)?; let mut update = match res { TypeSignature::TupleType(tuple_sig) => Ok(tuple_sig), - _ => Err(CheckErrors::ExpectedTuple(Box::new(res.clone()))), + _ => Err(CheckErrorKind::ExpectedTuple(Box::new(res.clone()))), }?; runtime_cost( ClarityCostFunction::AnalysisCheckTupleMerge, @@ -222,7 +224,7 @@ pub fn check_special_tuple_cons( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; let mut tuple_type_data = Vec::with_capacity(args.len()); @@ -254,7 +256,7 @@ pub fn check_special_tuple_cons( .saturating_add(var_type.size()?); tuple_type_data.push((var_name.clone(), var_type)); } else { - cons_error = Err(CheckErrors::BadTupleConstruction(format!( + cons_error = Err(CheckErrorKind::BadTupleConstruction(format!( "type size of {type_size} bytes exceeds maximum of {MAX_VALUE_SIZE} bytes" ))); } @@ -265,7 +267,7 @@ pub fn check_special_tuple_cons( cons_error?; let tuple_signature = TupleTypeSignature::try_from(tuple_type_data) - .map_err(|e| CheckErrors::BadTupleConstruction(e.message()))?; + .map_err(|e| CheckErrorKind::BadTupleConstruction(e.message()))?; Ok(TypeSignature::TupleType(tuple_signature)) } @@ -275,12 +277,12 @@ fn check_special_let( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; let binding_list = args[0] .match_list() - .ok_or(CheckError::new(CheckErrors::BadLetSyntax))?; + .ok_or(StaticCheckError::new(CheckErrorKind::BadLetSyntax))?; let mut out_context = context.extend()?; @@ -293,7 +295,7 @@ fn check_special_let( |var_name, var_sexp| { checker.contract_context.check_name_used(var_name)?; if out_context.lookup_variable_type(var_name).is_some() { - return Err(CheckError::new(CheckErrors::NameAlreadyUsed( + return Err(StaticCheckError::new(CheckErrorKind::NameAlreadyUsed( var_name.to_string(), ))); } @@ -330,17 +332,17 @@ fn check_special_fetch_var( checker: &mut TypeChecker, args: &[SymbolicExpression], _context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let var_name = args[0] .match_atom() - .ok_or(CheckError::new(CheckErrors::BadMapName))?; + .ok_or(StaticCheckError::new(CheckErrorKind::BadMapName))?; let value_type = checker .contract_context .get_persisted_variable_type(var_name) - .ok_or(CheckError::new(CheckErrors::NoSuchDataVariable( + .ok_or(StaticCheckError::new(CheckErrorKind::NoSuchDataVariable( var_name.to_string(), )))?; @@ -357,17 +359,17 @@ fn check_special_set_var( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let var_name = args[0].match_atom().ok_or(CheckErrors::BadMapName)?; + let var_name = args[0].match_atom().ok_or(CheckErrorKind::BadMapName)?; let value_type = checker.type_check(&args[1], context)?; let expected_value_type = checker .contract_context .get_persisted_variable_type(var_name) - .ok_or(CheckErrors::NoSuchDataVariable(var_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchDataVariable(var_name.to_string()))?; runtime_cost( ClarityCostFunction::AnalysisTypeLookup, @@ -377,7 +379,7 @@ fn check_special_set_var( analysis_typecheck_cost(&mut checker.cost_track, &value_type, expected_value_type)?; if !expected_value_type.admits_type(&StacksEpochId::Epoch21, &value_type)? { - Err(CheckError::new(CheckErrors::TypeError( + Err(StaticCheckError::new(CheckErrorKind::TypeError( Box::new(expected_value_type.clone()), Box::new(value_type), ))) @@ -390,7 +392,7 @@ fn check_special_equals( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; let mut arg_type = None; @@ -406,7 +408,7 @@ fn check_special_equals( costs.push(cost); arg_type = Some( TypeSignature::least_supertype(&StacksEpochId::Epoch21, &x_type, &cur_type) - .map_err(|_| CheckErrors::TypeError(Box::new(x_type), Box::new(cur_type))), + .map_err(|_| CheckErrorKind::TypeError(Box::new(x_type), Box::new(cur_type))), ); } } @@ -417,7 +419,7 @@ fn check_special_equals( // check if there was a least supertype failure. arg_type.ok_or_else(|| { - CheckErrors::Expects("Arg type should be set because arguments checked for >= 1".into()) + CheckErrorKind::Expects("Arg type should be set because arguments checked for >= 1".into()) })??; Ok(TypeSignature::BoolType) @@ -427,7 +429,7 @@ fn check_special_if( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BoolType)?; @@ -442,7 +444,7 @@ fn check_special_if( TypeSignature::least_supertype(&StacksEpochId::Epoch21, expr1, expr2) .and_then(|t| t.concretize()) .map_err(|_| { - CheckErrors::IfArmsMustMatch(Box::new(expr1.clone()), Box::new(expr2.clone())).into() + CheckErrorKind::IfArmsMustMatch(Box::new(expr1.clone()), Box::new(expr2.clone())).into() }) } @@ -450,12 +452,12 @@ fn check_contract_call( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let func_name = args[1] - .match_atom() - .ok_or(CheckError::new(CheckErrors::ContractCallExpectName))?; + let func_name = args[1].match_atom().ok_or(StaticCheckError::new( + CheckErrorKind::ContractCallExpectName, + ))?; checker.type_map.set_type(&args[1], no_type())?; let expected_sig = match &args[0].expr { @@ -479,7 +481,7 @@ fn check_contract_call( { Ok(function) } else { - Err(CheckError::new(CheckErrors::NoSuchPublicFunction( + Err(StaticCheckError::new(CheckErrorKind::NoSuchPublicFunction( contract_identifier.to_string(), func_name.to_string(), ))) @@ -502,21 +504,22 @@ fn check_contract_call( let trait_id = match context.lookup_trait_reference_type(trait_instance) { Some(trait_id) => trait_id, _ => { - return Err( - CheckErrors::TraitReferenceUnknown(trait_instance.to_string()).into(), - ); + return Err(CheckErrorKind::TraitReferenceUnknown( + trait_instance.to_string(), + ) + .into()); } }; runtime_cost(ClarityCostFunction::AnalysisLookupFunction, checker, 0)?; let trait_signature = checker.contract_context.get_trait(trait_id).ok_or( - CheckErrors::TraitReferenceUnknown(trait_id.name.to_string()), + CheckErrorKind::TraitReferenceUnknown(trait_id.name.to_string()), )?; let func_signature = trait_signature .get(func_name) - .ok_or(CheckErrors::TraitMethodUnknown( + .ok_or(CheckErrorKind::TraitMethodUnknown( trait_id.name.to_string(), func_name.to_string(), ))?; @@ -553,7 +556,7 @@ fn check_contract_call( { Ok(function) } else { - Err(CheckError::new(CheckErrors::NoSuchPublicFunction( + Err(StaticCheckError::new(CheckErrorKind::NoSuchPublicFunction( contract_identifier.to_string(), func_name.to_string(), ))) @@ -572,16 +575,17 @@ fn check_contract_call( } Some(var_type) => { // Any other typed constant is an error - return Err( - CheckErrors::ExpectedCallableType(Box::new(var_type.clone())).into(), - ); + return Err(CheckErrorKind::ExpectedCallableType(Box::new( + var_type.clone(), + )) + .into()); } _ => { // Dynamic dispatch let trait_id = match context.lookup_trait_reference_type(trait_instance) { Some(trait_id) => trait_id, _ => { - return Err(CheckErrors::TraitReferenceUnknown( + return Err(CheckErrorKind::TraitReferenceUnknown( trait_instance.to_string(), ) .into()); @@ -591,10 +595,10 @@ fn check_contract_call( runtime_cost(ClarityCostFunction::AnalysisLookupFunction, checker, 0)?; let trait_signature = checker.contract_context.get_trait(trait_id).ok_or( - CheckErrors::TraitReferenceUnknown(trait_id.name.to_string()), + CheckErrorKind::TraitReferenceUnknown(trait_id.name.to_string()), )?; let func_signature = trait_signature.get(func_name).ok_or( - CheckErrors::TraitMethodUnknown( + CheckErrorKind::TraitMethodUnknown( trait_id.name.to_string(), func_name.to_string(), ), @@ -611,7 +615,11 @@ fn check_contract_call( } } } - _ => return Err(CheckError::new(CheckErrors::ContractCallExpectName)), + _ => { + return Err(StaticCheckError::new( + CheckErrorKind::ContractCallExpectName, + )) + } }; check_argument_count(expected_sig.args.len(), &args[2..])?; @@ -626,17 +634,21 @@ fn check_contract_of( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let trait_instance = match &args[0].expr { SymbolicExpressionType::Atom(trait_instance) => trait_instance, - _ => return Err(CheckError::new(CheckErrors::ContractOfExpectsTrait)), + _ => { + return Err(StaticCheckError::new( + CheckErrorKind::ContractOfExpectsTrait, + )) + } }; let trait_id = match context.lookup_trait_reference_type(trait_instance) { Some(trait_id) => trait_id, - _ => return Err(CheckErrors::TraitReferenceUnknown(trait_instance.to_string()).into()), + _ => return Err(CheckErrorKind::TraitReferenceUnknown(trait_instance.to_string()).into()), }; runtime_cost(ClarityCostFunction::ContractOf, checker, 1)?; @@ -644,7 +656,7 @@ fn check_contract_of( checker .contract_context .get_trait(trait_id) - .ok_or_else(|| CheckErrors::TraitReferenceUnknown(trait_id.name.to_string()))?; + .ok_or_else(|| CheckErrorKind::TraitReferenceUnknown(trait_id.name.to_string()))?; Ok(TypeSignature::PrincipalType) } @@ -653,12 +665,12 @@ fn check_principal_of( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_33)?; Ok( TypeSignature::new_response(TypeSignature::PrincipalType, TypeSignature::UIntType) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, ) } @@ -672,7 +684,7 @@ fn check_principal_construct( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; check_arguments_at_most(3, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_1)?; @@ -690,13 +702,13 @@ fn check_principal_construct( ("error_code".into(), TypeSignature::UIntType), ( "value".into(), - TypeSignature::new_option(TypeSignature::PrincipalType).map_err(|_| CheckErrors::Expects("FATAL: failed to create (optional principal) type signature".into()))?, + TypeSignature::new_option(TypeSignature::PrincipalType).map_err(|_| CheckErrorKind::Expects("FATAL: failed to create (optional principal) type signature".into()))?, ), ]) - .map_err(|_| CheckErrors::Expects("FAIL: PrincipalConstruct failed to initialize type signature".into()))? + .map_err(|_| CheckErrorKind::Expects("FAIL: PrincipalConstruct failed to initialize type signature".into()))? .into() ) - .map_err(|_| CheckErrors::Expects("FATAL: failed to create `(response principal { error_code: uint, principal: (optional principal) })` type signature".into()))? + .map_err(|_| CheckErrorKind::Expects("FATAL: failed to create `(response principal { error_code: uint, principal: (optional principal) })` type signature".into()))? ) } @@ -704,13 +716,13 @@ fn check_secp256k1_recover( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_32)?; checker.type_check_expects(&args[1], context, &TypeSignature::BUFFER_65)?; Ok( TypeSignature::new_response(TypeSignature::BUFFER_33, TypeSignature::UIntType) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, ) } @@ -718,7 +730,7 @@ fn check_secp256k1_verify( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_32)?; checker.type_check_expects(&args[1], context, &TypeSignature::BUFFER_65)?; @@ -730,7 +742,7 @@ fn check_secp256r1_verify( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BUFFER_32)?; checker.type_check_expects(&args[1], context, &TypeSignature::BUFFER_64)?; @@ -742,18 +754,18 @@ fn check_get_block_info( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; - let block_info_prop_str = args[0] - .match_atom() - .ok_or(CheckError::new(CheckErrors::GetBlockInfoExpectPropertyName))?; + let block_info_prop_str = args[0].match_atom().ok_or(StaticCheckError::new( + CheckErrorKind::GetBlockInfoExpectPropertyName, + ))?; let block_info_prop = BlockInfoProperty::lookup_by_name_at_version(block_info_prop_str, &checker.clarity_version) - .ok_or(CheckError::new(CheckErrors::NoSuchBlockInfoProperty( - block_info_prop_str.to_string(), - )))?; + .ok_or(StaticCheckError::new( + CheckErrorKind::NoSuchBlockInfoProperty(block_info_prop_str.to_string()), + ))?; checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; @@ -761,30 +773,30 @@ fn check_get_block_info( } // # Errors -// - `CheckErrors::GetBurnBlockInfoExpectPropertyName` when `args[0]` is not a valid `ClarityName`. -// - `CheckErrors::NoSuchBlockInfoProperty` when `args[0]` does not name a `BurnBlockInfoProperty`. +// - `CheckErrorKind::GetBurnBlockInfoExpectPropertyName` when `args[0]` is not a valid `ClarityName`. +// - `CheckErrorKind::NoSuchBlockInfoProperty` when `args[0]` does not name a `BurnBlockInfoProperty`. fn check_get_burn_block_info( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let block_info_prop_str = args[0].match_atom().ok_or(CheckError::new( - CheckErrors::GetBurnBlockInfoExpectPropertyName, + let block_info_prop_str = args[0].match_atom().ok_or(StaticCheckError::new( + CheckErrorKind::GetBurnBlockInfoExpectPropertyName, ))?; let block_info_prop = - BurnBlockInfoProperty::lookup_by_name(block_info_prop_str).ok_or(CheckError::new( - CheckErrors::NoSuchBlockInfoProperty(block_info_prop_str.to_string()), + BurnBlockInfoProperty::lookup_by_name(block_info_prop_str).ok_or(StaticCheckError::new( + CheckErrorKind::NoSuchBlockInfoProperty(block_info_prop_str.to_string()), ))?; checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; Ok(TypeSignature::new_option( - block_info_prop - .type_result() - .map_err(|_| CheckErrors::Expects("FAILED to type valid burn info property".into()))?, + block_info_prop.type_result().map_err(|_| { + CheckErrorKind::Expects("FAILED to type valid burn info property".into()) + })?, )?) } @@ -792,17 +804,18 @@ fn check_get_stacks_block_info( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let block_info_prop_str = args[0].match_atom().ok_or(CheckError::new( - CheckErrors::GetStacksBlockInfoExpectPropertyName, + let block_info_prop_str = args[0].match_atom().ok_or(StaticCheckError::new( + CheckErrorKind::GetStacksBlockInfoExpectPropertyName, ))?; - let block_info_prop = - StacksBlockInfoProperty::lookup_by_name(block_info_prop_str).ok_or(CheckError::new( - CheckErrors::NoSuchStacksBlockInfoProperty(block_info_prop_str.to_string()), - ))?; + let block_info_prop = StacksBlockInfoProperty::lookup_by_name(block_info_prop_str).ok_or( + StaticCheckError::new(CheckErrorKind::NoSuchStacksBlockInfoProperty( + block_info_prop_str.to_string(), + )), + )?; checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; @@ -813,16 +826,16 @@ fn check_get_tenure_info( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let block_info_prop_str = args[0].match_atom().ok_or(CheckError::new( - CheckErrors::GetTenureInfoExpectPropertyName, + let block_info_prop_str = args[0].match_atom().ok_or(StaticCheckError::new( + CheckErrorKind::GetTenureInfoExpectPropertyName, ))?; let block_info_prop = - TenureInfoProperty::lookup_by_name(block_info_prop_str).ok_or(CheckError::new( - CheckErrors::NoSuchTenureInfoProperty(block_info_prop_str.to_string()), + TenureInfoProperty::lookup_by_name(block_info_prop_str).ok_or(StaticCheckError::new( + CheckErrorKind::NoSuchTenureInfoProperty(block_info_prop_str.to_string()), ))?; checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; @@ -836,7 +849,7 @@ impl TypedNativeFunction { checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, - ) -> Result { + ) -> Result { use self::TypedNativeFunction::{Simple, Special}; match self { Special(SpecialNativeFunction(check)) => check(checker, args, context), @@ -852,7 +865,7 @@ impl TypedNativeFunction { pub fn type_native_function( function: &NativeFunctions, - ) -> Result { + ) -> Result { use self::TypedNativeFunction::{Simple, Special}; use crate::vm::functions::NativeFunctions::*; let out = match function { @@ -881,7 +894,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::IntType, ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -892,7 +905,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::UIntType, ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -903,7 +916,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -915,10 +928,10 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::SequenceType(SequenceSubtype::BufferType( BufferLength::try_from(16_u32) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, )), ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -931,10 +944,10 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::SequenceType(SequenceSubtype::BufferType( BufferLength::try_from(16_u32) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, )), ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -970,7 +983,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::BoolType, ClarityName::try_from("value".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -1023,7 +1036,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("owner".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -1035,7 +1048,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("principal".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -1043,7 +1056,7 @@ impl TypedNativeFunction { returns: { /// The return type of `principal-destruct` is a Response, in which the success /// and error types are the same. - fn parse_principal_basic_type() -> Result { + fn parse_principal_basic_type() -> Result { TupleTypeSignature::try_from(vec![ ("version".into(), TypeSignature::BUFFER_1), ("hash-bytes".into(), TypeSignature::BUFFER_20), @@ -1052,11 +1065,11 @@ impl TypedNativeFunction { TypeSignature::new_option( TypeSignature::CONTRACT_NAME_STRING_ASCII_MAX, ) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, ), ]) .map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: PrincipalDestruct failed to initialize type signature" .into(), ) @@ -1072,7 +1085,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("owner".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -1083,7 +1096,7 @@ impl TypedNativeFunction { ("unlock-height".into(), TypeSignature::UIntType), ]) .map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: StxGetAccount failed to initialize type signature".into(), ) })? @@ -1094,7 +1107,7 @@ impl TypedNativeFunction { FunctionArg::new( TypeSignature::UIntType, ClarityName::try_from("amount".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -1102,7 +1115,7 @@ impl TypedNativeFunction { FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("sender".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -1112,7 +1125,7 @@ impl TypedNativeFunction { TypeSignature::BoolType, TypeSignature::UIntType, ) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, }))), StxTransfer => Special(SpecialNativeFunction(&assets::check_special_stx_transfer)), StxTransferMemo => Special(SpecialNativeFunction( @@ -1195,7 +1208,7 @@ impl TypedNativeFunction { args: vec![FunctionArg::new( TypeSignature::PrincipalType, ClarityName::try_from("contract".to_owned()).map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FAIL: ClarityName failed to accept default arg name".into(), ) })?, @@ -1204,7 +1217,7 @@ impl TypedNativeFunction { TypeSignature::BUFFER_32, TypeSignature::UIntType, ) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, }))), ToAscii => Special(SpecialNativeFunction(&conversions::check_special_to_ascii)), RestrictAssets => Special(SpecialNativeFunction( diff --git a/clarity/src/vm/analysis/type_checker/v2_1/natives/options.rs b/clarity/src/vm/analysis/type_checker/v2_1/natives/options.rs index 56d145298a6..b4f01b196c7 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/natives/options.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/natives/options.rs @@ -19,7 +19,8 @@ use clarity_types::types::TypeSignature; use stacks_common::types::StacksEpochId; use super::{ - check_argument_count, check_arguments_at_least, no_type, CheckError, CheckErrors, TypeChecker, + check_argument_count, check_arguments_at_least, no_type, CheckErrorKind, StaticCheckError, + TypeChecker, }; use crate::vm::analysis::type_checker::contexts::TypingContext; use crate::vm::costs::cost_functions::ClarityCostFunction; @@ -30,7 +31,7 @@ pub fn check_special_okay( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::AnalysisOptionCons, checker, 0)?; @@ -44,7 +45,7 @@ pub fn check_special_some( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::AnalysisOptionCons, checker, 0)?; @@ -58,7 +59,7 @@ pub fn check_special_error( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::AnalysisOptionCons, checker, 0)?; @@ -72,7 +73,7 @@ pub fn check_special_is_response( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -82,7 +83,7 @@ pub fn check_special_is_response( if let TypeSignature::ResponseType(_types) = input { Ok(TypeSignature::BoolType) } else { - Err(CheckErrors::ExpectedResponseType(Box::new(input.clone())).into()) + Err(CheckErrorKind::ExpectedResponseType(Box::new(input.clone())).into()) } } @@ -90,7 +91,7 @@ pub fn check_special_is_optional( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -100,7 +101,7 @@ pub fn check_special_is_optional( if let TypeSignature::OptionalType(_type) = input { Ok(TypeSignature::BoolType) } else { - Err(CheckErrors::ExpectedOptionalType(Box::new(input.clone())).into()) + Err(CheckErrorKind::ExpectedOptionalType(Box::new(input.clone())).into()) } } @@ -108,7 +109,7 @@ pub fn check_special_default_to( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let default = checker.type_check(&args[0], context)?; @@ -120,12 +121,12 @@ pub fn check_special_default_to( let contained_type = *input_type; TypeSignature::least_supertype(&StacksEpochId::Epoch21, &default, &contained_type).map_err( |_| { - CheckErrors::DefaultTypesMustMatch(Box::new(default), Box::new(contained_type)) + CheckErrorKind::DefaultTypesMustMatch(Box::new(default), Box::new(contained_type)) .into() }, ) } else { - Err(CheckErrors::ExpectedOptionalType(Box::new(input)).into()) + Err(CheckErrorKind::ExpectedOptionalType(Box::new(input)).into()) } } @@ -133,7 +134,7 @@ pub fn check_special_asserts( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; checker.type_check_expects(&args[0], context, &TypeSignature::BoolType)?; @@ -147,13 +148,13 @@ pub fn check_special_asserts( fn inner_unwrap( input: TypeSignature, checker: &mut TypeChecker, -) -> Result { +) -> Result { runtime_cost(ClarityCostFunction::AnalysisOptionCheck, checker, 0)?; match input { TypeSignature::OptionalType(input_type) => { if input_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseOkType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseOkType.into()) } else { Ok(*input_type) } @@ -161,30 +162,30 @@ fn inner_unwrap( TypeSignature::ResponseType(response_type) => { let ok_type = response_type.0; if ok_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseOkType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseOkType.into()) } else { Ok(ok_type) } } - _ => Err(CheckErrors::ExpectedOptionalOrResponseType(Box::new(input)).into()), + _ => Err(CheckErrorKind::ExpectedOptionalOrResponseType(Box::new(input)).into()), } } fn inner_unwrap_err( input: TypeSignature, checker: &mut TypeChecker, -) -> Result { +) -> Result { runtime_cost(ClarityCostFunction::AnalysisOptionCheck, checker, 0)?; if let TypeSignature::ResponseType(response_type) = input { let err_type = response_type.1; if err_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseErrType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseErrType.into()) } else { Ok(err_type) } } else { - Err(CheckErrors::ExpectedResponseType(Box::new(input)).into()) + Err(CheckErrorKind::ExpectedResponseType(Box::new(input)).into()) } } @@ -192,7 +193,7 @@ pub fn check_special_unwrap_or_ret( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let input = checker.type_check(&args[0], context)?; @@ -207,7 +208,7 @@ pub fn check_special_unwrap_err_or_ret( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let input = checker.type_check(&args[0], context)?; @@ -222,7 +223,7 @@ pub fn check_special_try_ret( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -232,7 +233,7 @@ pub fn check_special_try_ret( match input { TypeSignature::OptionalType(input_type) => { if input_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseOkType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseOkType.into()) } else { checker.track_return_type(TypeSignature::new_option(TypeSignature::NoType)?)?; Ok(*input_type) @@ -241,9 +242,9 @@ pub fn check_special_try_ret( TypeSignature::ResponseType(response_type) => { let (ok_type, err_type) = *response_type; if ok_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseOkType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseOkType.into()) } else if err_type.is_no_type() { - Err(CheckErrors::CouldNotDetermineResponseErrType.into()) + Err(CheckErrorKind::CouldNotDetermineResponseErrType.into()) } else { checker.track_return_type(TypeSignature::new_response( TypeSignature::NoType, @@ -252,7 +253,7 @@ pub fn check_special_try_ret( Ok(ok_type) } } - _ => Err(CheckErrors::ExpectedOptionalOrResponseType(Box::new(input)).into()), + _ => Err(CheckErrorKind::ExpectedOptionalOrResponseType(Box::new(input)).into()), } } @@ -260,7 +261,7 @@ pub fn check_special_unwrap( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -272,7 +273,7 @@ pub fn check_special_unwrap_err( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -287,7 +288,7 @@ fn eval_with_new_binding( bind_type: TypeSignature, checker: &mut TypeChecker, context: &TypingContext, -) -> Result { +) -> Result { let mut inner_context = context.extend()?; runtime_cost( @@ -305,7 +306,7 @@ fn eval_with_new_binding( checker.contract_context.check_name_used(&bind_name)?; if inner_context.lookup_variable_type(&bind_name).is_some() { - return Err(CheckErrors::NameAlreadyUsed(bind_name.into()).into()); + return Err(CheckErrorKind::NameAlreadyUsed(bind_name.into()).into()); } inner_context.add_variable_type(bind_name, bind_type, checker.clarity_version); @@ -322,22 +323,24 @@ fn check_special_match_opt( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { if args.len() != 3 { - Err(CheckErrors::BadMatchOptionSyntax(Box::new( - CheckErrors::IncorrectArgumentCount(4, args.len() + 1), + Err(CheckErrorKind::BadMatchOptionSyntax(Box::new( + CheckErrorKind::IncorrectArgumentCount(4, args.len() + 1), )))?; } let bind_name = args[0] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchOptionSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchOptionSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let some_branch = &args[1]; let none_branch = &args[2]; if option_type.is_no_type() { - return Err(CheckErrors::CouldNotDetermineMatchTypes.into()); + return Err(CheckErrorKind::CouldNotDetermineMatchTypes.into()); } let some_branch_type = @@ -352,7 +355,7 @@ fn check_special_match_opt( &none_branch_type, ) .map_err(|_| { - CheckErrors::MatchArmsMustMatch(Box::new(some_branch_type), Box::new(none_branch_type)) + CheckErrorKind::MatchArmsMustMatch(Box::new(some_branch_type), Box::new(none_branch_type)) .into() }) } @@ -362,28 +365,32 @@ fn check_special_match_resp( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { if args.len() != 4 { - Err(CheckErrors::BadMatchResponseSyntax(Box::new( - CheckErrors::IncorrectArgumentCount(5, args.len() + 1), + Err(CheckErrorKind::BadMatchResponseSyntax(Box::new( + CheckErrorKind::IncorrectArgumentCount(5, args.len() + 1), )))?; } let ok_bind_name = args[0] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let ok_branch = &args[1]; let err_bind_name = args[2] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let err_branch = &args[3]; let (ok_type, err_type) = resp_type; if ok_type.is_no_type() || err_type.is_no_type() { - return Err(CheckErrors::CouldNotDetermineMatchTypes.into()); + return Err(CheckErrorKind::CouldNotDetermineMatchTypes.into()); } let ok_branch_type = eval_with_new_binding(ok_branch, ok_bind_name, ok_type, checker, context)?; @@ -394,7 +401,7 @@ fn check_special_match_resp( TypeSignature::least_supertype(&StacksEpochId::Epoch21, &ok_branch_type, &err_branch_type) .map_err(|_| { - CheckErrors::MatchArmsMustMatch(Box::new(ok_branch_type), Box::new(err_branch_type)) + CheckErrorKind::MatchArmsMustMatch(Box::new(ok_branch_type), Box::new(err_branch_type)) .into() }) } @@ -403,7 +410,7 @@ pub fn check_special_match( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; let input = checker.type_check(&args[0], context)?; @@ -415,6 +422,6 @@ pub fn check_special_match( TypeSignature::ResponseType(resp_type) => { check_special_match_resp(*resp_type, checker, &args[1..], context) } - _ => Err(CheckErrors::BadMatchInput(Box::new(input)).into()), + _ => Err(CheckErrorKind::BadMatchInput(Box::new(input)).into()), } } diff --git a/clarity/src/vm/analysis/type_checker/v2_1/natives/post_conditions.rs b/clarity/src/vm/analysis/type_checker/v2_1/natives/post_conditions.rs index 6ac1104ef61..dc862545adb 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/natives/post_conditions.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/natives/post_conditions.rs @@ -14,7 +14,7 @@ // along with this program. If not, see . use clarity_types::errors::analysis::{check_argument_count, check_arguments_at_least}; -use clarity_types::errors::{CheckError, CheckErrors}; +use clarity_types::errors::{CheckErrorKind, StaticCheckError}; use clarity_types::representations::SymbolicExpression; use clarity_types::types::{SequenceSubtype, TypeSignature}; @@ -35,26 +35,26 @@ pub fn check_restrict_assets( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(3, args)?; let asset_owner = args .first() - .ok_or(CheckErrors::CheckerImplementationFailure)?; + .ok_or(CheckErrorKind::CheckerImplementationFailure)?; let allowance_list = args .get(1) - .ok_or(CheckErrors::CheckerImplementationFailure)? + .ok_or(CheckErrorKind::CheckerImplementationFailure)? .match_list() - .ok_or(CheckErrors::ExpectedListOfAllowances( + .ok_or(CheckErrorKind::ExpectedListOfAllowances( "restrict-assets?".into(), 2, ))?; let body_exprs = args .get(2..) - .ok_or(CheckErrors::CheckerImplementationFailure)?; + .ok_or(CheckErrorKind::CheckerImplementationFailure)?; if allowance_list.len() > MAX_ALLOWANCES { - return Err(CheckErrors::TooManyAllowances(MAX_ALLOWANCES, allowance_list.len()).into()); + return Err(CheckErrorKind::TooManyAllowances(MAX_ALLOWANCES, allowance_list.len()).into()); } runtime_cost( @@ -67,7 +67,7 @@ pub fn check_restrict_assets( for allowance in allowance_list { if check_allowance(checker, allowance, context)? { - return Err(CheckErrors::WithAllAllowanceNotAllowed.into()); + return Err(CheckErrorKind::WithAllAllowanceNotAllowed.into()); } } @@ -76,12 +76,12 @@ pub fn check_restrict_assets( for expr in body_exprs { let type_return = checker.type_check(expr, context)?; if type_return.is_response_type() { - return Err(CheckErrors::UncheckedIntermediaryResponses.into()); + return Err(CheckErrorKind::UncheckedIntermediaryResponses.into()); } last_return = Some(type_return); } - let ok_type = last_return.ok_or_else(|| CheckErrors::CheckerImplementationFailure)?; + let ok_type = last_return.ok_or_else(|| CheckErrorKind::CheckerImplementationFailure)?; Ok(TypeSignature::new_response( ok_type, TypeSignature::UIntType, @@ -92,23 +92,23 @@ pub fn check_as_contract( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; let allowance_list = args .first() - .ok_or(CheckErrors::CheckerImplementationFailure)? + .ok_or(CheckErrorKind::CheckerImplementationFailure)? .match_list() - .ok_or(CheckErrors::ExpectedListOfAllowances( + .ok_or(CheckErrorKind::ExpectedListOfAllowances( "as-contract?".into(), 1, ))?; let body_exprs = args .get(1..) - .ok_or(CheckErrors::CheckerImplementationFailure)?; + .ok_or(CheckErrorKind::CheckerImplementationFailure)?; if allowance_list.len() > MAX_ALLOWANCES { - return Err(CheckErrors::TooManyAllowances(MAX_ALLOWANCES, allowance_list.len()).into()); + return Err(CheckErrorKind::TooManyAllowances(MAX_ALLOWANCES, allowance_list.len()).into()); } runtime_cost( @@ -119,7 +119,7 @@ pub fn check_as_contract( for allowance in allowance_list { if check_allowance(checker, allowance, context)? && allowance_list.len() > 1 { - return Err(CheckErrors::WithAllAllowanceNotAlone.into()); + return Err(CheckErrorKind::WithAllAllowanceNotAlone.into()); } } @@ -128,12 +128,12 @@ pub fn check_as_contract( for expr in body_exprs { let type_return = checker.type_check(expr, context)?; if type_return.is_response_type() { - return Err(CheckErrors::UncheckedIntermediaryResponses.into()); + return Err(CheckErrorKind::UncheckedIntermediaryResponses.into()); } last_return = Some(type_return); } - let ok_type = last_return.ok_or_else(|| CheckErrors::CheckerImplementationFailure)?; + let ok_type = last_return.ok_or_else(|| CheckErrorKind::CheckerImplementationFailure)?; Ok(TypeSignature::new_response( ok_type, TypeSignature::UIntType, @@ -147,8 +147,8 @@ pub fn check_allowance_err( _checker: &mut TypeChecker, _args: &[SymbolicExpression], _context: &TypingContext, -) -> Result { - Err(CheckErrors::AllowanceExprNotAllowed.into()) +) -> Result { + Err(CheckErrorKind::AllowanceExprNotAllowed.into()) } /// Type check an allowance expression, returning whether it is a @@ -157,20 +157,20 @@ pub fn check_allowance( checker: &mut TypeChecker, allowance: &SymbolicExpression, context: &TypingContext, -) -> Result { +) -> Result { let list = allowance .match_list() - .ok_or(CheckErrors::ExpectedListApplication)?; + .ok_or(CheckErrorKind::ExpectedListApplication)?; let (allowance_fn, args) = list .split_first() - .ok_or(CheckErrors::ExpectedListApplication)?; + .ok_or(CheckErrorKind::ExpectedListApplication)?; let function_name = allowance_fn .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; let Some(ref native_function) = NativeFunctions::lookup_by_name_at_version(function_name, &checker.clarity_version) else { - return Err(CheckErrors::ExpectedAllowanceExpr(function_name.to_string()).into()); + return Err(CheckErrorKind::ExpectedAllowanceExpr(function_name.to_string()).into()); }; match native_function { @@ -181,7 +181,7 @@ pub fn check_allowance( check_allowance_with_stacking(checker, args, context) } NativeFunctions::AllowanceAll => check_allowance_all(checker, args, context), - _ => Err(CheckErrors::ExpectedAllowanceExpr(function_name.to_string()).into()), + _ => Err(CheckErrorKind::ExpectedAllowanceExpr(function_name.to_string()).into()), } } @@ -191,12 +191,12 @@ fn check_allowance_with_stx( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; checker.type_check_expects( args.first() - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, &TypeSignature::UIntType, )?; @@ -210,24 +210,24 @@ fn check_allowance_with_ft( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; checker.type_check_expects( args.first() - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, &TypeSignature::PrincipalType, )?; checker.type_check_expects( args.get(1) - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, &TypeSignature::STRING_ASCII_128, )?; checker.type_check_expects( args.get(2) - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, &TypeSignature::UIntType, )?; @@ -241,18 +241,18 @@ fn check_allowance_with_nft( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; checker.type_check_expects( args.first() - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, &TypeSignature::PrincipalType, )?; checker.type_check_expects( args.get(1) - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, &TypeSignature::STRING_ASCII_128, )?; @@ -260,14 +260,14 @@ fn check_allowance_with_nft( // Asset identifiers must be a Clarity list with any type of elements let id_list_ty = checker.type_check( args.get(2) - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, )?; let TypeSignature::SequenceType(SequenceSubtype::ListType(list_data)) = id_list_ty else { - return Err(CheckErrors::WithNftExpectedListOfIdentifiers.into()); + return Err(CheckErrorKind::WithNftExpectedListOfIdentifiers.into()); }; if list_data.get_max_len() > MAX_NFT_IDENTIFIERS { - return Err(CheckErrors::MaxIdentifierLengthExceeded( + return Err(CheckErrorKind::MaxIdentifierLengthExceeded( MAX_NFT_IDENTIFIERS, list_data.get_max_len(), ) @@ -283,12 +283,12 @@ fn check_allowance_with_stacking( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; checker.type_check_expects( args.first() - .ok_or(CheckErrors::CheckerImplementationFailure)?, + .ok_or(CheckErrorKind::CheckerImplementationFailure)?, context, &TypeSignature::UIntType, )?; @@ -302,7 +302,7 @@ fn check_allowance_all( _checker: &mut TypeChecker, args: &[SymbolicExpression], _context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(0, args)?; Ok(true) diff --git a/clarity/src/vm/analysis/type_checker/v2_1/natives/sequences.rs b/clarity/src/vm/analysis/type_checker/v2_1/natives/sequences.rs index c55656b9bf8..c2e162dae25 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/natives/sequences.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/natives/sequences.rs @@ -18,7 +18,7 @@ use stacks_common::types::StacksEpochId; use super::{SimpleNativeFunction, TypedNativeFunction}; use crate::vm::analysis::type_checker::v2_1::{ - check_argument_count, check_arguments_at_least, CheckError, CheckErrors, TypeChecker, + check_argument_count, check_arguments_at_least, CheckErrorKind, StaticCheckError, TypeChecker, TypingContext, }; use crate::vm::costs::cost_functions::ClarityCostFunction; @@ -34,7 +34,7 @@ use crate::vm::types::{FunctionType, TypeSignature, Value}; fn get_simple_native_or_user_define( function_name: &str, checker: &mut TypeChecker, -) -> Result { +) -> Result { runtime_cost(ClarityCostFunction::AnalysisLookupFunction, checker, 0)?; if let Some(ref native_function) = NativeFunctions::lookup_by_name_at_version(function_name, &checker.clarity_version) @@ -44,11 +44,14 @@ fn get_simple_native_or_user_define( { Ok(function_type) } else { - Err(CheckErrors::IllegalOrUnknownFunctionApplication(function_name.to_string()).into()) + Err( + CheckErrorKind::IllegalOrUnknownFunctionApplication(function_name.to_string()) + .into(), + ) } } else { checker.get_function_type(function_name).ok_or( - CheckErrors::IllegalOrUnknownFunctionApplication(function_name.to_string()).into(), + CheckErrorKind::IllegalOrUnknownFunctionApplication(function_name.to_string()).into(), ) } } @@ -57,12 +60,12 @@ pub fn check_special_map( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; let function_name = args[0] .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; // we will only lookup native or defined functions here. // you _cannot_ map a special function. let function_type = get_simple_native_or_user_define(function_name, checker)?; @@ -104,7 +107,7 @@ pub fn check_special_map( // However that could lead to confusions when combining certain types: // ex: (map concat (list "hello " "hi ") "world") would fail, because // strings are handled as sequences. - return Err(CheckErrors::ExpectedSequence(Box::new(argument_type)).into()); + return Err(CheckErrorKind::ExpectedSequence(Box::new(argument_type)).into()); } }; @@ -134,8 +137,8 @@ pub fn check_special_map( } if let Err(mut check_error) = check_result { - if let CheckErrors::IncorrectArgumentCount(expected, _actual) = *check_error.err { - check_error.err = Box::new(CheckErrors::IncorrectArgumentCount( + if let CheckErrorKind::IncorrectArgumentCount(expected, _actual) = *check_error.err { + check_error.err = Box::new(CheckErrorKind::IncorrectArgumentCount( expected, args.len().saturating_sub(1), )); @@ -156,19 +159,19 @@ pub fn check_special_map( context.clarity_version, )?; TypeSignature::list_of(mapped_type, min_args) - .map_err(|_| CheckErrors::ConstructedListTooLarge.into()) + .map_err(|_| CheckErrorKind::ConstructedListTooLarge.into()) } pub fn check_special_filter( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let function_name = args[0] .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; // we will only lookup native or defined functions here. // you _cannot_ map a special function. let function_type = get_simple_native_or_user_define(function_name, checker)?; @@ -179,7 +182,7 @@ pub fn check_special_filter( { let input_type = match argument_type { TypeSignature::SequenceType(ref sequence_type) => Ok(sequence_type.unit_type()), - _ => Err(CheckErrors::ExpectedSequence(Box::new( + _ => Err(CheckErrorKind::ExpectedSequence(Box::new( argument_type.clone(), ))), }?; @@ -192,7 +195,7 @@ pub fn check_special_filter( )?; if TypeSignature::BoolType != filter_type { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(TypeSignature::BoolType), Box::new(filter_type), ) @@ -207,12 +210,12 @@ pub fn check_special_fold( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; let function_name = args[0] .match_atom() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; // we will only lookup native or defined functions here. // you _cannot_ fold a special function. let function_type = get_simple_native_or_user_define(function_name, checker)?; @@ -222,7 +225,7 @@ pub fn check_special_fold( let input_type = match argument_type { TypeSignature::SequenceType(sequence_type) => Ok(sequence_type.unit_type()), - _ => Err(CheckErrors::ExpectedSequence(Box::new(argument_type))), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(argument_type))), }?; let initial_value_type = checker.type_check(&args[2], context)?; @@ -254,7 +257,7 @@ pub fn check_special_concat( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let lhs_type = checker.type_check(&args[0], context)?; @@ -280,29 +283,29 @@ pub fn check_special_concat( )?; let new_len = lhs_max_len .checked_add(rhs_max_len) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; TypeSignature::list_of(list_entry_type, new_len)? } (BufferType(lhs_len), BufferType(rhs_len)) => { let size: u32 = u32::from(lhs_len) .checked_add(u32::from(rhs_len)) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; TypeSignature::SequenceType(BufferType(size.try_into()?)) } (StringType(ASCII(lhs_len)), StringType(ASCII(rhs_len))) => { let size: u32 = u32::from(lhs_len) .checked_add(u32::from(rhs_len)) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; TypeSignature::SequenceType(StringType(ASCII(size.try_into()?))) } (StringType(UTF8(lhs_len)), StringType(UTF8(rhs_len))) => { let size: u32 = u32::from(lhs_len) .checked_add(u32::from(rhs_len)) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; TypeSignature::SequenceType(StringType(UTF8(size.try_into()?))) } (_, _) => { - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(lhs_type.clone()), Box::new(rhs_type.clone()), ) @@ -310,7 +313,7 @@ pub fn check_special_concat( } } } - _ => return Err(CheckErrors::ExpectedSequence(Box::new(lhs_type.clone())).into()), + _ => return Err(CheckErrorKind::ExpectedSequence(Box::new(lhs_type.clone())).into()), }; Ok(res) } @@ -319,7 +322,7 @@ pub fn check_special_append( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; @@ -339,11 +342,11 @@ pub fn check_special_append( )?; let new_len = lhs_max_len .checked_add(1) - .ok_or(CheckErrors::MaxLengthOverflow)?; + .ok_or(CheckErrorKind::MaxLengthOverflow)?; let return_type = TypeSignature::list_of(list_entry_type, new_len)?; Ok(return_type) } - _ => Err(CheckErrors::ExpectedListApplication.into()), + _ => Err(CheckErrorKind::ExpectedListApplication.into()), } } @@ -351,14 +354,14 @@ pub fn check_special_as_max_len( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let expected_len = match args[1].expr { SymbolicExpressionType::LiteralValue(Value::UInt(expected_len)) => expected_len, _ => { let expected_len_type = checker.type_check(&args[1], context)?; - return Err(CheckErrors::TypeError( + return Err(CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(expected_len_type), ) @@ -374,7 +377,8 @@ pub fn check_special_as_max_len( .type_map .set_type(&args[1], TypeSignature::UIntType)?; - let expected_len = u32::try_from(expected_len).map_err(|_e| CheckErrors::MaxLengthOverflow)?; + let expected_len = + u32::try_from(expected_len).map_err(|_e| CheckErrorKind::MaxLengthOverflow)?; let sequence = checker.type_check(&args[0], context)?; runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; @@ -400,7 +404,7 @@ pub fn check_special_as_max_len( StringUTF8Length::try_from(expected_len)?, )))), )), - _ => Err(CheckErrors::ExpectedSequence(Box::new(sequence)).into()), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(sequence)).into()), } } @@ -408,7 +412,7 @@ pub fn check_special_len( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let collection_type = checker.type_check(&args[0], context)?; @@ -416,7 +420,7 @@ pub fn check_special_len( match collection_type { TypeSignature::SequenceType(_) => Ok(()), - _ => Err(CheckErrors::ExpectedSequence(Box::new(collection_type))), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(collection_type))), }?; Ok(TypeSignature::UIntType) @@ -426,7 +430,7 @@ pub fn check_special_element_at( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let _index_type = checker.type_check_expects(&args[1], context, &TypeSignature::UIntType)?; @@ -445,16 +449,16 @@ pub fn check_special_element_at( TypeSignature::SequenceType(StringType(ASCII(_))) => Ok(TypeSignature::OptionalType( Box::new(TypeSignature::SequenceType(StringType(ASCII( BufferLength::try_from(1u32) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, )))), )), TypeSignature::SequenceType(StringType(UTF8(_))) => Ok(TypeSignature::OptionalType( Box::new(TypeSignature::SequenceType(StringType(UTF8( StringUTF8Length::try_from(1u32) - .map_err(|_| CheckErrors::Expects("Bad constructor".into()))?, + .map_err(|_| CheckErrorKind::Expects("Bad constructor".into()))?, )))), )), - _ => Err(CheckErrors::ExpectedSequence(Box::new(collection_type)).into()), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(collection_type)).into()), } } @@ -462,7 +466,7 @@ pub fn check_special_index_of( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; @@ -470,7 +474,7 @@ pub fn check_special_index_of( let expected_input_type = match list_type { TypeSignature::SequenceType(ref sequence_type) => Ok(sequence_type.unit_type()), - _ => Err(CheckErrors::ExpectedSequence(Box::new(list_type))), + _ => Err(CheckErrorKind::ExpectedSequence(Box::new(list_type))), }?; checker.type_check_expects(&args[1], context, &expected_input_type)?; @@ -483,7 +487,7 @@ pub fn check_special_slice( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; @@ -493,7 +497,7 @@ pub fn check_special_slice( TypeSignature::SequenceType(seq) => { TypeSignature::new_option(TypeSignature::SequenceType(seq))? } - _ => return Err(CheckErrors::ExpectedSequence(Box::new(seq_type)).into()), + _ => return Err(CheckErrorKind::ExpectedSequence(Box::new(seq_type)).into()), }; // Check left position argument @@ -509,7 +513,7 @@ pub fn check_special_replace_at( checker: &mut TypeChecker, args: &[SymbolicExpression], context: &TypingContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::AnalysisIterableFunc, checker, 0)?; @@ -517,7 +521,7 @@ pub fn check_special_replace_at( let input_type = checker.type_check(&args[0], context)?; let seq_type = match &input_type { TypeSignature::SequenceType(seq) => seq, - _ => return Err(CheckErrors::ExpectedSequence(Box::new(input_type)).into()), + _ => return Err(CheckErrorKind::ExpectedSequence(Box::new(input_type)).into()), }; let unit_seq = seq_type.unit_type(); // Check index argument diff --git a/clarity/src/vm/analysis/type_checker/v2_1/tests/assets.rs b/clarity/src/vm/analysis/type_checker/v2_1/tests/assets.rs index a25a43a3cc5..cd2c5620c04 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/tests/assets.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/tests/assets.rs @@ -21,7 +21,7 @@ use rstest_reuse::{self, *}; use stacks_common::types::StacksEpochId; use super::contracts::type_check; -use crate::vm::analysis::errors::CheckErrors; +use crate::vm::analysis::errors::CheckErrorKind; use crate::vm::ast::parse; use crate::vm::database::MemoryBackingStore; use crate::vm::tests::test_clarity_versions; @@ -173,108 +173,108 @@ fn test_bad_asset_usage() { ]; let expected = [ - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::BadTokenName, - CheckErrors::BadTokenName, - CheckErrors::TypeError( + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::BadTokenName, + CheckErrorKind::BadTokenName, + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::IntType), ), - CheckErrors::BadTokenName, - CheckErrors::NoSuchNFT("stackoos".to_string()), - CheckErrors::TypeError( + CheckErrorKind::BadTokenName, + CheckErrorKind::NoSuchNFT("stackoos".to_string()), + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(string_ascii_type(15)), ), - CheckErrors::BadTokenName, - CheckErrors::NoSuchNFT("stackoos".to_string()), - CheckErrors::TypeError( + CheckErrorKind::BadTokenName, + CheckErrorKind::NoSuchNFT("stackoos".to_string()), + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(string_ascii_type(15)), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::BadTokenName, - CheckErrors::TypeError( + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::BadTokenName, + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::BoolType), ), - CheckErrors::BadTokenName, - CheckErrors::NoSuchNFT("stackoos".to_string()), - CheckErrors::TypeError( + CheckErrorKind::BadTokenName, + CheckErrorKind::NoSuchNFT("stackoos".to_string()), + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(TypeSignature::UIntType), ), - CheckErrors::BadTokenName, - CheckErrors::TypeError( + CheckErrorKind::BadTokenName, + CheckErrorKind::TypeError( Box::new(string_ascii_type(10)), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::BadTokenName, - CheckErrors::TypeError( + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::BadTokenName, + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::BoolType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::BoolType), ), - CheckErrors::DefineNFTBadSignature, - CheckErrors::TypeError( + CheckErrorKind::DefineNFTBadSignature, + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::NoSuchFT("stackoos".to_string()), - CheckErrors::TypeError( + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::NoSuchFT("stackoos".to_string()), + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::IntType), ), 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 f3c434f2787..2b09b450d3f 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 @@ -21,11 +21,11 @@ use serde_json; use stacks_common::types::StacksEpochId; use crate::vm::analysis::contract_interface_builder::build_contract_interface; -use crate::vm::analysis::errors::CheckErrors; +use crate::vm::analysis::errors::CheckErrorKind; use crate::vm::analysis::type_checker::v2_1::tests::mem_type_check; use crate::vm::analysis::{ - mem_type_check as mem_run_analysis, run_analysis, AnalysisDatabase, CheckError, - ContractAnalysis, + mem_type_check as mem_run_analysis, run_analysis, AnalysisDatabase, ContractAnalysis, + StaticCheckError, }; use crate::vm::ast::parse; use crate::vm::costs::LimitedCostTracker; @@ -40,7 +40,7 @@ use crate::vm::{ClarityName, ClarityVersion, SymbolicExpression}; fn mem_type_check_v1( snippet: &str, -) -> Result<(Option, ContractAnalysis), CheckError> { +) -> Result<(Option, ContractAnalysis), StaticCheckError> { mem_run_analysis(snippet, ClarityVersion::Clarity1, StacksEpochId::latest()) } @@ -56,7 +56,7 @@ pub fn type_check( expressions: &mut [SymbolicExpression], analysis_db: &mut AnalysisDatabase, save_contract: bool, -) -> Result { +) -> Result { type_check_version( contract_identifier, expressions, @@ -74,7 +74,7 @@ pub fn type_check_version( save_contract: bool, epoch: StacksEpochId, version: ClarityVersion, -) -> Result { +) -> Result { run_analysis( contract_identifier, expressions, @@ -494,7 +494,7 @@ fn test_names_tokens_contracts_bad(#[case] version: ClarityVersion, #[case] epoc let err = db .execute(|db| type_check(&names_contract_id, &mut names_contract, db, true)) .unwrap_err(); - assert!(matches!(*err.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*err.err, CheckErrorKind::TypeError(_, _))); } #[test] @@ -535,12 +535,12 @@ fn test_bad_map_usage() { for contract in tests.iter() { let err = mem_type_check(contract).unwrap_err(); - assert!(matches!(*err.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*err.err, CheckErrorKind::TypeError(_, _))); } assert!(matches!( *mem_type_check(unhandled_option).unwrap_err().err, - CheckErrors::UnionTypeError(_, _) + CheckErrorKind::UnionTypeError(_, _) )); } @@ -627,25 +627,31 @@ fn test_expects() { for unmatched_return_types in bad_return_types_tests.iter() { let err = mem_type_check(unmatched_return_types).unwrap_err(); eprintln!("unmatched_return_types returned check error: {err}"); - assert!(matches!(*err.err, CheckErrors::ReturnTypesMustMatch(_, _))); + assert!(matches!( + *err.err, + CheckErrorKind::ReturnTypesMustMatch(_, _) + )); } let err = mem_type_check(bad_default_type).unwrap_err(); eprintln!("bad_default_types returned check error: {err}"); - assert!(matches!(*err.err, CheckErrors::DefaultTypesMustMatch(_, _))); + assert!(matches!( + *err.err, + CheckErrorKind::DefaultTypesMustMatch(_, _) + )); let err = mem_type_check(notype_response_type).unwrap_err(); eprintln!("notype_response_type returned check error: {err}"); assert!(matches!( *err.err, - CheckErrors::CouldNotDetermineResponseErrType + CheckErrorKind::CouldNotDetermineResponseErrType )); let err = mem_type_check(notype_response_type_2).unwrap_err(); eprintln!("notype_response_type_2 returned check error: {err}"); assert!(matches!( *err.err, - CheckErrors::CouldNotDetermineResponseOkType + CheckErrorKind::CouldNotDetermineResponseOkType )); } @@ -681,7 +687,7 @@ fn test_trait_to_compatible_trait() { mem_type_check(trait_to_compatible_trait).unwrap(); let err = mem_type_check_v1(trait_to_compatible_trait).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -708,7 +714,7 @@ fn test_bad_principal_to_trait() { let err = mem_type_check(bad_principal_to_trait).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::PrincipalType, @@ -721,7 +727,7 @@ fn test_bad_principal_to_trait() { }; let err = mem_type_check_v1(bad_principal_to_trait).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::PrincipalType, @@ -750,7 +756,7 @@ fn test_bad_other_trait() { let err = mem_type_check(bad_other_trait).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, actual) => { + CheckErrorKind::IncompatibleTrait(expected, actual) => { assert_eq!(expected.name.as_str(), "trait-2"); assert_eq!(actual.name.as_str(), "trait-1"); } @@ -758,7 +764,7 @@ fn test_bad_other_trait() { }; let err = mem_type_check_v1(bad_other_trait).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, actual) => match (&*expected, &*actual) { + CheckErrorKind::TypeError(expected, actual) => match (&*expected, &*actual) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -791,7 +797,7 @@ fn test_embedded_trait() { mem_type_check(embedded_trait).unwrap(); let err = mem_type_check_v1(embedded_trait).unwrap_err(); match *err.err { - CheckErrors::TraitReferenceUnknown(name) => { + CheckErrorKind::TraitReferenceUnknown(name) => { assert_eq!(name.as_str(), "contract"); } _ => panic!("Unexpected error: {err:?}"), @@ -821,7 +827,7 @@ fn test_embedded_trait_compatible() { mem_type_check(embedded_trait_compatible).unwrap(); let err = mem_type_check_v1(embedded_trait_compatible).unwrap_err(); match *err.err { - CheckErrors::TraitReferenceUnknown(name) => { + CheckErrorKind::TraitReferenceUnknown(name) => { assert_eq!(name.as_str(), "contract"); } _ => panic!("Unexpected error: {err:?}"), @@ -854,7 +860,7 @@ fn test_bad_embedded_trait() { let err = mem_type_check(bad_embedded_trait).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, actual) => { + CheckErrorKind::IncompatibleTrait(expected, actual) => { assert_eq!(expected.name.as_str(), "trait-12"); assert_eq!(actual.name.as_str(), "trait-1"); } @@ -862,7 +868,7 @@ fn test_bad_embedded_trait() { }; let err = mem_type_check_v1(bad_embedded_trait).unwrap_err(); match *err.err { - CheckErrors::TraitReferenceUnknown(name) => { + CheckErrorKind::TraitReferenceUnknown(name) => { assert_eq!(name.as_str(), "contract"); } _ => panic!("Unexpected error: {err:?}"), @@ -884,7 +890,7 @@ fn test_let_trait() { mem_type_check(let_trait).unwrap(); let err = mem_type_check_v1(let_trait).unwrap_err(); match *err.err { - CheckErrors::TraitReferenceUnknown(name) => { + CheckErrorKind::TraitReferenceUnknown(name) => { assert_eq!(name.as_str(), "t1"); } _ => panic!("Unexpected error: {err:?}"), @@ -910,7 +916,7 @@ fn test_let3_trait() { mem_type_check(let3_trait).unwrap(); let err = mem_type_check_v1(let3_trait).unwrap_err(); match *err.err { - CheckErrors::TraitReferenceUnknown(name) => { + CheckErrorKind::TraitReferenceUnknown(name) => { assert_eq!(name.as_str(), "t3"); } _ => panic!("Unexpected error: {err:?}"), @@ -965,7 +971,7 @@ fn test_let3_compound_trait_call() { mem_type_check(let3_compound_trait_call).unwrap(); let err = mem_type_check_v1(let3_compound_trait_call).unwrap_err(); match *err.err { - CheckErrors::TraitReferenceUnknown(name) => { + CheckErrorKind::TraitReferenceUnknown(name) => { assert_eq!(name.as_str(), "t4"); } _ => panic!("Unexpected error: {err:?}"), @@ -989,7 +995,7 @@ fn test_trait_args_differ() { let err = mem_type_check(trait_args_differ).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, actual) => { + CheckErrorKind::IncompatibleTrait(expected, actual) => { assert_eq!(expected.name.as_str(), "trait-2"); assert_eq!(actual.name.as_str(), "trait-1"); } @@ -997,7 +1003,7 @@ fn test_trait_args_differ() { }; let err = mem_type_check_v1(trait_args_differ).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1027,7 +1033,7 @@ fn test_trait_arg_counts_differ1() { let err = mem_type_check(trait_to_compatible_trait).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, found) => { + CheckErrorKind::IncompatibleTrait(expected, found) => { assert_eq!(expected.name.as_str(), "trait-2"); assert_eq!(found.name.as_str(), "trait-1"); } @@ -1035,7 +1041,7 @@ fn test_trait_arg_counts_differ1() { }; let err = mem_type_check_v1(trait_to_compatible_trait).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1065,7 +1071,7 @@ fn test_trait_arg_counts_differ2() { let err = mem_type_check(trait_to_compatible_trait).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, found) => { + CheckErrorKind::IncompatibleTrait(expected, found) => { assert_eq!(expected.name.as_str(), "trait-2"); assert_eq!(found.name.as_str(), "trait-1"); } @@ -1073,7 +1079,7 @@ fn test_trait_arg_counts_differ2() { }; let err = mem_type_check_v1(trait_to_compatible_trait).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1103,7 +1109,7 @@ fn test_trait_ret_ty_differ() { let err = mem_type_check(trait_ret_ty_differ).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, actual) => { + CheckErrorKind::IncompatibleTrait(expected, actual) => { assert_eq!(expected.name.as_str(), "trait-2"); assert_eq!(actual.name.as_str(), "trait-1"); } @@ -1111,7 +1117,7 @@ fn test_trait_ret_ty_differ() { }; let err = mem_type_check_v1(trait_ret_ty_differ).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1149,7 +1155,7 @@ fn test_trait_with_compatible_trait_arg() { mem_type_check(trait_with_compatible_trait_arg).unwrap(); let err = mem_type_check_v1(trait_with_compatible_trait_arg).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1186,7 +1192,7 @@ fn test_trait_with_bad_trait_arg() { let err = mem_type_check(trait_with_bad_trait_arg).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, actual) => { + CheckErrorKind::IncompatibleTrait(expected, actual) => { assert_eq!(expected.name.as_str(), "trait-b"); assert_eq!(actual.name.as_str(), "trait-a"); } @@ -1194,7 +1200,7 @@ fn test_trait_with_bad_trait_arg() { }; let err = mem_type_check_v1(trait_with_bad_trait_arg).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1232,7 +1238,7 @@ fn test_trait_with_superset_trait_arg() { let err = mem_type_check(trait_with_superset_trait_arg).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, actual) => { + CheckErrorKind::IncompatibleTrait(expected, actual) => { assert_eq!(expected.name.as_str(), "trait-b"); assert_eq!(actual.name.as_str(), "trait-a"); } @@ -1242,7 +1248,7 @@ fn test_trait_with_superset_trait_arg() { let err = mem_type_check_v1(trait_with_superset_trait_arg).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1281,7 +1287,7 @@ fn test_trait_with_subset_trait_arg() { mem_type_check(trait_with_subset_trait_arg).unwrap(); let err = mem_type_check_v1(trait_with_subset_trait_arg).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1305,7 +1311,7 @@ fn test_trait_with_duplicate_method() { let err = mem_type_check(trait_with_duplicate_method).unwrap_err(); match *err.err { - CheckErrors::DefineTraitDuplicateMethod(method_name) => { + CheckErrorKind::DefineTraitDuplicateMethod(method_name) => { assert_eq!(method_name.as_str(), "foo"); } _ => panic!("Unexpected error: {err:?}"), @@ -1334,7 +1340,7 @@ fn test_trait_to_subtrait_and_back() { let err = mem_type_check(trait_to_subtrait_and_back).unwrap_err(); match *err.err { - CheckErrors::IncompatibleTrait(expected, actual) => { + CheckErrorKind::IncompatibleTrait(expected, actual) => { assert_eq!(expected.name.as_str(), "trait-2"); assert_eq!(actual.name.as_str(), "trait-1"); } @@ -1342,7 +1348,7 @@ fn test_trait_to_subtrait_and_back() { }; let err = mem_type_check_v1(trait_to_subtrait_and_back).unwrap_err(); match *err.err { - CheckErrors::TypeError(expected, found) => match (&*expected, &*found) { + CheckErrorKind::TypeError(expected, found) => match (&*expected, &*found) { ( TypeSignature::CallableType(CallableSubtype::Trait(expected_trait)), TypeSignature::CallableType(CallableSubtype::Trait(found_trait)), @@ -1389,7 +1395,7 @@ fn test_if_branches_with_incompatible_trait_types() { )"; let err = mem_type_check(if_branches_with_incompatible_trait_types).unwrap_err(); match *err.err { - CheckErrors::IfArmsMustMatch(type1, type2) => match (&*type1, &*type2) { + CheckErrorKind::IfArmsMustMatch(type1, type2) => match (&*type1, &*type2) { ( TypeSignature::CallableType(CallableSubtype::Trait(trait1)), TypeSignature::CallableType(CallableSubtype::Trait(trait2)), @@ -1403,7 +1409,7 @@ fn test_if_branches_with_incompatible_trait_types() { }; let err = mem_type_check_v1(if_branches_with_incompatible_trait_types).unwrap_err(); match *err.err { - CheckErrors::IfArmsMustMatch(type1, type2) => match (&*type1, &*type2) { + CheckErrorKind::IfArmsMustMatch(type1, type2) => match (&*type1, &*type2) { ( TypeSignature::CallableType(CallableSubtype::Trait(trait1)), TypeSignature::CallableType(CallableSubtype::Trait(trait2)), @@ -1435,7 +1441,7 @@ fn test_if_branches_with_compatible_trait_types() { let err = mem_type_check(if_branches_with_compatible_trait_types).unwrap_err(); match *err.err { - CheckErrors::IfArmsMustMatch(type1, type2) => match (&*type1, &*type2) { + CheckErrorKind::IfArmsMustMatch(type1, type2) => match (&*type1, &*type2) { ( TypeSignature::CallableType(CallableSubtype::Trait(trait1)), TypeSignature::CallableType(CallableSubtype::Trait(trait2)), @@ -1449,7 +1455,7 @@ fn test_if_branches_with_compatible_trait_types() { }; let err = mem_type_check_v1(if_branches_with_compatible_trait_types).unwrap_err(); match *err.err { - CheckErrors::IfArmsMustMatch(type1, type2) => match (&*type1, &*type2) { + CheckErrorKind::IfArmsMustMatch(type1, type2) => match (&*type1, &*type2) { ( TypeSignature::CallableType(CallableSubtype::Trait(trait1)), TypeSignature::CallableType(CallableSubtype::Trait(trait2)), @@ -1507,8 +1513,8 @@ fn test_traits_multi_contract(#[case] version: ClarityVersion) { }); match result { Ok(_) if version >= ClarityVersion::Clarity2 => (), - Err(CheckError { err, .. }) if version < ClarityVersion::Clarity2 => match *err { - CheckErrors::TraitMethodUnknown(trait_name, function) => { + Err(StaticCheckError { err, .. }) if version < ClarityVersion::Clarity2 => match *err { + CheckErrorKind::TraitMethodUnknown(trait_name, function) => { assert_eq!(trait_name.as_str(), "a"); assert_eq!(function.as_str(), "do-it"); } @@ -3393,7 +3399,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? 123)", "int type", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::IntType), )), @@ -3401,7 +3407,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? u123)", "uint type", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::UIntType), )), @@ -3409,7 +3415,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? true)", "bool type", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::BoolType), )), @@ -3417,7 +3423,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? 0x1234)", "buffer type", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::SequenceType(SequenceSubtype::BufferType( BufferLength::try_from(2u32).unwrap(), @@ -3427,7 +3433,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? \"60 percent of the time, it works every time\")", "ascii string", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::SequenceType(SequenceSubtype::StringType( StringSubtype::ASCII(BufferLength::try_from(43u32).unwrap()), @@ -3437,7 +3443,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? u\"I am serious, and don't call me Shirley.\")", "utf8 string", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::SequenceType(SequenceSubtype::StringType( StringSubtype::UTF8(StringUTF8Length::try_from(40u32).unwrap()), @@ -3447,7 +3453,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? (list 1 2 3))", "list type", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::SequenceType(SequenceSubtype::ListType( ListTypeData::new_list(TypeSignature::IntType, 3).unwrap(), @@ -3457,7 +3463,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? { a: 1, b: u2 })", "tuple type", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::TupleType( vec![ @@ -3472,7 +3478,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? (some u789))", "optional type", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::new_option(TypeSignature::UIntType).unwrap()), )), @@ -3480,7 +3486,7 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc ( "(contract-hash? (ok true))", "response type", - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new( TypeSignature::new_response(TypeSignature::BoolType, TypeSignature::NoType) @@ -3497,7 +3503,9 @@ fn test_contract_hash(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc let expected = if version >= ClarityVersion::Clarity4 { clarity4_expected } else { - &Err(CheckErrors::UnknownFunction("contract-hash?".to_string())) + &Err(CheckErrorKind::UnknownFunction( + "contract-hash?".to_string(), + )) }; assert_eq!(&actual, expected, "Failed for test case: {description}"); diff --git a/clarity/src/vm/analysis/type_checker/v2_1/tests/conversions.rs b/clarity/src/vm/analysis/type_checker/v2_1/tests/conversions.rs index b9a62e62255..b889bcc53ff 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/tests/conversions.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/tests/conversions.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use clarity_types::errors::CheckErrors; +use clarity_types::errors::CheckErrorKind; use clarity_types::types::{ BufferLength, ListTypeData, SequenceSubtype, StringSubtype, TypeSignature, MAX_TO_ASCII_BUFFER_LEN, @@ -99,7 +99,7 @@ fn test_to_ascii(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) ( &format!("(to-ascii? 0x{})", "ff".repeat(524285)), "oversized buffer type", - Err(CheckErrors::UnionTypeError( + Err(CheckErrorKind::UnionTypeError( to_ascii_expected_types.clone(), Box::new(TypeSignature::SequenceType(SequenceSubtype::BufferType( BufferLength::try_from(524285u32).unwrap(), @@ -125,7 +125,7 @@ fn test_to_ascii(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) ( "(to-ascii? \"60 percent of the time, it works every time\")", "ascii string", - Err(CheckErrors::UnionTypeError( + Err(CheckErrorKind::UnionTypeError( to_ascii_expected_types.clone(), Box::new(TypeSignature::SequenceType(SequenceSubtype::StringType( StringSubtype::ASCII(BufferLength::try_from(43u32).unwrap()), @@ -135,7 +135,7 @@ fn test_to_ascii(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) ( "(to-ascii? (list 1 2 3))", "list type", - Err(CheckErrors::UnionTypeError( + Err(CheckErrorKind::UnionTypeError( to_ascii_expected_types.clone(), Box::new(TypeSignature::SequenceType(SequenceSubtype::ListType( ListTypeData::new_list(TypeSignature::IntType, 3).unwrap(), @@ -145,7 +145,7 @@ fn test_to_ascii(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) ( "(to-ascii? { a: 1, b: u2 })", "tuple type", - Err(CheckErrors::UnionTypeError( + Err(CheckErrorKind::UnionTypeError( to_ascii_expected_types.clone(), Box::new(TypeSignature::TupleType( vec![ @@ -160,7 +160,7 @@ fn test_to_ascii(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) ( "(to-ascii? (some u789))", "optional type", - Err(CheckErrors::UnionTypeError( + Err(CheckErrorKind::UnionTypeError( to_ascii_expected_types.clone(), Box::new(TypeSignature::new_option(TypeSignature::UIntType).unwrap()), )), @@ -168,7 +168,7 @@ fn test_to_ascii(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) ( "(to-ascii? (ok true))", "response type", - Err(CheckErrors::UnionTypeError( + Err(CheckErrorKind::UnionTypeError( to_ascii_expected_types.clone(), Box::new( TypeSignature::new_response(TypeSignature::BoolType, TypeSignature::NoType) @@ -185,7 +185,7 @@ fn test_to_ascii(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) let expected = if version >= ClarityVersion::Clarity4 { clarity4_expected } else { - &Err(CheckErrors::UnknownFunction("to-ascii?".to_string())) + &Err(CheckErrorKind::UnknownFunction("to-ascii?".to_string())) }; assert_eq!(&actual, expected, "Failed for test case: {description}"); diff --git a/clarity/src/vm/analysis/type_checker/v2_1/tests/mod.rs b/clarity/src/vm/analysis/type_checker/v2_1/tests/mod.rs index db5a0ad0ea9..3dc3148ba01 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/tests/mod.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/tests/mod.rs @@ -22,12 +22,12 @@ use rstest::rstest; use rstest_reuse::{self, *}; use stacks_common::types::StacksEpochId; -use crate::vm::analysis::errors::{CheckError, CheckErrors, SyntaxBindingError}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError, SyntaxBindingError}; use crate::vm::analysis::mem_type_check as mem_run_analysis; use crate::vm::analysis::type_checker::v2_1::{MAX_FUNCTION_PARAMETERS, MAX_TRAIT_METHODS}; use crate::vm::analysis::types::ContractAnalysis; use crate::vm::ast::build_ast; -use crate::vm::ast::errors::ParseErrors; +use crate::vm::ast::errors::ParseErrorKind; use crate::vm::tests::test_clarity_versions; use crate::vm::types::signatures::TypeSignature::OptionalType; use crate::vm::types::signatures::{ListTypeData, StringUTF8Length}; @@ -57,7 +57,9 @@ const SECP256R1_SIGNATURE: &str = "0x000306090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366696c6f7275787b7e8184878a8d909396999c9fa2a5a8abaeb1b4b7babd"; /// Backwards-compatibility shim for type_checker tests. Runs at latest Clarity version. -pub fn mem_type_check(exp: &str) -> Result<(Option, ContractAnalysis), CheckError> { +pub fn mem_type_check( + exp: &str, +) -> Result<(Option, ContractAnalysis), StaticCheckError> { mem_run_analysis( exp, crate::vm::ClarityVersion::latest(), @@ -66,7 +68,7 @@ pub fn mem_type_check(exp: &str) -> Result<(Option, ContractAnaly } /// NOTE: runs at latest Clarity version -fn type_check_helper(exp: &str) -> Result { +fn type_check_helper(exp: &str) -> Result { mem_type_check(exp).map(|(type_sig_opt, _)| type_sig_opt.unwrap()) } @@ -74,11 +76,11 @@ fn type_check_helper_version( exp: &str, version: ClarityVersion, epoch: StacksEpochId, -) -> Result { +) -> Result { mem_run_analysis(exp, version, epoch).map(|(type_sig_opt, _)| type_sig_opt.unwrap()) } -fn type_check_helper_v1(exp: &str) -> Result { +fn type_check_helper_v1(exp: &str) -> Result { type_check_helper_version(exp, ClarityVersion::Clarity1, StacksEpochId::latest()) } @@ -103,26 +105,26 @@ fn test_from_consensus_buff() { let bad = [ ( "(from-consensus-buff?)", - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), ), ( "(from-consensus-buff? 0x00 0x00 0x00)", - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), ), ( "(from-consensus-buff? 0x00 0x00)", - CheckErrors::InvalidTypeDescription, + CheckErrorKind::InvalidTypeDescription, ), ( "(from-consensus-buff? int u6)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_MAX), Box::new(TypeSignature::UIntType), ), ), ( "(from-consensus-buff? (buff 1048576) 0x00)", - CheckErrors::ValueTooLarge, + CheckErrorKind::ValueTooLarge, ), ]; @@ -199,26 +201,26 @@ fn test_to_consensus_buff() { let bad = [ ( "(to-consensus-buff?)", - CheckErrors::IncorrectArgumentCount(1, 0), + CheckErrorKind::IncorrectArgumentCount(1, 0), ), ( "(to-consensus-buff? 0x00 0x00)", - CheckErrors::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 2), ), ( "(define-private (my-func (x (buff 1048576))) (to-consensus-buff? x))", - CheckErrors::ValueTooLarge, + CheckErrorKind::ValueTooLarge, ), ( "(define-private (my-func (x (buff 1048570))) (to-consensus-buff? x))", - CheckErrors::ValueTooLarge, + CheckErrorKind::ValueTooLarge, ), ( "(define-private (my-func (x (buff 1048567))) (to-consensus-buff? x))", - CheckErrors::ValueTooLarge, + CheckErrorKind::ValueTooLarge, ), ]; @@ -277,10 +279,10 @@ fn test_get_block_info() { "(get-block-info? time)", ]; let bad_expected = [ - CheckErrors::NoSuchBlockInfoProperty("none".to_string()), - CheckErrors::TypeError(Box::new(UIntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::RequiresAtLeastArguments(2, 1), + CheckErrorKind::NoSuchBlockInfoProperty("none".to_string()), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::RequiresAtLeastArguments(2, 1), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -322,7 +324,7 @@ fn test_get_block_info() { } for good_test in good_v210.iter() { - if let CheckErrors::NoSuchBlockInfoProperty(_) = + if let CheckErrorKind::NoSuchBlockInfoProperty(_) = *type_check_helper_v1(good_test).unwrap_err().err { } else { @@ -343,10 +345,10 @@ fn test_get_burn_block_info() { r#"(get-burn-block-info? header-hash "a")"#, ]; let bad_expected = [ - CheckErrors::NoSuchBlockInfoProperty("none".to_string()), - CheckErrors::IncorrectArgumentCount(2, 0), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::TypeError( + CheckErrorKind::NoSuchBlockInfoProperty("none".to_string()), + CheckErrorKind::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError( Box::new(UIntType), Box::new(SequenceType(StringType(ASCII( BufferLength::try_from(1u32).expect("BufferLength::try_from failed"), @@ -403,15 +405,15 @@ fn test_define_functions(#[case] version: ClarityVersion, #[case] epoch: StacksE ), ]; let bad_expected = [ - CheckErrors::TooManyFunctionParameters( + CheckErrorKind::TooManyFunctionParameters( MAX_FUNCTION_PARAMETERS + 1, MAX_FUNCTION_PARAMETERS, ), - CheckErrors::TooManyFunctionParameters( + CheckErrorKind::TooManyFunctionParameters( MAX_FUNCTION_PARAMETERS + 1, MAX_FUNCTION_PARAMETERS, ), - CheckErrors::TooManyFunctionParameters( + CheckErrorKind::TooManyFunctionParameters( MAX_FUNCTION_PARAMETERS + 1, MAX_FUNCTION_PARAMETERS, ), @@ -451,11 +453,11 @@ fn test_define_trait(#[case] version: ClarityVersion, #[case] epoch: StacksEpoch "(define-trait trait-1 ((get-1 (uint) (response uint uint)) u1))", ]; let bad_expected = [ - CheckErrors::InvalidTypeDescription, - CheckErrors::DefineTraitBadSignature, - CheckErrors::DefineTraitBadSignature, - CheckErrors::InvalidTypeDescription, - CheckErrors::DefineTraitBadSignature, + CheckErrorKind::InvalidTypeDescription, + CheckErrorKind::DefineTraitBadSignature, + CheckErrorKind::DefineTraitBadSignature, + CheckErrorKind::InvalidTypeDescription, + CheckErrorKind::DefineTraitBadSignature, ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { @@ -469,13 +471,13 @@ fn test_define_trait(#[case] version: ClarityVersion, #[case] epoch: StacksEpoch "(define-trait trait-1 ((get-1 (uint) (response uint uint)))) u1)", ]; let bad_expected = [ - ParseErrors::DefineTraitBadSignature, - ParseErrors::DefineTraitBadSignature, + ParseErrorKind::DefineTraitBadSignature, + ParseErrorKind::DefineTraitBadSignature, if epoch == StacksEpochId::Epoch20 || epoch == StacksEpochId::Epoch2_05 { // the pre-2.1 parser returns less instructive errors - ParseErrors::ClosingParenthesisUnexpected + ParseErrorKind::ClosingParenthesisUnexpected } else { - ParseErrors::UnexpectedToken(Token::Rparen) + ParseErrorKind::UnexpectedToken(Token::Rparen) }, ]; @@ -503,8 +505,8 @@ fn test_define_trait(#[case] version: ClarityVersion, #[case] epoch: StacksEpoch ), ]; let bad_expected = [ - CheckErrors::TraitTooManyMethods(MAX_TRAIT_METHODS + 1, MAX_TRAIT_METHODS), - CheckErrors::TooManyFunctionParameters( + CheckErrorKind::TraitTooManyMethods(MAX_TRAIT_METHODS + 1, MAX_TRAIT_METHODS), + CheckErrorKind::TooManyFunctionParameters( MAX_FUNCTION_PARAMETERS + 1, MAX_FUNCTION_PARAMETERS, ), @@ -533,10 +535,10 @@ fn test_use_trait(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) "(use-trait)", ]; let bad_expected = [ - ParseErrors::ImportTraitBadSignature, - ParseErrors::ImportTraitBadSignature, - ParseErrors::ImportTraitBadSignature, - ParseErrors::ImportTraitBadSignature, + ParseErrorKind::ImportTraitBadSignature, + ParseErrorKind::ImportTraitBadSignature, + ParseErrorKind::ImportTraitBadSignature, + ParseErrorKind::ImportTraitBadSignature, ]; let contract_identifier = QualifiedContractIdentifier::transient(); @@ -550,8 +552,8 @@ fn test_use_trait(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) fn test_impl_trait(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) { let bad = ["(impl-trait trait-1)", "(impl-trait)"]; let bad_expected = [ - ParseErrors::ImplTraitBadSignature, - ParseErrors::ImplTraitBadSignature, + ParseErrorKind::ImplTraitBadSignature, + ParseErrorKind::ImplTraitBadSignature, ]; let contract_identifier = QualifiedContractIdentifier::transient(); @@ -599,42 +601,42 @@ fn test_stx_ops() { "(stx-get-balance 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR)" ]; let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(PrincipalType), Box::new(SequenceType(BufferType( BufferLength::try_from(2_u32).unwrap(), ))), ), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 5), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(UIntType)), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(BoolType)), - CheckErrors::TypeError( + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 5), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(UIntType)), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(BoolType)), + CheckErrorKind::TypeError( Box::new(PrincipalType), Box::new(OptionalType(Box::from(PrincipalType))), ), - CheckErrors::IncorrectArgumentCount(3, 4), - CheckErrors::TypeError( + CheckErrorKind::IncorrectArgumentCount(3, 4), + CheckErrorKind::TypeError( Box::new(PrincipalType), Box::new(SequenceType(BufferType( BufferLength::try_from(2_u32).unwrap(), ))), ), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(4, 5), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(UIntType)), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(BoolType)), - CheckErrors::TypeError( + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(4, 5), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(UIntType)), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(BoolType)), + CheckErrorKind::TypeError( Box::new(PrincipalType), Box::new(OptionalType(Box::from(PrincipalType))), ), - CheckErrors::IncorrectArgumentCount(4, 3), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(BoolType)), - CheckErrors::IncorrectArgumentCount(2, 3), - CheckErrors::TypeError(Box::new(PrincipalType), Box::new(BoolType)), - CheckErrors::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(4, 3), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(BoolType)), + CheckErrorKind::IncorrectArgumentCount(2, 3), + CheckErrorKind::TypeError(Box::new(PrincipalType), Box::new(BoolType)), + CheckErrorKind::IncorrectArgumentCount(1, 2), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -663,7 +665,7 @@ fn test_tx_sponsor() { ]; let bad = ["(stx-transfer? u10 tx-sponsor? 'SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G)"]; - let bad_expected = [CheckErrors::TypeError( + let bad_expected = [CheckErrorKind::TypeError( Box::new(PrincipalType), Box::new(OptionalType(Box::from(PrincipalType))), )]; @@ -731,7 +733,7 @@ fn test_destructuring_opts(#[case] version: ClarityVersion, #[case] epoch: Stack let bad = [ ( "(unwrap-err! (some 2) 2)", - CheckErrors::ExpectedResponseType(Box::new(TypeSignature::from_string( + CheckErrorKind::ExpectedResponseType(Box::new(TypeSignature::from_string( "(optional int)", version, epoch, @@ -739,88 +741,92 @@ fn test_destructuring_opts(#[case] version: ClarityVersion, #[case] epoch: Stack ), ( "(unwrap! (err 3) 2)", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(unwrap-err-panic (ok 3))", - CheckErrors::CouldNotDetermineResponseErrType, + CheckErrorKind::CouldNotDetermineResponseErrType, ), ( "(unwrap-panic none)", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(define-private (foo) (if (> 1 0) none none)) (unwrap-panic (foo))", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(unwrap-panic (err 3))", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(match none inner-value (/ 1 0) (+ 1 8))", - CheckErrors::CouldNotDetermineMatchTypes, + CheckErrorKind::CouldNotDetermineMatchTypes, ), ( "(match (ok 1) ok-val (/ ok-val 0) err-val (+ err-val 7))", - CheckErrors::CouldNotDetermineMatchTypes, + CheckErrorKind::CouldNotDetermineMatchTypes, ), ( "(match (err 1) ok-val (/ ok-val 0) err-val (+ err-val 7))", - CheckErrors::CouldNotDetermineMatchTypes, + CheckErrorKind::CouldNotDetermineMatchTypes, ), ( "(define-private (foo) (if (> 1 0) (ok 1) (err u8))) (match (foo) ok-val (+ 1 ok-val) err-val (/ err-val u0))", - CheckErrors::MatchArmsMustMatch( + CheckErrorKind::MatchArmsMustMatch( Box::new(TypeSignature::IntType), Box::new(TypeSignature::UIntType), ), ), ( "(match (some 1) inner-value (+ 1 inner-value) (> 1 28))", - CheckErrors::MatchArmsMustMatch( + CheckErrorKind::MatchArmsMustMatch( Box::new(TypeSignature::IntType), Box::new(TypeSignature::BoolType), ), ), ( "(match (some 1) inner-value (+ 1 inner-value))", - CheckErrors::BadMatchOptionSyntax(Box::new(CheckErrors::IncorrectArgumentCount(4, 3))), + CheckErrorKind::BadMatchOptionSyntax(Box::new(CheckErrorKind::IncorrectArgumentCount( + 4, 3, + ))), ), ( "(match (ok 1) inner-value (+ 1 inner-value))", - CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::IncorrectArgumentCount( - 5, 3, - ))), + CheckErrorKind::BadMatchResponseSyntax(Box::new( + CheckErrorKind::IncorrectArgumentCount(5, 3), + )), ), ( "(match (ok 1) 1 (+ 1 1) err-val (+ 2 err-val))", - CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)), + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)), ), ( "(match (ok 1) ok-val (+ 1 1) (+ 3 4) (+ 2 err-val))", - CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)), + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)), ), ( "(match (some 1) 2 (+ 1 1) (+ 3 4))", - CheckErrors::BadMatchOptionSyntax(Box::new(CheckErrors::ExpectedName)), + CheckErrorKind::BadMatchOptionSyntax(Box::new(CheckErrorKind::ExpectedName)), ), - ("(match)", CheckErrors::RequiresAtLeastArguments(1, 0)), + ("(match)", CheckErrorKind::RequiresAtLeastArguments(1, 0)), ( "(match 1 ok-val (/ ok-val 0) err-val (+ err-val 7))", - CheckErrors::BadMatchInput(Box::new(TypeSignature::from_string("int", version, epoch))), + CheckErrorKind::BadMatchInput(Box::new(TypeSignature::from_string( + "int", version, epoch, + ))), ), ( "(default-to 3 5)", - CheckErrors::ExpectedOptionalType(Box::new(TypeSignature::IntType)), + CheckErrorKind::ExpectedOptionalType(Box::new(TypeSignature::IntType)), ), ( "(define-private (foo (x int)) (match (some 3) x (+ x 2) 5))", - CheckErrors::NameAlreadyUsed("x".to_string()), + CheckErrorKind::NameAlreadyUsed("x".to_string()), ), ( "(define-private (t1 (x uint)) (if (> x u1) (ok x) (err false))) @@ -828,7 +834,7 @@ fn test_destructuring_opts(#[case] version: ClarityVersion, #[case] epoch: Stack (if (> x u4) (err u3) (ok (+ u2 (try! (t1 x))))))", - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( Box::new( TypeSignature::new_response(TypeSignature::NoType, TypeSignature::BoolType) .unwrap(), @@ -843,7 +849,7 @@ fn test_destructuring_opts(#[case] version: ClarityVersion, #[case] epoch: Stack "(define-private (t1 (x uint)) (if (> x u1) (ok x) (err false))) (define-private (t2 (x uint)) (> u2 (try! (t1 x))))", - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( Box::new( TypeSignature::new_response(TypeSignature::NoType, TypeSignature::BoolType) .unwrap(), @@ -853,18 +859,24 @@ fn test_destructuring_opts(#[case] version: ClarityVersion, #[case] epoch: Stack ), ( "(try! (ok 3))", - CheckErrors::CouldNotDetermineResponseErrType, + CheckErrorKind::CouldNotDetermineResponseErrType, + ), + ( + "(try! none)", + CheckErrorKind::CouldNotDetermineResponseOkType, ), - ("(try! none)", CheckErrors::CouldNotDetermineResponseOkType), ( "(try! (err 3))", - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::CouldNotDetermineResponseOkType, ), ( "(try! 3)", - CheckErrors::ExpectedOptionalOrResponseType(Box::new(TypeSignature::IntType)), + CheckErrorKind::ExpectedOptionalOrResponseType(Box::new(TypeSignature::IntType)), + ), + ( + "(try! (ok 3) 4)", + CheckErrorKind::IncorrectArgumentCount(1, 2), ), - ("(try! (ok 3) 4)", CheckErrors::IncorrectArgumentCount(1, 2)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -886,14 +898,14 @@ fn test_at_block() { let bad = [ ( "(at-block (sha512 u0) u1)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_32), Box::new(TypeSignature::BUFFER_64), ), ), ( "(at-block (sha256 u0) u1 u2)", - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), ), ]; @@ -913,7 +925,7 @@ fn test_at_block() { fn test_trait_reference_unknown(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) { let bad = [( "(+ 1 )", - ParseErrors::TraitReferenceUnknown("kvstore".to_string()), + ParseErrorKind::TraitReferenceUnknown("kvstore".to_string()), )]; let contract_identifier = QualifiedContractIdentifier::transient(); @@ -927,7 +939,7 @@ fn test_trait_reference_unknown(#[case] version: ClarityVersion, #[case] epoch: fn test_unexpected_use_of_field_or_trait_reference() { let bad = [( "(+ 1 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR.contract.field)", - CheckErrors::UnexpectedTraitOrFieldReference, + CheckErrorKind::UnexpectedTraitOrFieldReference, )]; for (bad_test, expected) in bad.iter() { @@ -974,23 +986,23 @@ fn test_bitwise_bad_checks() { "(bit-or 1 2 u4)", ]; let bad_expected = [ - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::TypeError(Box::new(IntType), Box::new(UIntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::UnionTypeError( + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(UIntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::UnionTypeError( vec![IntType, UIntType], Box::new(SequenceType(StringType(ASCII( BufferLength::try_from(5u32).unwrap(), )))), ), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::TypeError(Box::new(IntType), Box::new(UIntType)), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(UIntType)), + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(UIntType)), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(UIntType)), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { @@ -1015,12 +1027,12 @@ fn test_simple_arithmetic_checks() { "(and (or true false) (+ 1 2 3))", ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::RequiresAtLeastArguments(1, 0), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::UndefinedVariable("x".to_string()), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::RequiresAtLeastArguments(1, 0), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::UndefinedVariable("x".to_string()), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1081,14 +1093,14 @@ fn test_simple_hash_checks() { for bad_test in bad_types.iter() { assert!(matches!( *type_check_helper(bad_test).unwrap_err().err, - CheckErrors::UnionTypeError(_, _) + CheckErrorKind::UnionTypeError(_, _) )); } for bad_test in invalid_args.iter() { assert!(matches!( *type_check_helper(bad_test).unwrap_err().err, - CheckErrors::IncorrectArgumentCount(_, _) + CheckErrorKind::IncorrectArgumentCount(_, _) )); } } @@ -1111,10 +1123,10 @@ fn test_simple_ifs() { ]; let bad_expected = [ - CheckErrors::IfArmsMustMatch(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IfArmsMustMatch(Box::new(ascii_type(1)), Box::new(BoolType)), - CheckErrors::IncorrectArgumentCount(3, 0), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IfArmsMustMatch(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IfArmsMustMatch(Box::new(ascii_type(1)), Box::new(BoolType)), + CheckErrorKind::IncorrectArgumentCount(3, 0), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1147,9 +1159,9 @@ fn test_simple_lets() { ]; let bad_expected = [ - CheckErrors::BadSyntaxBinding(SyntaxBindingError::let_binding_invalid_length(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::let_binding_not_atom(0)), - CheckErrors::TypeError( + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::let_binding_invalid_length(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::let_binding_not_atom(0)), + CheckErrorKind::TypeError( Box::new(TypeSignature::IntType), Box::new(TypeSignature::UIntType), ), @@ -1222,47 +1234,47 @@ fn test_index_of() { ]; let bad_expected = [ - CheckErrors::ExpectedSequence(Box::new(TypeSignature::IntType)), - CheckErrors::TypeError( + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::IntType)), + CheckErrorKind::TypeError( Box::new(TypeSignature::IntType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_MIN), Box::new(TypeSignature::STRING_ASCII_MIN), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::STRING_UTF8_MIN), Box::new(TypeSignature::STRING_ASCII_MIN), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::STRING_ASCII_MIN), Box::new(TypeSignature::STRING_UTF8_MIN), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::list_of(TypeSignature::IntType, 1).unwrap()), Box::new(TypeSignature::list_of(TypeSignature::IntType, 2).unwrap()), ), - CheckErrors::ExpectedSequence(Box::new(TypeSignature::IntType)), - CheckErrors::TypeError( + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::IntType)), + CheckErrorKind::TypeError( Box::new(TypeSignature::IntType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_MIN), Box::new(TypeSignature::STRING_ASCII_MIN), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::STRING_UTF8_MIN), Box::new(TypeSignature::STRING_ASCII_MIN), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::STRING_ASCII_MIN), Box::new(TypeSignature::STRING_UTF8_MIN), ), - CheckErrors::CouldNotDetermineType, - CheckErrors::CouldNotDetermineType, - CheckErrors::CouldNotDetermineType, + CheckErrorKind::CouldNotDetermineType, + CheckErrorKind::CouldNotDetermineType, + CheckErrorKind::CouldNotDetermineType, ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { @@ -1306,16 +1318,16 @@ fn test_element_at() { ]; let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::ExpectedSequence(Box::new(TypeSignature::IntType)), - CheckErrors::TypeError( + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::IntType)), + CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::IntType), ), - CheckErrors::ExpectedSequence(Box::new(TypeSignature::IntType)), + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1347,12 +1359,12 @@ fn test_eqs(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::TypeError( + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::TypeError( Box::new(TypeSignature::list_of(IntType, 1).unwrap()), Box::new(IntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::from_string( "(optional bool)", version, @@ -1390,9 +1402,9 @@ fn test_asserts() { ]; let bad_expected = [ - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 3), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1456,23 +1468,23 @@ fn test_lists() { "(map + (list 1 2 3 4 5) (list true true true true true))", ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(BoolType), Box::new(buff_type(20))), - CheckErrors::TypeError(Box::new(BoolType), Box::new(buff_type(20))), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 3), - CheckErrors::UnknownFunction("ynot".to_string()), - CheckErrors::IllegalOrUnknownFunctionApplication("if".to_string()), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), - CheckErrors::ExpectedSequence(Box::new(UIntType)), - CheckErrors::ExpectedSequence(Box::new(IntType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(buff_type(20))), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(buff_type(20))), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 3), + CheckErrorKind::UnknownFunction("ynot".to_string()), + CheckErrorKind::IllegalOrUnknownFunctionApplication("if".to_string()), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), + CheckErrorKind::ExpectedSequence(Box::new(UIntType)), + CheckErrorKind::ExpectedSequence(Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1513,20 +1525,20 @@ fn test_buff() { "(len 1)", ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(BoolType), Box::new(buff_type(20))), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 3), - CheckErrors::UnknownFunction("ynot".to_string()), - CheckErrors::IllegalOrUnknownFunctionApplication("if".to_string()), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), - CheckErrors::ExpectedSequence(Box::new(UIntType)), - CheckErrors::ExpectedSequence(Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(buff_type(20))), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 3), + CheckErrorKind::UnknownFunction("ynot".to_string()), + CheckErrorKind::IllegalOrUnknownFunctionApplication("if".to_string()), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::UnionTypeError(vec![IntType, UIntType], Box::new(BoolType)), + CheckErrorKind::ExpectedSequence(Box::new(UIntType)), + CheckErrorKind::ExpectedSequence(Box::new(IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -1594,9 +1606,9 @@ fn test_native_as_max_len() { "(as-max-len? 0x01 u1048577)", ]; let bad_expected = [ - CheckErrors::ValueTooLarge, - CheckErrors::ValueTooLarge, - CheckErrors::ValueTooLarge, + CheckErrorKind::ValueTooLarge, + CheckErrorKind::ValueTooLarge, + CheckErrorKind::ValueTooLarge, ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1640,9 +1652,9 @@ fn test_native_append() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(IntType), Box::new(UIntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(UIntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 1), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1680,9 +1692,9 @@ fn test_slice_list() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 2), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1711,9 +1723,9 @@ fn test_slice_buff() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 2), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1745,9 +1757,9 @@ fn test_slice_ascii() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 2), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1776,9 +1788,9 @@ fn test_slice_utf8() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 2), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -1824,17 +1836,17 @@ fn test_replace_at_list() { ]; let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(IntType), Box::new(SequenceType(ListType( ListTypeData::new_list(IntType, 1).unwrap(), ))), ), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 4), - CheckErrors::IncorrectArgumentCount(3, 2), - CheckErrors::TypeError( + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 4), + CheckErrorKind::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError( Box::new(SequenceType(ListType( ListTypeData::new_list(IntType, 1).unwrap(), ))), @@ -1882,20 +1894,20 @@ fn test_replace_at_buff() { let buff_len = BufferLength::try_from(1u32).unwrap(); let buff_len_two = BufferLength::try_from(2u32).unwrap(); let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(BufferType(buff_len.clone()))), Box::new(SequenceType(ListType( ListTypeData::new_list(IntType, 1).unwrap(), ))), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(BufferType(buff_len.clone()))), Box::new(SequenceType(StringType(ASCII(buff_len.clone())))), ), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 4), - CheckErrors::IncorrectArgumentCount(3, 2), - CheckErrors::TypeError( + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 4), + CheckErrorKind::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError( Box::new(SequenceType(BufferType(buff_len))), Box::new(SequenceType(BufferType(buff_len_two))), ), @@ -1940,20 +1952,20 @@ fn test_replace_at_ascii() { let buff_len = BufferLength::try_from(1u32).unwrap(); let buff_len_two = BufferLength::try_from(2u32).unwrap(); let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(StringType(ASCII(buff_len.clone())))), Box::new(SequenceType(ListType( ListTypeData::new_list(IntType, 1).unwrap(), ))), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(StringType(ASCII(buff_len.clone())))), Box::new(SequenceType(BufferType(buff_len.clone()))), ), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 4), - CheckErrors::IncorrectArgumentCount(3, 2), - CheckErrors::TypeError( + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 4), + CheckErrorKind::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError( Box::new(SequenceType(StringType(ASCII(buff_len)))), Box::new(SequenceType(StringType(ASCII(buff_len_two)))), ), @@ -1998,20 +2010,20 @@ fn test_replace_at_utf8() { let str_len = StringUTF8Length::try_from(1u32).unwrap(); let str_len_two = StringUTF8Length::try_from(2u32).unwrap(); let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(StringType(UTF8(str_len.clone())))), Box::new(SequenceType(ListType( ListTypeData::new_list(IntType, 1).unwrap(), ))), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(StringType(UTF8(str_len.clone())))), Box::new(SequenceType(BufferType(buff_len))), ), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(3, 4), - CheckErrors::IncorrectArgumentCount(3, 2), - CheckErrors::TypeError( + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(3, 4), + CheckErrorKind::IncorrectArgumentCount(3, 2), + CheckErrorKind::TypeError( Box::new(SequenceType(StringType(UTF8(str_len)))), Box::new(SequenceType(StringType(UTF8(str_len_two)))), ), @@ -2040,9 +2052,9 @@ fn test_native_concat() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(IntType), Box::new(UIntType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(UIntType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::IncorrectArgumentCount(2, 1), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { assert_eq!(*expected, *type_check_helper(bad_test).unwrap_err().err); @@ -2125,8 +2137,8 @@ fn test_tuples() { ]; let bad_expected = [ - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(BoolType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(BoolType), Box::new(IntType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -2150,7 +2162,7 @@ fn test_empty_tuple_should_fail() { assert_eq!( *mem_type_check(contract_src).unwrap_err().err, - CheckErrors::EmptyTuplesNotAllowed, + CheckErrorKind::EmptyTuplesNotAllowed, ); } @@ -2230,9 +2242,9 @@ fn test_simple_uints() { let bad = ["(> u1 1)", "(to-uint true)", "(to-int false)"]; let bad_expected = [ - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)), - CheckErrors::TypeError(Box::new(UIntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)), + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(BoolType)), ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -2264,9 +2276,9 @@ fn test_buffer_to_ints() { ]; let bad_expected = [ - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::IncorrectArgumentCount(1, 0), - CheckErrors::TypeError( + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 0), + CheckErrorKind::TypeError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap(), ))), @@ -2274,7 +2286,7 @@ fn test_buffer_to_ints() { BufferLength::try_from(17_u32).unwrap(), ))), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap(), ))), @@ -2338,37 +2350,37 @@ fn test_string_to_ints() { ]; let bad_expected = [ - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::IncorrectArgumentCount(1, 0), - CheckErrors::UnionTypeError( + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 0), + CheckErrorKind::UnionTypeError( vec![IntType, UIntType], Box::new(SequenceType(BufferType( BufferLength::try_from(17_u32).unwrap(), ))), ), - CheckErrors::UnionTypeError( + CheckErrorKind::UnionTypeError( vec![IntType, UIntType], Box::new(SequenceType(StringType(ASCII( BufferLength::try_from(1_u32).unwrap(), )))), ), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::IncorrectArgumentCount(1, 0), - CheckErrors::UnionTypeError( + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 0), + CheckErrorKind::UnionTypeError( vec![IntType, UIntType], Box::new(SequenceType(BufferType( BufferLength::try_from(17_u32).unwrap(), ))), ), - CheckErrors::UnionTypeError( + CheckErrorKind::UnionTypeError( vec![IntType, UIntType], Box::new(SequenceType(StringType(ASCII( BufferLength::try_from(1_u32).unwrap(), )))), ), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::IncorrectArgumentCount(1, 0), - CheckErrors::UnionTypeError( + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 0), + CheckErrorKind::UnionTypeError( vec![ TypeSignature::STRING_ASCII_MAX, TypeSignature::STRING_UTF8_MAX, @@ -2377,16 +2389,16 @@ fn test_string_to_ints() { BufferLength::try_from(17_u32).unwrap(), ))), ), - CheckErrors::UnionTypeError( + CheckErrorKind::UnionTypeError( vec![ TypeSignature::STRING_ASCII_MAX, TypeSignature::STRING_UTF8_MAX, ], Box::new(IntType), ), - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::IncorrectArgumentCount(1, 0), - CheckErrors::UnionTypeError( + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 0), + CheckErrorKind::UnionTypeError( vec![ TypeSignature::STRING_ASCII_MAX, TypeSignature::STRING_UTF8_MAX, @@ -2395,7 +2407,7 @@ fn test_string_to_ints() { BufferLength::try_from(17_u32).unwrap(), ))), ), - CheckErrors::UnionTypeError( + CheckErrorKind::UnionTypeError( vec![ TypeSignature::STRING_ASCII_MAX, TypeSignature::STRING_UTF8_MAX, @@ -2450,7 +2462,7 @@ fn test_response_inference(#[case] version: ClarityVersion, #[case] epoch: Stack ]; let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::from_string( "(response bool int)", version, @@ -2458,8 +2470,8 @@ fn test_response_inference(#[case] version: ClarityVersion, #[case] epoch: Stack )), Box::new(BoolType), ), - CheckErrors::ReturnTypesMustMatch(Box::new(IntType), Box::new(BoolType)), - CheckErrors::CouldNotDetermineResponseOkType, + CheckErrorKind::ReturnTypesMustMatch(Box::new(IntType), Box::new(BoolType)), + CheckErrorKind::CouldNotDetermineResponseOkType, ]; for (good_test, expected) in good.iter().zip(expected.iter()) { @@ -2577,7 +2589,7 @@ fn test_options(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) { if version < ClarityVersion::Clarity2 { assert!( match *mem_run_analysis(contract, version, epoch).unwrap_err().err { - CheckErrors::TypeError(t1, t2) => { + CheckErrorKind::TypeError(t1, t2) => { *t1 == TypeSignature::from_string("(optional bool)", version, epoch) && *t2 == TypeSignature::from_string("(optional int)", version, epoch) } @@ -2587,7 +2599,7 @@ fn test_options(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) { } else { assert!( match *mem_run_analysis(contract, version, epoch).unwrap_err().err { - CheckErrors::TypeError(t1, t2) => { + CheckErrorKind::TypeError(t1, t2) => { *t1 == TypeSignature::from_string("bool", version, epoch) && *t2 == TypeSignature::from_string("int", version, epoch) } @@ -2696,7 +2708,7 @@ fn test_missing_value_on_declaration_should_fail() { let res = mem_type_check(contract_src).unwrap_err(); assert!(matches!( *res.err, - CheckErrors::IncorrectArgumentCount(_, _) + CheckErrorKind::IncorrectArgumentCount(_, _) )); } @@ -2707,7 +2719,7 @@ fn test_mismatching_type_on_declaration_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } #[test] @@ -2723,7 +2735,7 @@ fn test_mismatching_type_on_update_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } #[test] @@ -2735,7 +2747,7 @@ fn test_direct_access_to_persisted_var_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } #[test] @@ -2750,7 +2762,7 @@ fn test_data_var_shadowed_by_let_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -2763,7 +2775,7 @@ fn test_mutating_unknown_data_var_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NoSuchDataVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::NoSuchDataVariable(_))); } #[test] @@ -2774,7 +2786,7 @@ fn test_accessing_unknown_data_var_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NoSuchDataVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::NoSuchDataVariable(_))); } #[test] @@ -2785,7 +2797,7 @@ fn test_let_shadowed_by_let_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -2797,7 +2809,7 @@ fn test_let_shadowed_by_nested_let_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -2810,7 +2822,7 @@ fn test_define_constant_shadowed_by_let_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -2822,7 +2834,7 @@ fn test_define_constant_shadowed_by_argument_should_fail() { "#; let res = mem_type_check(contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::NameAlreadyUsed(_))); + assert!(matches!(*res.err, CheckErrorKind::NameAlreadyUsed(_))); } #[test] @@ -3022,7 +3034,7 @@ fn test_fetch_entry_mismatching_type_signatures() { ({case}))" ); let res = mem_type_check(&contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } } @@ -3037,7 +3049,7 @@ fn test_fetch_entry_unbound_variables() { ({case}))" ); let res = mem_type_check(&contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } } @@ -3079,7 +3091,7 @@ fn test_insert_entry_mismatching_type_signatures() { ({case}))" ); let res = mem_type_check(&contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } } @@ -3097,7 +3109,7 @@ fn test_insert_entry_unbound_variables() { ({case}))" ); let res = mem_type_check(&contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } } @@ -3137,7 +3149,7 @@ fn test_delete_entry_mismatching_type_signatures() { ({case}))" ); let res = mem_type_check(&contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } } @@ -3152,7 +3164,7 @@ fn test_delete_entry_unbound_variables() { ({case}))" ); let res = mem_type_check(&contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } } @@ -3196,7 +3208,7 @@ fn test_set_entry_mismatching_type_signatures() { ({case}))" ); let res = mem_type_check(&contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::TypeError(_, _))); + assert!(matches!(*res.err, CheckErrorKind::TypeError(_, _))); } } @@ -3214,7 +3226,7 @@ fn test_set_entry_unbound_variables() { ({case}))" ); let res = mem_type_check(&contract_src).unwrap_err(); - assert!(matches!(*res.err, CheckErrors::UndefinedVariable(_))); + assert!(matches!(*res.err, CheckErrorKind::UndefinedVariable(_))); } } @@ -3330,7 +3342,7 @@ fn test_buff_negative_len() { (func 0x00)"; let res = mem_type_check(contract_src).unwrap_err(); - assert_eq!(*res.err, CheckErrors::ValueOutOfBounds); + assert_eq!(*res.err, CheckErrorKind::ValueOutOfBounds); } #[test] @@ -3339,7 +3351,7 @@ fn test_string_ascii_negative_len() { (func \"\")"; let res = mem_type_check(contract_src).unwrap_err(); - assert_eq!(*res.err, CheckErrors::ValueOutOfBounds); + assert_eq!(*res.err, CheckErrorKind::ValueOutOfBounds); } #[test] @@ -3348,7 +3360,7 @@ fn test_string_utf8_negative_len() { (func u\"\")"; let res = mem_type_check(contract_src).unwrap_err(); - assert_eq!(*res.err, CheckErrors::ValueOutOfBounds); + assert_eq!(*res.err, CheckErrorKind::ValueOutOfBounds); } #[test] @@ -3392,7 +3404,7 @@ fn test_comparison_types() { r#"(>= "aaa" "aaa" "aaa")"#, ]; let bad_expected = [ - CheckErrors::UnionTypeError( + CheckErrorKind::UnionTypeError( vec![ IntType, UIntType, @@ -3406,7 +3418,7 @@ fn test_comparison_types() { ], Box::new(PrincipalType), ), - CheckErrors::UnionTypeError( + CheckErrorKind::UnionTypeError( vec![ IntType, UIntType, @@ -3422,7 +3434,7 @@ fn test_comparison_types() { ListTypeData::new_list(IntType, 3).unwrap(), ))), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(StringType(UTF8( StringUTF8Length::try_from(3u32).unwrap(), )))), @@ -3430,7 +3442,7 @@ fn test_comparison_types() { BufferLength::try_from(2_u32).unwrap(), )))), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(StringType(ASCII( BufferLength::try_from(3_u32).unwrap(), )))), @@ -3438,7 +3450,7 @@ fn test_comparison_types() { BufferLength::try_from(2_u32).unwrap(), ))), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(BufferType( BufferLength::try_from(2_u32).unwrap(), ))), @@ -3446,7 +3458,7 @@ fn test_comparison_types() { StringUTF8Length::try_from(3u32).unwrap(), )))), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(SequenceType(BufferType( BufferLength::try_from(2_u32).unwrap(), ))), @@ -3454,9 +3466,9 @@ fn test_comparison_types() { BufferLength::try_from(3_u32).unwrap(), )))), ), - CheckErrors::IncorrectArgumentCount(2, 0), - CheckErrors::IncorrectArgumentCount(2, 1), - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 3), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { @@ -3485,9 +3497,9 @@ fn test_principal_destruct() { r#"(principal-destruct? 0x22)"#, ]; let bad_expected = [ - CheckErrors::IncorrectArgumentCount(1, 2), - CheckErrors::IncorrectArgumentCount(1, 0), - CheckErrors::TypeError( + CheckErrorKind::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 0), + CheckErrorKind::TypeError( Box::new(TypeSignature::PrincipalType), Box::new(TypeSignature::BUFFER_1), ), @@ -3541,17 +3553,17 @@ fn test_principal_construct() { // Too few arguments, just has the `(buff 1)`. ( r#"(principal-construct? 0x22)"#, - CheckErrors::RequiresAtLeastArguments(2, 1), + CheckErrorKind::RequiresAtLeastArguments(2, 1), ), // Too few arguments, just hs the `(buff 20)`. ( r#"(principal-construct? 0xfa6bf38ed557fe417333710d6033e9419391a320)"#, - CheckErrors::RequiresAtLeastArguments(2, 1), + CheckErrorKind::RequiresAtLeastArguments(2, 1), ), // The first buffer is too long, should be `(buff 1)`. ( r#"(principal-construct? 0xfa6bf38ed557fe417333710d6033e9419391a320 0xfa6bf38ed557fe417333710d6033e9419391a320)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_1), Box::new(TypeSignature::BUFFER_20), ), @@ -3559,7 +3571,7 @@ fn test_principal_construct() { // The second buffer is too long, should be `(buff 20)`. ( r#"(principal-construct? 0x22 0xfa6bf38ed557fe417333710d6033e9419391a32009)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_20), Box::new(TypeSignature::SequenceType(SequenceSubtype::BufferType( 21_u32.try_into().unwrap(), @@ -3569,12 +3581,12 @@ fn test_principal_construct() { // `int` argument instead of `(buff 1)` for version. ( r#"(principal-construct? 22 0xfa6bf38ed557fe417333710d6033e9419391a320)"#, - CheckErrors::TypeError(Box::new(TypeSignature::BUFFER_1), Box::new(IntType.clone())), + CheckErrorKind::TypeError(Box::new(TypeSignature::BUFFER_1), Box::new(IntType.clone())), ), // `name` argument is too long ( r#"(principal-construct? 0x22 0xfa6bf38ed557fe417333710d6033e9419391a320 "foooooooooooooooooooooooooooooooooooooooo")"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::CONTRACT_NAME_STRING_ASCII_MAX), Box::new(SequenceType(StringType(ASCII(41_u32.try_into().unwrap())))), ), @@ -3582,7 +3594,7 @@ fn test_principal_construct() { // bad argument type for `name` ( r#"(principal-construct? 0x22 0xfa6bf38ed557fe417333710d6033e9419391a320 u123)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::CONTRACT_NAME_STRING_ASCII_MAX), Box::new(UIntType), ), @@ -3590,7 +3602,7 @@ fn test_principal_construct() { // too many arguments ( r#"(principal-construct? 0x22 0xfa6bf38ed557fe417333710d6033e9419391a320 "foo" "bar")"#, - CheckErrors::RequiresAtMostArguments(3, 4), + CheckErrorKind::RequiresAtMostArguments(3, 4), ), ]; @@ -3644,7 +3656,7 @@ fn test_trait_args() { )"]; let contract_identifier = QualifiedContractIdentifier::transient(); - let bad_expected = [CheckErrors::IncompatibleTrait( + let bad_expected = [CheckErrorKind::IncompatibleTrait( Box::new(TraitIdentifier { name: ClarityName::from("trait-foo"), contract_identifier: contract_identifier.clone(), @@ -3810,15 +3822,15 @@ fn test_list_arg(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) ", ]; let bad_expected = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::list_of(TypeSignature::IntType, 3).unwrap()), Box::new(TypeSignature::list_of(TypeSignature::IntType, 4).unwrap()), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::list_of(TypeSignature::IntType, 3).unwrap()), Box::new(TypeSignature::list_of(TypeSignature::UIntType, 1).unwrap()), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::list_of(TypeSignature::IntType, 3).unwrap()), Box::new( TypeSignature::list_of( @@ -3830,15 +3842,15 @@ fn test_list_arg(#[case] version: ClarityVersion, #[case] epoch: StacksEpochId) ), ]; let bad_expected2 = [ - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::list_of(TypeSignature::IntType, 3).unwrap()), Box::new(TypeSignature::list_of(TypeSignature::IntType, 4).unwrap()), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::IntType), Box::new(TypeSignature::UIntType), ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::IntType), Box::new(TypeSignature::list_of(TypeSignature::NoType, 0).unwrap()), ), @@ -3950,17 +3962,17 @@ fn test_simple_bad_syntax_bindings() { "(from-consensus-buff? (tuple (a (string-ascii -12))) 0x00)", ]; let expected = [ - CheckErrors::BadSyntaxBinding(SyntaxBindingError::let_binding_not_list(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::let_binding_invalid_length(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::let_binding_not_atom(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::eval_binding_not_list(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::eval_binding_invalid_length(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::eval_binding_not_atom(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::tuple_cons_not_list(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::tuple_cons_invalid_length(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::tuple_cons_not_atom(0)), - CheckErrors::ValueOutOfBounds, - CheckErrors::ValueOutOfBounds, + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::let_binding_not_list(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::let_binding_invalid_length(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::let_binding_not_atom(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::eval_binding_not_list(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::eval_binding_invalid_length(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::eval_binding_not_atom(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::tuple_cons_not_list(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::tuple_cons_invalid_length(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::tuple_cons_not_atom(0)), + CheckErrorKind::ValueOutOfBounds, + CheckErrorKind::ValueOutOfBounds, ]; for (bad_code, expected_err) in bad.iter().zip(expected.iter()) { @@ -3984,9 +3996,9 @@ fn test_nested_bad_type_signature_syntax_bindings() { ]; let expected = [ - CheckErrors::ValueOutOfBounds, - CheckErrors::InvalidTypeDescription, - CheckErrors::ValueOutOfBounds, + CheckErrorKind::ValueOutOfBounds, + CheckErrorKind::InvalidTypeDescription, + CheckErrorKind::ValueOutOfBounds, ]; for (bad_code, expected_err) in bad.iter().zip(expected.iter()) { @@ -4011,21 +4023,21 @@ fn test_secp256k1_recover_type_check() { let bad_cases = [ ( "(secp256k1-recover?)".to_string(), - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), ), ( format!( "(secp256k1-recover? {} {} {})", SECP256_MESSAGE_HASH, SECP256K1_SIGNATURE, SECP256K1_PUBLIC_KEY ), - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), ), ( format!( "(secp256k1-recover? {} {})", SECP256K1_SIGNATURE, SECP256K1_SIGNATURE ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_32), Box::new(TypeSignature::BUFFER_65), ), @@ -4035,7 +4047,7 @@ fn test_secp256k1_recover_type_check() { "(secp256k1-recover? {} {})", SECP256_MESSAGE_HASH, SECP256K1_SIGNATURE_TOO_LONG ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_65), Box::new(buffer_66_type.clone()), ), @@ -4069,21 +4081,21 @@ fn test_secp256k1_verify_type_check() { let bad_cases = [ ( "(secp256k1-verify)".to_string(), - CheckErrors::IncorrectArgumentCount(3, 0), + CheckErrorKind::IncorrectArgumentCount(3, 0), ), ( format!( "(secp256k1-verify {} {})", SECP256_MESSAGE_HASH, SECP256K1_SIGNATURE ), - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::IncorrectArgumentCount(3, 2), ), ( format!( "(secp256k1-verify {} {} {})", SECP256K1_SIGNATURE, SECP256K1_SIGNATURE, SECP256K1_PUBLIC_KEY ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_32), Box::new(TypeSignature::BUFFER_65), ), @@ -4093,7 +4105,7 @@ fn test_secp256k1_verify_type_check() { "(secp256k1-verify {} {} {})", SECP256_MESSAGE_HASH, SECP256K1_SIGNATURE_TOO_LONG, SECP256K1_PUBLIC_KEY ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_65), Box::new(buffer_66_type.clone()), ), @@ -4103,7 +4115,7 @@ fn test_secp256k1_verify_type_check() { "(secp256k1-verify {} {} {})", SECP256_MESSAGE_HASH, SECP256K1_SIGNATURE, SECP256K1_SIGNATURE ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_33), Box::new(TypeSignature::BUFFER_65), ), @@ -4132,21 +4144,21 @@ fn test_secp256r1_verify_type_check() { let bad_cases = [ ( "(secp256r1-verify)".to_string(), - CheckErrors::IncorrectArgumentCount(3, 0), + CheckErrorKind::IncorrectArgumentCount(3, 0), ), ( format!( "(secp256r1-verify {} {})", SECP256_MESSAGE_HASH, SECP256R1_SIGNATURE ), - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::IncorrectArgumentCount(3, 2), ), ( format!( "(secp256r1-verify {} {} {})", SECP256K1_SIGNATURE, SECP256R1_SIGNATURE, SECP256K1_PUBLIC_KEY ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_32), Box::new(TypeSignature::BUFFER_65), ), @@ -4156,7 +4168,7 @@ fn test_secp256r1_verify_type_check() { "(secp256r1-verify {} {} {})", SECP256_MESSAGE_HASH, SECP256K1_SIGNATURE, SECP256K1_PUBLIC_KEY ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_64), Box::new(TypeSignature::BUFFER_65), ), @@ -4166,7 +4178,7 @@ fn test_secp256r1_verify_type_check() { "(secp256r1-verify {} {} {})", SECP256_MESSAGE_HASH, SECP256R1_SIGNATURE, SECP256K1_SIGNATURE ), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(TypeSignature::BUFFER_33), Box::new(TypeSignature::BUFFER_65), ), diff --git a/clarity/src/vm/analysis/type_checker/v2_1/tests/post_conditions.rs b/clarity/src/vm/analysis/type_checker/v2_1/tests/post_conditions.rs index 30f2a8d94dc..85ff9b1fe2f 100644 --- a/clarity/src/vm/analysis/type_checker/v2_1/tests/post_conditions.rs +++ b/clarity/src/vm/analysis/type_checker/v2_1/tests/post_conditions.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use clarity_types::errors::CheckErrors; +use clarity_types::errors::CheckErrorKind; use clarity_types::representations::MAX_STRING_LEN; use clarity_types::types::TypeSignature; use stacks_common::types::StacksEpochId; @@ -70,22 +70,22 @@ fn test_restrict_assets(#[case] version: ClarityVersion, #[case] epoch: StacksEp // with-all-assets-unsafe ( "(restrict-assets? tx-sender ((with-all-assets-unsafe)) true)", - CheckErrors::WithAllAllowanceNotAllowed, + CheckErrorKind::WithAllAllowanceNotAllowed, ), // no asset-owner ( "(restrict-assets? ((with-stx u5000)) true)", - CheckErrors::RequiresAtLeastArguments(3, 2), + CheckErrorKind::RequiresAtLeastArguments(3, 2), ), // no asset-owner, 3 args ( "(restrict-assets? ((with-stx u5000)) true true)", - CheckErrors::NonFunctionApplication, + CheckErrorKind::NonFunctionApplication, ), // bad asset-owner type ( "(restrict-assets? u100 ((with-stx u5000)) true)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::PrincipalType.into(), TypeSignature::UIntType.into(), ), @@ -93,57 +93,57 @@ fn test_restrict_assets(#[case] version: ClarityVersion, #[case] epoch: StacksEp // no allowances ( "(restrict-assets? tx-sender true)", - CheckErrors::RequiresAtLeastArguments(3, 2), + CheckErrorKind::RequiresAtLeastArguments(3, 2), ), // allowance not in list ( "(restrict-assets? tx-sender (with-stx u1) true)", - CheckErrors::ExpectedListApplication, + CheckErrorKind::ExpectedListApplication, ), // other value in place of allowance list ( "(restrict-assets? tx-sender u1 true)", - CheckErrors::ExpectedListOfAllowances("restrict-assets?".into(), 2), + CheckErrorKind::ExpectedListOfAllowances("restrict-assets?".into(), 2), ), // non-allowance in allowance list ( "(restrict-assets? tx-sender (u1) true)", - CheckErrors::ExpectedListApplication, + CheckErrorKind::ExpectedListApplication, ), // empty list in allowance list ( "(restrict-assets? tx-sender (()) true)", - CheckErrors::NonFunctionApplication, + CheckErrorKind::NonFunctionApplication, ), // list with literal in allowance list ( "(restrict-assets? tx-sender ((123)) true)", - CheckErrors::NonFunctionApplication, + CheckErrorKind::NonFunctionApplication, ), // non-allowance function in allowance list ( "(restrict-assets? tx-sender ((foo)) true)", - CheckErrors::UnknownFunction("foo".into()), + CheckErrorKind::UnknownFunction("foo".into()), ), // no body expressions ( "(restrict-assets? tx-sender ((with-stx u5000)))", - CheckErrors::RequiresAtLeastArguments(3, 2), + CheckErrorKind::RequiresAtLeastArguments(3, 2), ), // unhandled response in only body expression ( "(restrict-assets? tx-sender ((with-stx u1000)) (err u1))", - CheckErrors::UncheckedIntermediaryResponses, + CheckErrorKind::UncheckedIntermediaryResponses, ), // unhandled response in last body expression ( "(restrict-assets? tx-sender ((with-stx u1000)) true (err u1))", - CheckErrors::UncheckedIntermediaryResponses, + CheckErrorKind::UncheckedIntermediaryResponses, ), // unhandled response in other body expression ( "(restrict-assets? tx-sender ((with-stx u1000)) (err u1) true)", - CheckErrors::UncheckedIntermediaryResponses, + CheckErrorKind::UncheckedIntermediaryResponses, ), // too many allowances ( @@ -153,7 +153,7 @@ fn test_restrict_assets(#[case] version: ClarityVersion, #[case] epoch: StacksEp .collect::>() .join(" ") ), - CheckErrors::TooManyAllowances(MAX_ALLOWANCES, 130), + CheckErrorKind::TooManyAllowances(MAX_ALLOWANCES, 130), ), // different error types thrown from body expressions ( @@ -164,7 +164,7 @@ fn test_restrict_assets(#[case] version: ClarityVersion, #[case] epoch: StacksEp u0 ) )", - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( TypeSignature::new_response(TypeSignature::NoType, TypeSignature::UIntType) .unwrap() .into(), @@ -179,7 +179,7 @@ fn test_restrict_assets(#[case] version: ClarityVersion, #[case] epoch: StacksEp if version < ClarityVersion::Clarity4 { // restrict-assets? is only available in Clarity 4+ assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -198,7 +198,7 @@ fn test_restrict_assets(#[case] version: ClarityVersion, #[case] epoch: StacksEp if version < ClarityVersion::Clarity4 { // restrict-assets? is only available in Clarity 4+ assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -252,67 +252,67 @@ fn test_as_contract(#[case] version: ClarityVersion, #[case] epoch: StacksEpochI // no allowances ( "(as-contract? true)", - CheckErrors::RequiresAtLeastArguments(2, 1), + CheckErrorKind::RequiresAtLeastArguments(2, 1), ), // allowance not in list ( "(as-contract? (with-stx u1) true)", - CheckErrors::ExpectedListApplication, + CheckErrorKind::ExpectedListApplication, ), // other value in place of allowance list ( "(as-contract? u1 true)", - CheckErrors::ExpectedListOfAllowances("as-contract?".into(), 1), + CheckErrorKind::ExpectedListOfAllowances("as-contract?".into(), 1), ), // non-allowance in allowance list ( "(as-contract? (u1) true)", - CheckErrors::ExpectedListApplication, + CheckErrorKind::ExpectedListApplication, ), // empty list in allowance list ( "(as-contract? (()) true)", - CheckErrors::NonFunctionApplication, + CheckErrorKind::NonFunctionApplication, ), // list with literal in allowance list ( "(as-contract? ((123)) true)", - CheckErrors::NonFunctionApplication, + CheckErrorKind::NonFunctionApplication, ), // non-allowance function in allowance list ( "(as-contract? ((foo)) true)", - CheckErrors::UnknownFunction("foo".into()), + CheckErrorKind::UnknownFunction("foo".into()), ), // no body expressions ( "(as-contract? ((with-stx u5000)))", - CheckErrors::RequiresAtLeastArguments(2, 1), + CheckErrorKind::RequiresAtLeastArguments(2, 1), ), // unhandled response in only body expression ( "(as-contract? ((with-stx u1000)) (err u1))", - CheckErrors::UncheckedIntermediaryResponses, + CheckErrorKind::UncheckedIntermediaryResponses, ), // unhandled response in last body expression ( "(as-contract? ((with-stx u1000)) true (err u1))", - CheckErrors::UncheckedIntermediaryResponses, + CheckErrorKind::UncheckedIntermediaryResponses, ), // unhandled response in other body expression ( "(as-contract? ((with-stx u1000)) (err u1) true)", - CheckErrors::UncheckedIntermediaryResponses, + CheckErrorKind::UncheckedIntermediaryResponses, ), // other allowances together with with-all-assets-unsafe (first) ( "(as-contract? ((with-all-assets-unsafe) (with-stx u1000)) true)", - CheckErrors::WithAllAllowanceNotAlone, + CheckErrorKind::WithAllAllowanceNotAlone, ), // other allowances together with with-all-assets-unsafe (second) ( "(as-contract? ((with-stx u1000) (with-all-assets-unsafe)) true)", - CheckErrors::WithAllAllowanceNotAlone, + CheckErrorKind::WithAllAllowanceNotAlone, ), // too many allowances ( @@ -322,7 +322,7 @@ fn test_as_contract(#[case] version: ClarityVersion, #[case] epoch: StacksEpochI .collect::>() .join(" ") ), - CheckErrors::TooManyAllowances(MAX_ALLOWANCES, 130), + CheckErrorKind::TooManyAllowances(MAX_ALLOWANCES, 130), ), // different error types thrown from body expressions ( @@ -333,7 +333,7 @@ fn test_as_contract(#[case] version: ClarityVersion, #[case] epoch: StacksEpochI u0 ) )", - CheckErrors::ReturnTypesMustMatch( + CheckErrorKind::ReturnTypesMustMatch( TypeSignature::new_response(TypeSignature::NoType, TypeSignature::UIntType) .unwrap() .into(), @@ -348,7 +348,7 @@ fn test_as_contract(#[case] version: ClarityVersion, #[case] epoch: StacksEpochI if version < ClarityVersion::Clarity4 { // as-contract? is only available in Clarity 4+ assert_eq!( - CheckErrors::UnknownFunction("as-contract?".to_string()), + CheckErrorKind::UnknownFunction("as-contract?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -367,7 +367,7 @@ fn test_as_contract(#[case] version: ClarityVersion, #[case] epoch: StacksEpochI if version < ClarityVersion::Clarity4 { // as-contract? is only available in Clarity 4+ assert_eq!( - CheckErrors::UnknownFunction("as-contract?".to_string()), + CheckErrorKind::UnknownFunction("as-contract?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -416,17 +416,17 @@ fn test_with_stx_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack // no arguments ( "(restrict-assets? tx-sender ((with-stx)) true)", - CheckErrors::IncorrectArgumentCount(1, 0), + CheckErrorKind::IncorrectArgumentCount(1, 0), ), // too many arguments ( "(restrict-assets? tx-sender ((with-stx u1000 u2000)) true)", - CheckErrors::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 2), ), // wrong type - string instead of uint ( r#"(restrict-assets? tx-sender ((with-stx "1000")) true)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::UIntType.into(), TypeSignature::new_ascii_type_checked(4).into(), ), @@ -434,7 +434,7 @@ fn test_with_stx_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack // wrong type - int instead of uint ( "(restrict-assets? tx-sender ((with-stx 1000)) true)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::UIntType.into(), TypeSignature::IntType.into(), ), @@ -444,7 +444,7 @@ fn test_with_stx_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack for (code, expected_type) in &good { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -462,7 +462,7 @@ fn test_with_stx_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack for (code, expected_err) in &bad { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -526,27 +526,27 @@ fn test_with_ft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stacks // no arguments ( "(restrict-assets? tx-sender ((with-ft)) true)", - CheckErrors::IncorrectArgumentCount(3, 0), + CheckErrorKind::IncorrectArgumentCount(3, 0), ), // one argument ( "(restrict-assets? tx-sender ((with-ft .token)) true)", - CheckErrors::IncorrectArgumentCount(3, 1), + CheckErrorKind::IncorrectArgumentCount(3, 1), ), // two arguments ( r#"(restrict-assets? tx-sender ((with-ft .token "token-name")) true)"#, - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::IncorrectArgumentCount(3, 2), ), // too many arguments ( r#"(restrict-assets? tx-sender ((with-ft .token "token-name" u1000 u2000)) true)"#, - CheckErrors::IncorrectArgumentCount(3, 4), + CheckErrorKind::IncorrectArgumentCount(3, 4), ), // wrong type for contract-id - uint instead of principal ( r#"(restrict-assets? tx-sender ((with-ft u123 "token-name" u1000)) true)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::PrincipalType.into(), TypeSignature::UIntType.into(), ), @@ -554,7 +554,7 @@ fn test_with_ft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stacks // wrong type for token-name - uint instead of string ( "(restrict-assets? tx-sender ((with-ft .token u123 u1000)) true)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::new_ascii_type_checked(MAX_STRING_LEN as u32).into(), TypeSignature::UIntType.into(), ), @@ -562,7 +562,7 @@ fn test_with_ft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stacks // wrong type for amount - string instead of uint ( r#"(restrict-assets? tx-sender ((with-ft .token "token-name" "1000")) true)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::UIntType.into(), TypeSignature::new_ascii_type_checked(4).into(), ), @@ -570,7 +570,7 @@ fn test_with_ft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stacks // wrong type for amount - int instead of uint ( r#"(restrict-assets? tx-sender ((with-ft .token "token-name" 1000)) true)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::UIntType.into(), TypeSignature::IntType.into(), ), @@ -578,7 +578,7 @@ fn test_with_ft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stacks // too long token name (longer than 128 chars) ( "(restrict-assets? tx-sender ((with-ft .token \"this-token-name-is-way-too-long-to-be-valid-because-it-has-more-than-one-hundred-and-twenty-eight-characters-in-it-so-it-is-not-a-valid-token-name\" u1000)) true)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::new_ascii_type_checked(MAX_STRING_LEN as u32).into(), TypeSignature::new_ascii_type_checked(146u32).into(), ), @@ -588,7 +588,7 @@ fn test_with_ft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stacks for (code, expected_type) in &good { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -606,7 +606,7 @@ fn test_with_ft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stacks for (code, expected_err) in &bad { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -680,27 +680,27 @@ fn test_with_nft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack // no arguments ( "(restrict-assets? tx-sender ((with-nft)) true)", - CheckErrors::IncorrectArgumentCount(3, 0), + CheckErrorKind::IncorrectArgumentCount(3, 0), ), // one argument ( "(restrict-assets? tx-sender ((with-nft .token)) true)", - CheckErrors::IncorrectArgumentCount(3, 1), + CheckErrorKind::IncorrectArgumentCount(3, 1), ), // two arguments ( r#"(restrict-assets? tx-sender ((with-nft .token "token-name")) true)"#, - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::IncorrectArgumentCount(3, 2), ), // too many arguments ( r#"(restrict-assets? tx-sender ((with-nft .token "token-name" (list u123) (list u456))) true)"#, - CheckErrors::IncorrectArgumentCount(3, 4), + CheckErrorKind::IncorrectArgumentCount(3, 4), ), // wrong type for contract-id - uint instead of principal ( r#"(restrict-assets? tx-sender ((with-nft u123 "token-name" (list u456))) true)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::PrincipalType.into(), TypeSignature::UIntType.into(), ), @@ -708,7 +708,7 @@ fn test_with_nft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack // wrong type for token-name - uint instead of string ( "(restrict-assets? tx-sender ((with-nft .token u123 (list u456))) true)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::new_ascii_type_checked(MAX_STRING_LEN as u32).into(), TypeSignature::UIntType.into(), ), @@ -716,7 +716,7 @@ fn test_with_nft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack // too long token name (longer than 128 chars) ( "(restrict-assets? tx-sender ((with-ft .token \"this-token-name-is-way-too-long-to-be-valid-because-it-has-more-than-one-hundred-and-twenty-eight-characters-in-it-so-it-is-not-a-valid-token-name\" u1000)) true)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::new_ascii_type_checked(MAX_STRING_LEN as u32).into(), TypeSignature::new_ascii_type_checked(146u32).into(), ), @@ -729,14 +729,14 @@ fn test_with_nft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack .collect::>() .join(" ") ), - CheckErrors::MaxIdentifierLengthExceeded(MAX_NFT_IDENTIFIERS, 130), + CheckErrorKind::MaxIdentifierLengthExceeded(MAX_NFT_IDENTIFIERS, 130), ), ]; for (code, expected_type) in &good { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -754,7 +754,7 @@ fn test_with_nft_allowance(#[case] version: ClarityVersion, #[case] epoch: Stack for (code, expected_err) in &bad { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -798,17 +798,17 @@ fn test_with_stacking_allowance(#[case] version: ClarityVersion, #[case] epoch: // no arguments ( "(restrict-assets? tx-sender ((with-stacking)) true)", - CheckErrors::IncorrectArgumentCount(1, 0), + CheckErrorKind::IncorrectArgumentCount(1, 0), ), // too many arguments ( "(restrict-assets? tx-sender ((with-stacking u1000 u2000)) true)", - CheckErrors::IncorrectArgumentCount(1, 2), + CheckErrorKind::IncorrectArgumentCount(1, 2), ), // wrong type - string instead of uint ( r#"(restrict-assets? tx-sender ((with-stacking "1000")) true)"#, - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::UIntType.into(), TypeSignature::new_ascii_type_checked(4).into(), ), @@ -816,7 +816,7 @@ fn test_with_stacking_allowance(#[case] version: ClarityVersion, #[case] epoch: // wrong type - int instead of uint ( "(restrict-assets? tx-sender ((with-stacking 1000)) true)", - CheckErrors::TypeError( + CheckErrorKind::TypeError( TypeSignature::UIntType.into(), TypeSignature::IntType.into(), ), @@ -826,7 +826,7 @@ fn test_with_stacking_allowance(#[case] version: ClarityVersion, #[case] epoch: for (code, expected_type) in &good { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -844,7 +844,7 @@ fn test_with_stacking_allowance(#[case] version: ClarityVersion, #[case] epoch: for (code, expected_err) in &bad { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -881,19 +881,19 @@ fn test_with_all_assets_unsafe_allowance( // with-all-assets-unsafe in restrict-assets? (not allowed) ( "(restrict-assets? tx-sender ((with-all-assets-unsafe)) true)", - CheckErrors::WithAllAllowanceNotAllowed, + CheckErrorKind::WithAllAllowanceNotAllowed, ), // with-all-assets-unsafe with arguments (should take 0) ( "(restrict-assets? tx-sender ((with-all-assets-unsafe u123)) true)", - CheckErrors::IncorrectArgumentCount(0, 1), + CheckErrorKind::IncorrectArgumentCount(0, 1), ), ]; for (code, expected_type) in &good { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("as-contract?".to_string()), + CheckErrorKind::UnknownFunction("as-contract?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, @@ -911,7 +911,7 @@ fn test_with_all_assets_unsafe_allowance( for (code, expected_err) in &bad { if version < ClarityVersion::Clarity4 { assert_eq!( - CheckErrors::UnknownFunction("restrict-assets?".to_string()), + CheckErrorKind::UnknownFunction("restrict-assets?".to_string()), *type_check_helper_version(code, version, epoch) .unwrap_err() .err, diff --git a/clarity/src/vm/analysis/types.rs b/clarity/src/vm/analysis/types.rs index 145ce59bd3c..1be8f15918e 100644 --- a/clarity/src/vm/analysis/types.rs +++ b/clarity/src/vm/analysis/types.rs @@ -22,7 +22,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::analysis::analysis_db::AnalysisDatabase; use crate::vm::analysis::contract_interface_builder::ContractInterface; -use crate::vm::analysis::errors::{CheckError, CheckErrors}; +use crate::vm::analysis::errors::{CheckErrorKind, StaticCheckError}; use crate::vm::analysis::type_checker::contexts::TypeMap; use crate::vm::costs::LimitedCostTracker; use crate::vm::types::signatures::FunctionSignature; @@ -39,7 +39,7 @@ pub trait AnalysisPass { epoch: &StacksEpochId, contract_analysis: &mut ContractAnalysis, analysis_db: &mut AnalysisDatabase, - ) -> Result<(), CheckError>; + ) -> Result<(), StaticCheckError>; } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] @@ -230,7 +230,7 @@ impl ContractAnalysis { epoch: &StacksEpochId, trait_identifier: &TraitIdentifier, trait_definition: &BTreeMap, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { let trait_name = trait_identifier.name.to_string(); for (func_name, expected_sig) in trait_definition.iter() { @@ -242,7 +242,7 @@ impl ContractAnalysis { | (None, Some(FunctionType::Fixed(func))) => { let args_sig = func.args.iter().map(|a| a.signature.clone()).collect(); if !expected_sig.check_args_trait_compliance(epoch, args_sig)? { - return Err(CheckErrors::BadTraitImplementation( + return Err(CheckErrorKind::BadTraitImplementation( trait_name, func_name.to_string(), ) @@ -250,7 +250,7 @@ impl ContractAnalysis { } if !expected_sig.returns.admits_type(epoch, &func.returns)? { - return Err(CheckErrors::BadTraitImplementation( + return Err(CheckErrorKind::BadTraitImplementation( trait_name, func_name.to_string(), ) @@ -258,7 +258,7 @@ impl ContractAnalysis { } } (_, _) => { - return Err(CheckErrors::BadTraitImplementation( + return Err(CheckErrorKind::BadTraitImplementation( trait_name, func_name.to_string(), ) diff --git a/clarity/src/vm/ast/definition_sorter/mod.rs b/clarity/src/vm/ast/definition_sorter/mod.rs index bc12151af1b..a684d68e9cd 100644 --- a/clarity/src/vm/ast/definition_sorter/mod.rs +++ b/clarity/src/vm/ast/definition_sorter/mod.rs @@ -18,7 +18,7 @@ use std::collections::{HashMap, HashSet}; use clarity_types::representations::ClarityName; -use crate::vm::ast::errors::{ParseError, ParseErrors, ParseResult}; +use crate::vm::ast::errors::{ParseError, ParseErrorKind, ParseResult}; use crate::vm::ast::types::ContractAST; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{runtime_cost, CostTracker}; @@ -90,7 +90,7 @@ impl DefinitionSorter { let sorted_indexes = walker.get_sorted_dependencies(&self.graph); if let Some(deps) = walker.get_cycling_dependencies(&self.graph, &sorted_indexes) { - let functions_names = deps + let mut function_names = deps .into_iter() .filter_map(|i| { let exp = &contract_ast.pre_expressions[i]; @@ -99,7 +99,10 @@ impl DefinitionSorter { .map(|i| i.0.to_string()) .collect::>(); - let error = ParseError::new(ParseErrors::CircularReference(functions_names)); + // Sorting function names to make the error contents deterministic + function_names.sort(); + + let error = ParseError::new(ParseErrorKind::CircularReference(function_names)); return Err(error); } @@ -421,7 +424,7 @@ impl Graph { let list = self .adjacency_list .get_mut(src_expr_index) - .ok_or(ParseErrors::InterpreterFailure)?; + .ok_or(ParseErrorKind::InterpreterFailure)?; list.push(dst_expr_index); Ok(()) } @@ -443,7 +446,7 @@ impl Graph { for node in self.adjacency_list.iter() { total = total .checked_add(node.len() as u64) - .ok_or(ParseErrors::CostOverflow)?; + .ok_or(ParseErrorKind::CostOverflow)?; } Ok(total) } diff --git a/clarity/src/vm/ast/definition_sorter/tests.rs b/clarity/src/vm/ast/definition_sorter/tests.rs index 9bbb3211781..c05611c3b20 100644 --- a/clarity/src/vm/ast/definition_sorter/tests.rs +++ b/clarity/src/vm/ast/definition_sorter/tests.rs @@ -21,7 +21,7 @@ use rstest_reuse::{self, *}; use crate::vm::analysis::type_checker::v2_1::tests::mem_type_check as run_analysis_helper; use crate::vm::ast::definition_sorter::DefinitionSorter; -use crate::vm::ast::errors::{ParseErrors, ParseResult}; +use crate::vm::ast::errors::{ParseErrorKind, ParseResult}; use crate::vm::ast::expression_identifier::ExpressionIdentifier; use crate::vm::ast::parser; use crate::vm::ast::types::ContractAST; @@ -96,7 +96,7 @@ fn should_raise_dependency_cycle_case_1(#[case] version: ClarityVersion) { "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] @@ -109,7 +109,7 @@ fn should_raise_dependency_cycle_case_2(#[case] version: ClarityVersion) { "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] @@ -131,7 +131,7 @@ fn should_raise_dependency_cycle_case_let(#[case] version: ClarityVersion) { "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] @@ -153,7 +153,7 @@ fn should_raise_dependency_cycle_case_get(#[case] version: ClarityVersion) { "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] @@ -177,7 +177,7 @@ fn should_raise_dependency_cycle_case_fetch_entry(#[case] version: ClarityVersio "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] @@ -201,7 +201,7 @@ fn should_raise_dependency_cycle_case_delete_entry(#[case] version: ClarityVersi "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] @@ -225,7 +225,7 @@ fn should_raise_dependency_cycle_case_set_entry(#[case] version: ClarityVersion) "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] @@ -249,7 +249,7 @@ fn should_raise_dependency_cycle_case_insert_entry(#[case] version: ClarityVersi "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] @@ -260,7 +260,7 @@ fn should_raise_dependency_cycle_case_fetch_contract_entry(#[case] version: Clar "#; let err = run_scoped_parsing_helper(contract, version).unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[apply(test_clarity_versions_definition_sorter)] diff --git a/clarity/src/vm/ast/errors.rs b/clarity/src/vm/ast/errors.rs index 2b9b5beb3c5..897d4fed24e 100644 --- a/clarity/src/vm/ast/errors.rs +++ b/clarity/src/vm/ast/errors.rs @@ -14,4 +14,4 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -pub use clarity_types::errors::ast::{ParseError, ParseErrors, ParseResult, PlacedError}; +pub use clarity_types::errors::ast::{ParseError, ParseErrorKind, ParseResult, PlacedError}; diff --git a/clarity/src/vm/ast/expression_identifier/mod.rs b/clarity/src/vm/ast/expression_identifier/mod.rs index 13b9aac2bd1..d73d99dc242 100644 --- a/clarity/src/vm/ast/expression_identifier/mod.rs +++ b/clarity/src/vm/ast/expression_identifier/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::vm::ast::errors::{ParseError, ParseErrors, ParseResult}; +use crate::vm::ast::errors::{ParseError, ParseErrorKind, ParseResult}; use crate::vm::ast::types::ContractAST; use crate::vm::representations::SymbolicExpressionCommon; use crate::vm::ClarityVersion; @@ -22,7 +22,7 @@ use crate::vm::ClarityVersion; fn inner_relabel(args: &mut [T], index: u64) -> ParseResult { let mut current = index .checked_add(1) - .ok_or(ParseError::new(ParseErrors::TooManyExpressions))?; + .ok_or(ParseError::new(ParseErrorKind::TooManyExpressions))?; for expression in &mut args[..] { expression.set_id(current); current = if let Some(exprs) = expression.match_list_mut() { @@ -30,7 +30,7 @@ fn inner_relabel(args: &mut [T], index: u64) -> Par } else { current .checked_add(1) - .ok_or(ParseError::new(ParseErrors::TooManyExpressions)) + .ok_or(ParseError::new(ParseErrorKind::TooManyExpressions)) }?; } Ok(current) diff --git a/clarity/src/vm/ast/mod.rs b/clarity/src/vm/ast/mod.rs index da65d20521b..b09de172e6d 100644 --- a/clarity/src/vm/ast/mod.rs +++ b/clarity/src/vm/ast/mod.rs @@ -49,7 +49,8 @@ pub fn parse( source_code: &str, version: ClarityVersion, epoch: StacksEpochId, -) -> Result, crate::vm::errors::Error> { +) -> Result, crate::vm::errors::VmExecutionError> +{ let ast = build_ast(contract_identifier, source_code, &mut (), version, epoch)?; Ok(ast.expressions) } @@ -237,10 +238,11 @@ pub fn build_ast( mod test { use std::collections::HashMap; + use clarity_types::types::MAX_VALUE_SIZE; use stacks_common::types::StacksEpochId; use crate::vm::ast::build_ast; - use crate::vm::ast::errors::ParseErrors; + use crate::vm::ast::errors::ParseErrorKind; use crate::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; use crate::vm::costs::{LimitedCostTracker, *}; use crate::vm::representations::depth_traverse; @@ -320,7 +322,7 @@ mod test { ) .expect_err("Contract should error in parsing"); - let expected_err = ParseErrors::VaryExpressionStackDepthTooDeep; + let expected_err = ParseErrorKind::VaryExpressionStackDepthTooDeep; let expected_list_cost_state = UnitTestTracker { invoked_functions: vec![(ClarityCostFunction::AstParse, vec![500])], invocation_count: 1, @@ -340,7 +342,7 @@ mod test { ) .expect_err("Contract should error in parsing"); - let expected_err = ParseErrors::VaryExpressionStackDepthTooDeep; + let expected_err = ParseErrorKind::VaryExpressionStackDepthTooDeep; let expected_list_cost_state = UnitTestTracker { invoked_functions: vec![(ClarityCostFunction::AstParse, vec![571])], invocation_count: 1, @@ -382,7 +384,7 @@ mod test { ) .expect_err("Contract should error in parsing"); - let expected_err = ParseErrors::ExpressionStackDepthTooDeep; + let expected_err = ParseErrorKind::ExpressionStackDepthTooDeep; let expected_list_cost_state = UnitTestTracker { invoked_functions: vec![(ClarityCostFunction::AstParse, vec![500])], invocation_count: 1, @@ -402,7 +404,7 @@ mod test { ) .expect_err("Contract should error in parsing"); - let expected_err = ParseErrors::ExpressionStackDepthTooDeep; + let expected_err = ParseErrorKind::ExpressionStackDepthTooDeep; let expected_list_cost_state = UnitTestTracker { invoked_functions: vec![(ClarityCostFunction::AstParse, vec![571])], invocation_count: 1, @@ -446,4 +448,141 @@ mod test { } } } + + #[test] + fn test_build_ast_error_exceeding_cost_balance_due_to_ast_parse() { + let limit = ExecutionCost { + read_count: u64::MAX, + write_count: u64::MAX, + read_length: u64::MAX, + write_length: u64::MAX, + runtime: 1, + }; + let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::Epoch33, limit); + + let err = build_ast( + &QualifiedContractIdentifier::transient(), + "(define-constant my-const u1)", + &mut tracker, + ClarityVersion::Clarity4, + StacksEpochId::Epoch33, + ) + .unwrap_err(); + + assert!( + matches!(*err.err, ParseErrorKind::CostBalanceExceeded(_, _)), + "Instead found: {err}" + ); + } + + #[test] + fn test_build_ast_error_exceeding_cost_balance_due_to_ast_cycle_detection_with_0_edges() { + let expected_ast_parse_cost = 1215; + let expected_cycle_det_cost = 72; + let expected_total = expected_ast_parse_cost + expected_cycle_det_cost; + + let limit = ExecutionCost { + read_count: u64::MAX, + write_count: u64::MAX, + read_length: u64::MAX, + write_length: u64::MAX, + runtime: expected_ast_parse_cost, + }; + let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::Epoch33, 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, + ) + .expect_err("Expected parse error, but found success!"); + + let total = match *err.err { + ParseErrorKind::CostBalanceExceeded(total, _) => total, + _ => panic!("Expected CostBalanceExceeded, but found: {err}"), + }; + + assert_eq!(expected_total, total.runtime); + } + + #[test] + fn test_build_ast_error_exceeding_cost_balance_due_to_ast_cycle_detection_with_1_edge() { + let expected_ast_parse_cost = 1215; + let expected_cycle_det_cost = 213; + let expected_total = expected_ast_parse_cost + expected_cycle_det_cost; + + let limit = ExecutionCost { + read_count: u64::MAX, + write_count: u64::MAX, + read_length: u64::MAX, + write_length: u64::MAX, + runtime: expected_ast_parse_cost, + }; + let mut tracker = LimitedCostTracker::new_with_limit(StacksEpochId::Epoch33, 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, + ) + .expect_err("Expected parse error, but found success!"); + + let total = match *err.err { + ParseErrorKind::CostBalanceExceeded(total, _) => total, + _ => panic!("Expected CostBalanceExceeded, but found: {err}"), + }; + + assert_eq!(expected_total, total.runtime); + } + + #[test] + fn test_build_ast_error_vary_stack_too_deep() { + // This contract pass the parse v2 MAX_NESTING_DEPTH but fails the [`VaryStackDepthChecker`] + let contract = { + let count = AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64) - 1; + let body_start = "(list ".repeat(count as usize); + let body_end = ")".repeat(count as usize); + format!("{{ a: {body_start}u1 {body_end} }}") + }; + + let err = build_ast( + &QualifiedContractIdentifier::transient(), + &contract, + &mut (), + ClarityVersion::Clarity4, + StacksEpochId::Epoch33, + ) + .expect_err("Expected parse error, but found success!"); + + assert!( + matches!(*err.err, ParseErrorKind::VaryExpressionStackDepthTooDeep), + "Instead found: {err}" + ); + } + + #[test] + fn test_build_ast_error_illegal_ascii_string_due_to_size() { + let contract = { + let string = "a".repeat(MAX_VALUE_SIZE as usize + 1); + format!("(define-constant my-str \"{string}\")") + }; + + let err = build_ast( + &QualifiedContractIdentifier::transient(), + &contract, + &mut (), + ClarityVersion::Clarity4, + StacksEpochId::Epoch33, + ) + .expect_err("Expected parse error, but found success!"); + + assert!( + matches!(*err.err, ParseErrorKind::IllegalASCIIString(_)), + "Instead found: {err}" + ); + } } diff --git a/clarity/src/vm/ast/parser/v1.rs b/clarity/src/vm/ast/parser/v1.rs index feb59798956..98fe7028724 100644 --- a/clarity/src/vm/ast/parser/v1.rs +++ b/clarity/src/vm/ast/parser/v1.rs @@ -18,7 +18,7 @@ use lazy_static::lazy_static; use regex::{Captures, Regex}; use stacks_common::util::hash::hex_bytes; -use crate::vm::ast::errors::{ParseError, ParseErrors, ParseResult}; +use crate::vm::ast::errors::{ParseError, ParseErrorKind, ParseResult}; use crate::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; use crate::vm::representations::{ ClarityName, ContractName, PreSymbolicExpression, MAX_STRING_LEN, @@ -98,7 +98,7 @@ impl LexMatcher { fn get_value_or_err(input: &str, captures: Captures) -> ParseResult { let matched = captures .name("value") - .ok_or(ParseError::new(ParseErrors::FailedCapturingInput))?; + .ok_or(ParseError::new(ParseErrorKind::FailedCapturingInput))?; Ok(input[matched.start()..matched.end()].to_string()) } @@ -207,7 +207,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult ParseResult ParseResult Ok(()), TokenType::Comma => Ok(()), TokenType::Colon => Ok(()), - _ => Err(ParseError::new(ParseErrors::SeparatorExpected( + _ => Err(ParseError::new(ParseErrorKind::SeparatorExpected( current_slice[..whole_match.end()].to_string(), ))), } @@ -244,9 +244,11 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Ok(()), TokenType::Comma => Ok(()), TokenType::Colon => Ok(()), - _ => Err(ParseError::new(ParseErrors::SeparatorExpectedAfterColon( - current_slice[..whole_match.end()].to_string(), - ))), + _ => Err(ParseError::new( + ParseErrorKind::SeparatorExpectedAfterColon( + current_slice[..whole_match.end()].to_string(), + ), + )), } } }?; @@ -260,7 +262,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult max_nesting { return Err(ParseError::new( - ParseErrors::VaryExpressionStackDepthTooDeep, + ParseErrorKind::VaryExpressionStackDepthTooDeep, )); } Ok(LexItem::LeftParen) @@ -289,7 +291,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult max_nesting { return Err(ParseError::new( - ParseErrors::VaryExpressionStackDepthTooDeep, + ParseErrorKind::VaryExpressionStackDepthTooDeep, )); } Ok(LexItem::LeftCurly) @@ -302,7 +304,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult { let value = get_value_or_err(current_slice, captures)?; if value.contains('#') { - Err(ParseError::new(ParseErrors::IllegalVariableName(value))) + Err(ParseError::new(ParseErrorKind::IllegalVariableName(value))) } else { Ok(LexItem::Variable(value)) } @@ -311,7 +313,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult() { Ok(parsed) => Ok(Value::UInt(parsed)), - Err(_e) => Err(ParseError::new(ParseErrors::FailedParsingIntValue( + Err(_e) => Err(ParseError::new(ParseErrorKind::FailedParsingIntValue( str_value.clone(), ))), }?; @@ -321,7 +323,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult() { Ok(parsed) => Ok(Value::Int(parsed)), - Err(_e) => Err(ParseError::new(ParseErrors::FailedParsingIntValue( + Err(_e) => Err(ParseError::new(ParseErrorKind::FailedParsingIntValue( str_value.clone(), ))), }?; @@ -333,7 +335,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Ok(Value::Principal(parsed)), Err(_e) => Err(ParseError::new( - ParseErrors::FailedParsingPrincipal(str_value.clone()), + ParseErrorKind::FailedParsingPrincipal(str_value.clone()), )), }?; Ok(LexItem::LiteralValue(str_value.len(), value)) @@ -342,9 +344,9 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Ok(parsed), - Err(_e) => Err(ParseError::new(ParseErrors::FailedParsingPrincipal( - str_value.clone(), - ))), + Err(_e) => Err(ParseError::new( + ParseErrorKind::FailedParsingPrincipal(str_value.clone()), + )), }?; Ok(LexItem::SugaredContractIdentifier(str_value.len(), value)) } @@ -352,7 +354,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Ok(parsed), - Err(_e) => Err(ParseError::new(ParseErrors::FailedParsingField( + Err(_e) => Err(ParseError::new(ParseErrorKind::FailedParsingField( str_value.clone(), ))), }?; @@ -363,9 +365,9 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Ok((contract_name, field_name)), - Err(_e) => Err(ParseError::new(ParseErrors::FailedParsingField( - str_value.clone(), - ))), + Err(_e) => Err(ParseError::new( + ParseErrorKind::FailedParsingField(str_value.clone()), + )), }?; Ok(LexItem::SugaredFieldIdentifier( str_value.len(), @@ -377,30 +379,32 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Ok(Value::Principal(PrincipalData::Standard(parsed))), - Err(_e) => Err(ParseError::new(ParseErrors::FailedParsingPrincipal( - str_value.clone(), - ))), + Err(_e) => Err(ParseError::new( + ParseErrorKind::FailedParsingPrincipal(str_value.clone()), + )), }?; Ok(LexItem::LiteralValue(str_value.len(), value)) } TokenType::TraitReferenceLiteral => { let str_value = get_value_or_err(current_slice, captures)?; let data = str_value.clone().try_into().map_err(|_| { - ParseError::new(ParseErrors::IllegalVariableName(str_value.to_string())) + ParseError::new(ParseErrorKind::IllegalVariableName( + str_value.to_string(), + )) })?; Ok(LexItem::TraitReference(str_value.len(), data)) } TokenType::HexStringLiteral => { let str_value = get_value_or_err(current_slice, captures)?; let byte_vec = hex_bytes(&str_value).map_err(|x| { - ParseError::new(ParseErrors::FailedParsingHexValue( + ParseError::new(ParseErrorKind::FailedParsingHexValue( str_value.clone(), x.to_string(), )) })?; let value = match Value::buff_from(byte_vec) { Ok(parsed) => Ok(parsed), - Err(_e) => Err(ParseError::new(ParseErrors::FailedParsingBuffer( + Err(_e) => Err(ParseError::new(ParseErrorKind::FailedParsingBuffer( str_value.clone(), ))), }?; @@ -414,7 +418,9 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Ok(parsed), - Err(_e) => Err(ParseError::new(ParseErrors::InvalidCharactersDetected)), + Err(_e) => { + Err(ParseError::new(ParseErrorKind::InvalidCharactersDetected)) + } }?; Ok(LexItem::LiteralValue(str_value_len, value)) } @@ -426,7 +432,9 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Ok(parsed), - Err(_e) => Err(ParseError::new(ParseErrors::InvalidCharactersDetected)), + Err(_e) => { + Err(ParseError::new(ParseErrorKind::InvalidCharactersDetected)) + } }?; Ok(LexItem::LiteralValue(str_value_len, value)) } @@ -443,7 +451,7 @@ fn inner_lex(input: &str, max_nesting: u64) -> ParseResult Pars 'r' => unescaped_str.push('\r'), '0' => unescaped_str.push('\0'), 'u' if allow_unicode_escape => unescaped_str.push_str("\\u"), - _ => return Err(ParseError::new(ParseErrors::InvalidEscaping)), + _ => return Err(ParseError::new(ParseErrorKind::InvalidEscaping)), } } else { - return Err(ParseError::new(ParseErrors::InvalidEscaping)); + return Err(ParseError::new(ParseErrorKind::InvalidEscaping)); } } else { unescaped_str.push(char); @@ -525,12 +533,12 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult Ok(e), - ParseStackItem::Colon => { - Err(ParseError::new(ParseErrors::ColonSeparatorUnexpected)) - } - ParseStackItem::Comma => { - Err(ParseError::new(ParseErrors::CommaSeparatorUnexpected)) - } + ParseStackItem::Colon => Err(ParseError::new( + ParseErrorKind::ColonSeparatorUnexpected, + )), + ParseStackItem::Comma => Err(ParseError::new( + ParseErrorKind::CommaSeparatorUnexpected, + )), }) .collect(); let checked_list = checked_list?; @@ -540,7 +548,7 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult { let mut error = - ParseError::new(ParseErrors::ClosingTupleLiteralExpected); + ParseError::new(ParseErrorKind::ClosingTupleLiteralExpected); error.diagnostic.add_span( start_line, start_column, @@ -552,7 +560,9 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult { @@ -574,21 +584,21 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult { if let ParseStackItem::Colon = item { Ok(()) } else { - Err(ParseErrors::TupleColonExpected(index)) + Err(ParseErrorKind::TupleColonExpected(index)) } } 3 => { if let ParseStackItem::Comma = item { Ok(()) } else { - Err(ParseErrors::TupleCommaExpected(index)) + Err(ParseErrorKind::TupleCommaExpected(index)) } } _ => unreachable!("More than four modulos of four."), @@ -600,7 +610,7 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult { let mut error = - ParseError::new(ParseErrors::ClosingParenthesisExpected); + ParseError::new(ParseErrorKind::ClosingParenthesisExpected); error.diagnostic.add_span( start_line, start_column, @@ -612,13 +622,15 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult { let end_column = column_pos + (value.len() as u32) - 1; let value = value.clone().try_into().map_err(|_| { - ParseError::new(ParseErrors::IllegalVariableName(value.to_string())) + ParseError::new(ParseErrorKind::IllegalVariableName(value.to_string())) })?; let mut pre_expr = PreSymbolicExpression::atom(value); pre_expr.set_span(line_pos, column_pos, line_pos, end_column); @@ -673,7 +685,7 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult { match parse_stack.last_mut() { - None => return Err(ParseError::new(ParseErrors::ColonSeparatorUnexpected)), + None => return Err(ParseError::new(ParseErrorKind::ColonSeparatorUnexpected)), Some((ref mut list, ..)) => { list.push(ParseStackItem::Colon); } @@ -681,7 +693,7 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult { match parse_stack.last_mut() { - None => return Err(ParseError::new(ParseErrors::CommaSeparatorUnexpected)), + None => return Err(ParseError::new(ParseErrorKind::CommaSeparatorUnexpected)), Some((ref mut list, ..)) => { list.push(ParseStackItem::Comma); } @@ -693,7 +705,7 @@ pub fn parse_lexed(input: Vec<(LexItem, u32, u32)>) -> ParseResult ParseResult Parser<'a> { - pub fn new(input: &'a str, fail_fast: bool) -> Result { + pub fn new(input: &'a str, fail_fast: bool) -> Result { let lexer = match Lexer::new(input, fail_fast) { Ok(lexer) => lexer, - Err(e) => return Err(ParseErrors::Lexer(e)), + Err(e) => return Err(ParseErrorKind::Lexer(e)), }; let mut p = Self { lexer, @@ -89,7 +89,7 @@ impl<'a> Parser<'a> { "Parser::read_token should not return an error when not in fail_fast mode" ); p.success = false; - return Err(ParseErrors::Lexer(e)); + return Err(ParseErrorKind::Lexer(e)); } }; if token.token == Token::Eof { @@ -103,7 +103,7 @@ impl<'a> Parser<'a> { .diagnostics .iter() .map(|lex_error| PlacedError { - e: ParseErrors::Lexer(lex_error.e.clone()), + e: ParseErrorKind::Lexer(lex_error.e.clone()), span: lex_error.span.clone(), }) .collect(); @@ -111,7 +111,7 @@ impl<'a> Parser<'a> { Ok(p) } - fn add_diagnostic(&mut self, e: ParseErrors, span: Span) -> ParseResult<()> { + fn add_diagnostic(&mut self, e: ParseErrorKind, span: Span) -> ParseResult<()> { if self.fail_fast { return Err(ParseError::new(e)); } else { @@ -152,11 +152,11 @@ impl<'a> Parser<'a> { /// raises an UnexpectedParserFailure. fn peek_last_token(&self) -> ParseResult<&PlacedToken> { if self.next_token == 0 { - return Err(ParseError::new(ParseErrors::UnexpectedParserFailure)); + return Err(ParseError::new(ParseErrorKind::UnexpectedParserFailure)); } self.tokens .get(self.next_token - 1) - .ok_or_else(|| ParseError::new(ParseErrors::UnexpectedParserFailure)) + .ok_or_else(|| ParseError::new(ParseErrorKind::UnexpectedParserFailure)) } fn skip_to_end(&mut self) { @@ -222,7 +222,10 @@ impl<'a> Parser<'a> { } => { if let Some(node) = node_opt { if !*whitespace && node.match_comment().is_none() { - self.add_diagnostic(ParseErrors::ExpectedWhitespace, node.span().clone())?; + self.add_diagnostic( + ParseErrorKind::ExpectedWhitespace, + node.span().clone(), + )?; } nodes.push(node); *whitespace = self.ignore_whitespace(); @@ -241,11 +244,11 @@ impl<'a> Parser<'a> { Token::Eof => { // Report an error, but return the list and attempt to continue parsing self.add_diagnostic( - ParseErrors::ExpectedClosing(Token::Rparen), + ParseErrorKind::ExpectedClosing(Token::Rparen), token.span.clone(), )?; self.add_diagnostic( - ParseErrors::NoteToMatchThis(Token::Lparen), + ParseErrorKind::NoteToMatchThis(Token::Lparen), span.clone(), )?; span.end_line = token.span.end_line; @@ -258,7 +261,7 @@ impl<'a> Parser<'a> { _ => { // Report an error, then skip this token self.add_diagnostic( - ParseErrors::UnexpectedToken(token.token.clone()), + ParseErrorKind::UnexpectedToken(token.token.clone()), token.span, )?; *whitespace = self.ignore_whitespace(); @@ -293,11 +296,11 @@ impl<'a> Parser<'a> { match last_token.token { Token::Eof => { self.add_diagnostic( - ParseErrors::ExpectedClosing(Token::Rbrace), + ParseErrorKind::ExpectedClosing(Token::Rbrace), open_tuple.diagnostic_token.span.clone(), )?; self.add_diagnostic( - ParseErrors::NoteToMatchThis(Token::Lbrace), + ParseErrorKind::NoteToMatchThis(Token::Lbrace), open_tuple.span.clone(), )?; let out_nodes: Vec<_> = open_tuple.nodes.drain(..).collect(); @@ -311,7 +314,7 @@ impl<'a> Parser<'a> { _ => { // Report an error, then skip this token self.add_diagnostic( - ParseErrors::UnexpectedToken(last_token.token), + ParseErrorKind::UnexpectedToken(last_token.token), last_token.span, )?; return Ok(None); // Ok(None) yields to the parse loop @@ -335,7 +338,10 @@ impl<'a> Parser<'a> { // This indicates we have reached the end of the input. // Create a placeholder value so that parsing can continue, // then return. - self.add_diagnostic(ParseErrors::TupleColonExpectedv2, token.span.clone())?; + self.add_diagnostic( + ParseErrorKind::TupleColonExpectedv2, + token.span.clone(), + )?; let mut placeholder = PreSymbolicExpression::placeholder("".to_string()); placeholder.copy_span(&token.span); open_tuple.nodes.push(placeholder); // Placeholder value @@ -349,7 +355,10 @@ impl<'a> Parser<'a> { } _ => { // Record an error, then continue to parse - self.add_diagnostic(ParseErrors::TupleColonExpectedv2, token.span.clone())?; + self.add_diagnostic( + ParseErrorKind::TupleColonExpectedv2, + token.span.clone(), + )?; } } open_tuple.diagnostic_token = token; @@ -377,7 +386,7 @@ impl<'a> Parser<'a> { let eof_span = last_token.span; self.add_diagnostic( - ParseErrors::TupleValueExpected, + ParseErrorKind::TupleValueExpected, open_tuple.diagnostic_token.span.clone(), )?; let mut placeholder = @@ -396,7 +405,7 @@ impl<'a> Parser<'a> { _ => { // Report an error, then skip this token self.add_diagnostic( - ParseErrors::UnexpectedToken(last_token.token), + ParseErrorKind::UnexpectedToken(last_token.token), last_token.span, )?; return Ok(None); // Ok(None) yields to the parse loop @@ -425,7 +434,7 @@ impl<'a> Parser<'a> { return Ok(Some(e)); } Token::Eof => (), - _ => self.add_diagnostic(ParseErrors::TupleCommaExpectedv2, token.span)?, + _ => self.add_diagnostic(ParseErrorKind::TupleCommaExpectedv2, token.span)?, } let mut comments = self.ignore_whitespace_and_comments(); @@ -469,7 +478,7 @@ impl<'a> Parser<'a> { let token = self.peek_next_token(); match token.token { Token::Comma => { - self.add_diagnostic(ParseErrors::UnexpectedToken(token.token), token.span)?; + self.add_diagnostic(ParseErrorKind::UnexpectedToken(token.token), token.span)?; self.next_token(); } Token::Rbrace => { @@ -514,7 +523,7 @@ impl<'a> Parser<'a> { let principal = match PrincipalData::parse_standard_principal(&addr) { Ok(principal) => principal, _ => { - self.add_diagnostic(ParseErrors::InvalidPrincipalLiteral, span.clone())?; + self.add_diagnostic(ParseErrorKind::InvalidPrincipalLiteral, span.clone())?; let mut placeholder = PreSymbolicExpression::placeholder(format!("'{addr}")); placeholder.copy_span(&span); return Ok(placeholder); @@ -540,7 +549,7 @@ impl<'a> Parser<'a> { }) => { span.end_line = token_span.end_line; span.end_column = token_span.end_column; - self.add_diagnostic(ParseErrors::ExpectedContractIdentifier, token_span)?; + self.add_diagnostic(ParseErrorKind::ExpectedContractIdentifier, token_span)?; let mut placeholder = PreSymbolicExpression::placeholder(format!( "'{principal}.{}", token.reproduce() @@ -549,7 +558,7 @@ impl<'a> Parser<'a> { return Ok(placeholder); } None => { - self.add_diagnostic(ParseErrors::ExpectedContractIdentifier, dot.span)?; + self.add_diagnostic(ParseErrorKind::ExpectedContractIdentifier, dot.span)?; let mut placeholder = PreSymbolicExpression::placeholder(format!("'{principal}.")); placeholder.copy_span(&span); @@ -559,7 +568,7 @@ impl<'a> Parser<'a> { if name.len() > MAX_CONTRACT_NAME_LEN { self.add_diagnostic( - ParseErrors::ContractNameTooLong(name.clone()), + ParseErrorKind::ContractNameTooLong(name.clone()), contract_span, )?; let mut placeholder = @@ -571,7 +580,7 @@ impl<'a> Parser<'a> { Ok(id) => id, Err(_) => { self.add_diagnostic( - ParseErrors::IllegalContractName(name.clone()), + ParseErrorKind::IllegalContractName(name.clone()), contract_span, )?; let mut placeholder = @@ -600,7 +609,7 @@ impl<'a> Parser<'a> { token, }) => { self.add_diagnostic( - ParseErrors::ExpectedTraitIdentifier, + ParseErrorKind::ExpectedTraitIdentifier, token_span.clone(), )?; let mut placeholder = PreSymbolicExpression::placeholder(format!( @@ -614,7 +623,7 @@ impl<'a> Parser<'a> { } None => { self.add_diagnostic( - ParseErrors::ExpectedTraitIdentifier, + ParseErrorKind::ExpectedTraitIdentifier, dot.span.clone(), )?; let mut placeholder = @@ -626,7 +635,7 @@ impl<'a> Parser<'a> { } }; if name.len() > MAX_STRING_LEN { - self.add_diagnostic(ParseErrors::NameTooLong(name.clone()), trait_span)?; + self.add_diagnostic(ParseErrorKind::NameTooLong(name.clone()), trait_span)?; let mut placeholder = PreSymbolicExpression::placeholder(format!("'{contract_id}.{name}",)); placeholder.copy_span(&span); @@ -636,7 +645,7 @@ impl<'a> Parser<'a> { Ok(id) => id, Err(_) => { self.add_diagnostic( - ParseErrors::IllegalTraitName(name.clone()), + ParseErrorKind::IllegalTraitName(name.clone()), trait_span, )?; let mut placeholder = @@ -682,7 +691,10 @@ impl<'a> Parser<'a> { span: token_span, token, }) => { - self.add_diagnostic(ParseErrors::ExpectedContractIdentifier, token_span.clone())?; + self.add_diagnostic( + ParseErrorKind::ExpectedContractIdentifier, + token_span.clone(), + )?; let mut placeholder = PreSymbolicExpression::placeholder(format!(".{}", token.reproduce())); span.end_line = token_span.end_line; @@ -691,7 +703,7 @@ impl<'a> Parser<'a> { return Ok(placeholder); } None => { - self.add_diagnostic(ParseErrors::ExpectedContractIdentifier, span.clone())?; + self.add_diagnostic(ParseErrorKind::ExpectedContractIdentifier, span.clone())?; let mut placeholder = PreSymbolicExpression::placeholder(".".to_string()); placeholder.copy_span(&span); return Ok(placeholder); @@ -699,7 +711,10 @@ impl<'a> Parser<'a> { }; if name.len() > MAX_CONTRACT_NAME_LEN { - self.add_diagnostic(ParseErrors::ContractNameTooLong(name.clone()), span.clone())?; + self.add_diagnostic( + ParseErrorKind::ContractNameTooLong(name.clone()), + span.clone(), + )?; let mut placeholder = PreSymbolicExpression::placeholder(format!(".{name}")); placeholder.copy_span(&span); return Ok(placeholder); @@ -709,7 +724,7 @@ impl<'a> Parser<'a> { Ok(id) => id, Err(_) => { self.add_diagnostic( - ParseErrors::IllegalContractName(name.clone()), + ParseErrorKind::IllegalContractName(name.clone()), contract_span, )?; let mut placeholder = PreSymbolicExpression::placeholder(format!(".{name}")); @@ -735,7 +750,10 @@ impl<'a> Parser<'a> { span: token_span, token, }) => { - self.add_diagnostic(ParseErrors::ExpectedTraitIdentifier, token_span.clone())?; + self.add_diagnostic( + ParseErrorKind::ExpectedTraitIdentifier, + token_span.clone(), + )?; let mut placeholder = PreSymbolicExpression::placeholder(format!( ".{contract_name}.{}", token.reproduce(), @@ -746,7 +764,7 @@ impl<'a> Parser<'a> { return Ok(placeholder); } None => { - self.add_diagnostic(ParseErrors::ExpectedTraitIdentifier, dot.span.clone())?; + self.add_diagnostic(ParseErrorKind::ExpectedTraitIdentifier, dot.span.clone())?; let mut placeholder = PreSymbolicExpression::placeholder(format!(".{contract_name}.")); span.end_line = dot.span.end_line; @@ -756,7 +774,7 @@ impl<'a> Parser<'a> { } }; if name.len() > MAX_STRING_LEN { - self.add_diagnostic(ParseErrors::NameTooLong(name.clone()), trait_span)?; + self.add_diagnostic(ParseErrorKind::NameTooLong(name.clone()), trait_span)?; let mut placeholder = PreSymbolicExpression::placeholder(format!(".{contract_name}.{name}")); placeholder.copy_span(&span); @@ -765,7 +783,10 @@ impl<'a> Parser<'a> { let trait_name = match ClarityName::try_from(name.clone()) { Ok(id) => id, Err(_) => { - self.add_diagnostic(ParseErrors::IllegalTraitName(name.clone()), trait_span)?; + self.add_diagnostic( + ParseErrorKind::IllegalTraitName(name.clone()), + trait_span, + )?; let mut placeholder = PreSymbolicExpression::placeholder(format!(".{contract_name}.{name}")); placeholder.copy_span(&span); @@ -805,7 +826,7 @@ impl<'a> Parser<'a> { self.nesting_depth += 1; if self.nesting_depth > MAX_NESTING_DEPTH { self.add_diagnostic( - ParseErrors::ExpressionStackDepthTooDeep, + ParseErrorKind::ExpressionStackDepthTooDeep, token.span.clone(), )?; // Do not try to continue, exit cleanly now to avoid a stack overflow. @@ -824,7 +845,7 @@ impl<'a> Parser<'a> { // This sugared syntax for tuple becomes a list of pairs, so depth is increased by 2. if self.nesting_depth + 2 > MAX_NESTING_DEPTH { self.add_diagnostic( - ParseErrors::ExpressionStackDepthTooDeep, + ParseErrorKind::ExpressionStackDepthTooDeep, token.span.clone(), )?; // Do not try to continue, exit cleanly now to avoid a stack overflow. @@ -847,7 +868,7 @@ impl<'a> Parser<'a> { Ok(val) => PreSymbolicExpression::atom_value(Value::Int(val)), Err(_) => { self.add_diagnostic( - ParseErrors::FailedParsingIntValue(val_string.clone()), + ParseErrorKind::FailedParsingIntValue(val_string.clone()), token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -861,7 +882,7 @@ impl<'a> Parser<'a> { Ok(val) => PreSymbolicExpression::atom_value(Value::UInt(val)), Err(_) => { self.add_diagnostic( - ParseErrors::FailedParsingUIntValue(val_string.clone()), + ParseErrorKind::FailedParsingUIntValue(val_string.clone()), token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -875,8 +896,14 @@ impl<'a> Parser<'a> { match Value::string_ascii_from_bytes(val.clone().into_bytes()) { Ok(s) => PreSymbolicExpression::atom_value(s), Err(_) => { + // Protect against console flooding and process hanging while running tests, + // using a purely arbitrary max chars limit. + // NOTE: A better place for this would be the enum itself, but then we need to write a custom Debug implementation + #[cfg(any(test, feature = "testing"))] + let val = ellipse_string_for_test(val, 128); + self.add_diagnostic( - ParseErrors::IllegalASCIIString(val.clone()), + ParseErrorKind::IllegalASCIIString(val.clone()), token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -905,7 +932,7 @@ impl<'a> Parser<'a> { Token::Ident(name) => { let mut expr = if name.len() > MAX_STRING_LEN { self.add_diagnostic( - ParseErrors::NameTooLong(name.clone()), + ParseErrorKind::NameTooLong(name.clone()), token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -914,7 +941,7 @@ impl<'a> Parser<'a> { Ok(name) => PreSymbolicExpression::atom(name), Err(_) => { self.add_diagnostic( - ParseErrors::IllegalClarityName(name.clone()), + ParseErrorKind::IllegalClarityName(name.clone()), token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -927,7 +954,7 @@ impl<'a> Parser<'a> { Token::TraitIdent(name) => { let mut expr = if name.len() > MAX_STRING_LEN { self.add_diagnostic( - ParseErrors::NameTooLong(name.clone()), + ParseErrorKind::NameTooLong(name.clone()), token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -936,7 +963,7 @@ impl<'a> Parser<'a> { Ok(name) => PreSymbolicExpression::trait_reference(name), Err(_) => { self.add_diagnostic( - ParseErrors::IllegalTraitName(name.clone()), + ParseErrorKind::IllegalTraitName(name.clone()), token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -952,7 +979,7 @@ impl<'a> Parser<'a> { Ok(value) => PreSymbolicExpression::atom_value(value), _ => { self.add_diagnostic( - ParseErrors::InvalidBuffer, + ParseErrorKind::InvalidBuffer, token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -960,7 +987,7 @@ impl<'a> Parser<'a> { }, Err(_) => { self.add_diagnostic( - ParseErrors::InvalidBuffer, + ParseErrorKind::InvalidBuffer, token.span.clone(), )?; PreSymbolicExpression::placeholder(token.token.reproduce()) @@ -986,7 +1013,7 @@ impl<'a> Parser<'a> { | Token::Greater | Token::GreaterEqual => { let name = ClarityName::try_from(token.token.to_string()) - .map_err(|_| ParseErrors::InterpreterFailure)?; + .map_err(|_| ParseErrorKind::InterpreterFailure)?; let mut e = PreSymbolicExpression::atom(name); e.copy_span(&token.span); Some(e) @@ -1054,7 +1081,7 @@ impl<'a> Parser<'a> { _ => { // Report an error, then skip this token self.add_diagnostic( - ParseErrors::UnexpectedToken(token.token), + ParseErrorKind::UnexpectedToken(token.token), token.span, )?; } @@ -1110,6 +1137,25 @@ pub fn parse_collect_diagnostics( (stmts, diagnostics, parser.success) } +/// Test helper function to shorten big strings while running tests +/// +/// This prevents both: +/// - Console flooding with multi-megabyte output during test runs. +/// - Potential test process blocking or hanging due to stdout buffering limits. +/// +/// In case a the input `string` need to be shortned based on `max_chars`, +/// the resulting string will be ellipsed showing the original character count. +#[cfg(any(test, feature = "testing"))] +fn ellipse_string_for_test(string: &str, max_chars: usize) -> String { + let char_count = string.chars().count(); + if char_count <= max_chars { + string.into() + } else { + let shortened: String = string.chars().take(max_chars).collect(); + format!("{shortened}...[{char_count}]") + } +} + #[cfg(test)] #[cfg(feature = "developer-mode")] mod tests { @@ -3533,7 +3579,10 @@ mod tests { fn test_parse_fail_fast() { match parse("42g !ok") { Ok(_) => panic!("fail_fast mode should have returned an error"), - Err(e) => assert_eq!(*e.err, ParseErrors::Lexer(LexerError::InvalidCharInt('g'))), + Err(e) => assert_eq!( + *e.err, + ParseErrorKind::Lexer(LexerError::InvalidCharInt('g')) + ), } } @@ -3561,7 +3610,7 @@ mod tests { ); assert!(match *(parse(&exceeds_stack_depth_list).unwrap_err().err) { - ParseErrors::ExpressionStackDepthTooDeep => true, + ParseErrorKind::ExpressionStackDepthTooDeep => true, x => panic!("expected a stack depth too deep error, got {x:?}"), }); @@ -3584,7 +3633,7 @@ mod tests { ); assert!(match *parse(&exceeds_stack_depth_tuple).unwrap_err().err { - ParseErrors::ExpressionStackDepthTooDeep => true, + ParseErrorKind::ExpressionStackDepthTooDeep => true, x => panic!("expected a stack depth too deep error, got {x:?}"), }); diff --git a/clarity/src/vm/ast/stack_depth_checker.rs b/clarity/src/vm/ast/stack_depth_checker.rs index 5115e107373..0e3bf7db23c 100644 --- a/clarity/src/vm/ast/stack_depth_checker.rs +++ b/clarity/src/vm/ast/stack_depth_checker.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::vm::ast::errors::{ParseErrors, ParseResult}; +use crate::vm::ast::errors::{ParseErrorKind, ParseResult}; use crate::vm::ast::types::{BuildASTPass, ContractAST}; use crate::vm::representations::PreSymbolicExpression; use crate::vm::representations::PreSymbolicExpressionType::{List, Tuple}; @@ -27,7 +27,7 @@ pub const AST_CALL_STACK_DEPTH_BUFFER: u64 = 5; fn check(args: &[PreSymbolicExpression], depth: u64) -> ParseResult<()> { if depth >= (AST_CALL_STACK_DEPTH_BUFFER + MAX_CALL_STACK_DEPTH as u64) { - return Err(ParseErrors::ExpressionStackDepthTooDeep.into()); + return Err(ParseErrorKind::ExpressionStackDepthTooDeep.into()); } for expression in args.iter() { match expression.pre_expr { @@ -52,7 +52,7 @@ impl BuildASTPass for StackDepthChecker { fn check_vary(args: &[PreSymbolicExpression], depth: u64) -> ParseResult<()> { if depth >= (AST_CALL_STACK_DEPTH_BUFFER + MAX_CALL_STACK_DEPTH as u64) { - return Err(ParseErrors::VaryExpressionStackDepthTooDeep.into()); + return Err(ParseErrorKind::VaryExpressionStackDepthTooDeep.into()); } for expression in args.iter() { match expression.pre_expr { diff --git a/clarity/src/vm/ast/sugar_expander/mod.rs b/clarity/src/vm/ast/sugar_expander/mod.rs index b7b4965f50c..57b2f414c2c 100644 --- a/clarity/src/vm/ast/sugar_expander/mod.rs +++ b/clarity/src/vm/ast/sugar_expander/mod.rs @@ -21,7 +21,7 @@ use clarity_types::types::{ PrincipalData, QualifiedContractIdentifier, StandardPrincipalData, TraitIdentifier, Value, }; -use crate::vm::ast::errors::{ParseErrors, ParseResult}; +use crate::vm::ast::errors::{ParseErrorKind, ParseResult}; use crate::vm::ast::types::{BuildASTPass, ContractAST, PreExpressionsDrain}; use crate::vm::representations::{PreSymbolicExpressionType, SymbolicExpression}; use crate::vm::ClarityVersion; @@ -92,7 +92,7 @@ impl SugarExpander { "tuple" .to_string() .try_into() - .map_err(|_| ParseErrors::InterpreterFailure)?, + .map_err(|_| ParseErrorKind::InterpreterFailure)?, ), ); SymbolicExpression::list(pairs) @@ -119,7 +119,7 @@ impl SugarExpander { if let Some(trait_reference) = contract_ast.get_referenced_trait(&name) { SymbolicExpression::trait_reference(name, trait_reference.clone()) } else { - return Err(ParseErrors::TraitReferenceUnknown(name.to_string()).into()); + return Err(ParseErrorKind::TraitReferenceUnknown(name.to_string()).into()); } } #[cfg(not(feature = "developer-mode"))] diff --git a/clarity/src/vm/ast/traits_resolver/mod.rs b/clarity/src/vm/ast/traits_resolver/mod.rs index 90bf989ade5..df77ed41f65 100644 --- a/clarity/src/vm/ast/traits_resolver/mod.rs +++ b/clarity/src/vm/ast/traits_resolver/mod.rs @@ -19,7 +19,7 @@ use std::collections::HashMap; use clarity_types::representations::ClarityName; use clarity_types::types::{QualifiedContractIdentifier, TraitIdentifier}; -use crate::vm::ast::errors::{ParseError, ParseErrors, ParseResult}; +use crate::vm::ast::errors::{ParseError, ParseErrorKind, ParseResult}; use crate::vm::ast::types::{BuildASTPass, ContractAST}; use crate::vm::functions::define::DefineFunctions; use crate::vm::representations::PreSymbolicExpressionType::{ @@ -56,16 +56,17 @@ impl TraitsResolver { match define_type { DefineFunctions::Trait => { if args.len() != 2 { - return Err(ParseErrors::DefineTraitBadSignature.into()); + return Err(ParseErrorKind::DefineTraitBadSignature.into()); } match (&args[0].pre_expr, &args[1].pre_expr) { (Atom(trait_name), List(trait_definition)) => { // Check for collisions if contract_ast.referenced_traits.contains_key(trait_name) { - return Err( - ParseErrors::NameAlreadyUsed(trait_name.to_string()).into() - ); + return Err(ParseErrorKind::NameAlreadyUsed( + trait_name.to_string(), + ) + .into()); } // Traverse and probe for generics nested in the trait definition @@ -83,18 +84,20 @@ impl TraitsResolver { .referenced_traits .insert(trait_name.clone(), TraitDefinition::Defined(trait_id)); } - _ => return Err(ParseErrors::DefineTraitBadSignature.into()), + _ => return Err(ParseErrorKind::DefineTraitBadSignature.into()), } } DefineFunctions::UseTrait => { if args.len() != 2 { - return Err(ParseErrors::ImportTraitBadSignature.into()); + return Err(ParseErrorKind::ImportTraitBadSignature.into()); } if let Some(trait_name) = args[0].match_atom() { // Check for collisions if contract_ast.referenced_traits.contains_key(trait_name) { - return Err(ParseErrors::NameAlreadyUsed(trait_name.to_string()).into()); + return Err( + ParseErrorKind::NameAlreadyUsed(trait_name.to_string()).into() + ); } let trait_id = match &args[1].pre_expr { @@ -109,18 +112,18 @@ impl TraitsResolver { } } FieldIdentifier(trait_identifier) => trait_identifier.clone(), - _ => return Err(ParseErrors::ImportTraitBadSignature.into()), + _ => return Err(ParseErrorKind::ImportTraitBadSignature.into()), }; contract_ast .referenced_traits .insert(trait_name.clone(), TraitDefinition::Imported(trait_id)); } else { - return Err(ParseErrors::ImportTraitBadSignature.into()); + return Err(ParseErrorKind::ImportTraitBadSignature.into()); } } DefineFunctions::ImplTrait => { if args.len() != 1 { - return Err(ParseErrors::ImplTraitBadSignature.into()); + return Err(ParseErrorKind::ImplTraitBadSignature.into()); } let trait_id = match &args[0].pre_expr { @@ -135,7 +138,7 @@ impl TraitsResolver { } } FieldIdentifier(trait_identifier) => trait_identifier.clone(), - _ => return Err(ParseErrors::ImplTraitBadSignature.into()), + _ => return Err(ParseErrorKind::ImplTraitBadSignature.into()), }; contract_ast.implemented_traits.insert(trait_id); } @@ -166,7 +169,7 @@ impl TraitsResolver { .referenced_traits .contains_key(&trait_reference) { - let mut err = ParseError::new(ParseErrors::TraitReferenceUnknown( + let mut err = ParseError::new(ParseErrorKind::TraitReferenceUnknown( trait_reference.to_string(), )); err.set_pre_expression(&expr); @@ -207,7 +210,7 @@ impl TraitsResolver { if should_reference { referenced_traits.insert(trait_name.clone(), expression.clone()); } else { - return Err(ParseErrors::TraitReferenceNotAllowed.into()); + return Err(ParseErrorKind::TraitReferenceNotAllowed.into()); } } Tuple(atoms) => { diff --git a/clarity/src/vm/callables.rs b/clarity/src/vm/callables.rs index fb82f973386..052c7d6dc00 100644 --- a/clarity/src/vm/callables.rs +++ b/clarity/src/vm/callables.rs @@ -21,14 +21,14 @@ pub use clarity_types::types::FunctionIdentifier; use stacks_common::types::StacksEpochId; use super::costs::{CostErrors, CostOverflowingMath}; -use super::errors::InterpreterError; +use super::errors::VmInternalError; use super::types::signatures::CallableSubtype; use super::ClarityVersion; -use crate::vm::analysis::errors::CheckErrors; +use crate::vm::analysis::errors::CheckErrorKind; use crate::vm::contexts::ContractContext; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; -use crate::vm::errors::{check_argument_count, Error, InterpreterResult as Result}; +use crate::vm::errors::{check_argument_count, VmExecutionError}; use crate::vm::representations::SymbolicExpression; use crate::vm::types::{ CallableData, ListData, ListTypeData, OptionalData, PrincipalData, ResponseData, SequenceData, @@ -47,11 +47,15 @@ pub enum CallableType { &'static str, NativeHandle, ClarityCostFunction, - &'static dyn Fn(&[Value]) -> Result, + &'static dyn Fn(&[Value]) -> Result, ), SpecialFunction( &'static str, - &'static dyn Fn(&[SymbolicExpression], &mut Environment, &LocalContext) -> Result, + &'static dyn Fn( + &[SymbolicExpression], + &mut Environment, + &LocalContext, + ) -> Result, ), } @@ -76,30 +80,35 @@ pub struct DefinedFunction { /// implementing a native function. Each variant handles /// different expected number of arguments. pub enum NativeHandle { - SingleArg(&'static dyn Fn(Value) -> Result), - DoubleArg(&'static dyn Fn(Value, Value) -> Result), - MoreArg(&'static dyn Fn(Vec) -> Result), - MoreArgEnv(&'static dyn Fn(Vec, &mut Environment) -> Result), + SingleArg(&'static dyn Fn(Value) -> Result), + DoubleArg(&'static dyn Fn(Value, Value) -> Result), + MoreArg(&'static dyn Fn(Vec) -> Result), + #[allow(clippy::type_complexity)] + MoreArgEnv(&'static dyn Fn(Vec, &mut Environment) -> Result), } impl NativeHandle { - pub fn apply(&self, mut args: Vec, env: &mut Environment) -> Result { + pub fn apply( + &self, + mut args: Vec, + env: &mut Environment, + ) -> Result { match self { Self::SingleArg(function) => { check_argument_count(1, &args)?; function( args.pop() - .ok_or_else(|| InterpreterError::Expect("Unexpected list length".into()))?, + .ok_or_else(|| VmInternalError::Expect("Unexpected list length".into()))?, ) } Self::DoubleArg(function) => { check_argument_count(2, &args)?; let second = args .pop() - .ok_or_else(|| InterpreterError::Expect("Unexpected list length".into()))?; + .ok_or_else(|| VmInternalError::Expect("Unexpected list length".into()))?; let first = args .pop() - .ok_or_else(|| InterpreterError::Expect("Unexpected list length".into()))?; + .ok_or_else(|| VmInternalError::Expect("Unexpected list length".into()))?; function(first, second) } Self::MoreArg(function) => function(args), @@ -108,7 +117,7 @@ impl NativeHandle { } } -pub fn cost_input_sized_vararg(args: &[Value]) -> Result { +pub fn cost_input_sized_vararg(args: &[Value]) -> Result { args.iter() .try_fold(0, |sum, value| { (value @@ -116,7 +125,7 @@ pub fn cost_input_sized_vararg(args: &[Value]) -> Result { .map_err(|e| CostErrors::Expect(format!("{e:?}")))? as u64) .cost_overflow_add(sum) }) - .map_err(Error::from) + .map_err(VmExecutionError::from) } impl DefinedFunction { @@ -139,7 +148,11 @@ impl DefinedFunction { } } - pub fn execute_apply(&self, args: &[Value], env: &mut Environment) -> Result { + pub fn execute_apply( + &self, + args: &[Value], + env: &mut Environment, + ) -> Result { runtime_cost( ClarityCostFunction::UserFunctionApplication, env, @@ -162,7 +175,7 @@ impl DefinedFunction { let mut context = LocalContext::new(); if args.len() != self.arguments.len() { - Err(CheckErrors::IncorrectArgumentCount( + Err(CheckErrorKind::IncorrectArgumentCount( self.arguments.len(), args.len(), ))? @@ -233,7 +246,7 @@ impl DefinedFunction { } _ => { if !type_sig.admits(env.epoch(), value)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(type_sig.clone()), Box::new(value.clone()), ) @@ -244,7 +257,7 @@ impl DefinedFunction { .insert(name.clone(), value.clone()) .is_some() { - return Err(CheckErrors::NameAlreadyUsed(name.to_string()).into()); + return Err(CheckErrorKind::NameAlreadyUsed(name.to_string()).into()); } } } @@ -278,7 +291,7 @@ impl DefinedFunction { } _ => { if !type_sig.admits(env.epoch(), &cast_value)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(type_sig.clone()), Box::new(cast_value), ) @@ -288,7 +301,7 @@ impl DefinedFunction { } if context.variables.insert(name.clone(), cast_value).is_some() { - return Err(CheckErrors::NameAlreadyUsed(name.to_string()).into()); + return Err(CheckErrorKind::NameAlreadyUsed(name.to_string()).into()); } } } @@ -300,7 +313,7 @@ impl DefinedFunction { match result { Ok(r) => Ok(r), Err(e) => match e { - Error::ShortReturn(v) => Ok(v.into()), + VmExecutionError::EarlyReturn(v) => Ok(v.into()), _ => Err(e), }, } @@ -311,15 +324,17 @@ impl DefinedFunction { epoch: &StacksEpochId, contract_defining_trait: &ContractContext, trait_identifier: &TraitIdentifier, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let trait_name = trait_identifier.name.to_string(); let constraining_trait = contract_defining_trait .lookup_trait_definition(&trait_name) - .ok_or(CheckErrors::TraitReferenceUnknown(trait_name.to_string()))?; + .ok_or(CheckErrorKind::TraitReferenceUnknown( + trait_name.to_string(), + ))?; let expected_sig = constraining_trait .get(&self.name) - .ok_or(CheckErrors::TraitMethodUnknown( + .ok_or(CheckErrorKind::TraitMethodUnknown( trait_name.to_string(), self.name.to_string(), ))?; @@ -327,7 +342,7 @@ impl DefinedFunction { let args = self.arg_types.to_vec(); if !expected_sig.check_args_trait_compliance(epoch, args)? { return Err( - CheckErrors::BadTraitImplementation(trait_name, self.name.to_string()).into(), + CheckErrorKind::BadTraitImplementation(trait_name, self.name.to_string()).into(), ); } @@ -338,7 +353,7 @@ impl DefinedFunction { self.define_type == DefineType::ReadOnly } - pub fn apply(&self, args: &[Value], env: &mut Environment) -> Result { + pub fn apply(&self, args: &[Value], env: &mut Environment) -> Result { match self.define_type { DefineType::Private => self.execute_apply(args, env), DefineType::Public => env.execute_function_as_transaction(self, args, None, false), @@ -395,7 +410,10 @@ impl CallableType { // recursing into compound types. This function does not check for legality of // these casts, as that is done in the type-checker. Note: depth of recursion // should be capped by earlier checks on the types/values. -fn clarity2_implicit_cast(type_sig: &TypeSignature, value: &Value) -> Result { +fn clarity2_implicit_cast( + type_sig: &TypeSignature, + value: &Value, +) -> Result { Ok(match (type_sig, value) { ( TypeSignature::OptionalType(inner_type), @@ -455,7 +473,7 @@ fn clarity2_implicit_cast(type_sig: &TypeSignature, value: &Value) -> Result ty, None => { // This should be unreachable if the type-checker has already run successfully - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(type_sig.clone()), Box::new(value.clone()), ) diff --git a/clarity/src/vm/clarity.rs b/clarity/src/vm/clarity.rs index 34461862d7b..0bbd6a7d0a6 100644 --- a/clarity/src/vm/clarity.rs +++ b/clarity/src/vm/clarity.rs @@ -2,24 +2,37 @@ use std::fmt; use stacks_common::types::StacksEpochId; -use crate::vm::analysis::{AnalysisDatabase, CheckError, CheckErrors, ContractAnalysis}; -use crate::vm::ast::errors::{ParseError, ParseErrors}; +use crate::vm::analysis::{AnalysisDatabase, CheckErrorKind, ContractAnalysis, StaticCheckError}; +use crate::vm::ast::errors::{ParseError, ParseErrorKind}; use crate::vm::ast::ContractAST; use crate::vm::contexts::{AssetMap, Environment, OwnedEnvironment}; use crate::vm::costs::{ExecutionCost, LimitedCostTracker}; use crate::vm::database::ClarityDatabase; -use crate::vm::errors::Error as InterpreterError; +use crate::vm::errors::VmExecutionError; use crate::vm::events::StacksTransactionEvent; use crate::vm::types::{BuffData, PrincipalData, QualifiedContractIdentifier}; use crate::vm::{analysis, ast, ClarityVersion, ContractContext, SymbolicExpression, Value}; +/// Top-level error type for Clarity contract processing, encompassing errors from parsing, +/// type-checking, runtime evaluation, and transaction execution. #[derive(Debug)] -pub enum Error { - Analysis(CheckError), +pub enum ClarityError { + /// Error during static type-checking or semantic analysis. + /// The `StaticCheckError` wraps the specific type-checking error, including diagnostic details. + StaticCheck(StaticCheckError), + /// Error during lexical or syntactic parsing. + /// The `ParseError` wraps the specific parsing error, such as invalid syntax or tokens. Parse(ParseError), - Interpreter(InterpreterError), + /// Error during runtime evaluation in the virtual machine. + /// The `VmExecutionError` wraps the specific error, such as runtime errors or dynamic type-checking errors. + Interpreter(VmExecutionError), + /// Transaction is malformed or invalid due to blockchain-level issues. + /// The `String` wraps a human-readable description of the issue, such as incorrect format or invalid signatures. BadTransaction(String), + /// Transaction exceeds the allocated cost budget during execution. + /// The first `ExecutionCost` represents the total consumed cost, and the second represents the budget limit. CostError(ExecutionCost, ExecutionCost), + /// Transaction aborted by a callback (e.g., post-condition check or custom logic). AbortedByCallback { /// What the output value of the transaction would have been. /// This will be a Some for contract-calls, and None for contract initialization txs. @@ -33,85 +46,107 @@ pub enum Error { }, } -impl fmt::Display for Error { +impl fmt::Display for ClarityError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Error::CostError(ref a, ref b) => { + ClarityError::CostError(ref a, ref b) => { write!(f, "Cost Error: {a} cost exceeded budget of {b} cost") } - Error::Analysis(ref e) => fmt::Display::fmt(e, f), - Error::Parse(ref e) => fmt::Display::fmt(e, f), - Error::AbortedByCallback { reason, .. } => { + ClarityError::StaticCheck(ref e) => fmt::Display::fmt(e, f), + ClarityError::Parse(ref e) => fmt::Display::fmt(e, f), + ClarityError::AbortedByCallback { reason, .. } => { write!(f, "Post condition aborted transaction: {reason}") } - Error::Interpreter(ref e) => fmt::Display::fmt(e, f), - Error::BadTransaction(ref s) => fmt::Display::fmt(s, f), + ClarityError::Interpreter(ref e) => fmt::Display::fmt(e, f), + ClarityError::BadTransaction(ref s) => fmt::Display::fmt(s, f), } } } -impl std::error::Error for Error { +impl std::error::Error for ClarityError { fn cause(&self) -> Option<&dyn std::error::Error> { match *self { - Error::CostError(ref _a, ref _b) => None, - Error::AbortedByCallback { .. } => None, - Error::Analysis(ref e) => Some(e), - Error::Parse(ref e) => Some(e), - Error::Interpreter(ref e) => Some(e), - Error::BadTransaction(ref _s) => None, + ClarityError::CostError(ref _a, ref _b) => None, + ClarityError::AbortedByCallback { .. } => None, + ClarityError::StaticCheck(ref e) => Some(e), + ClarityError::Parse(ref e) => Some(e), + ClarityError::Interpreter(ref e) => Some(e), + ClarityError::BadTransaction(ref _s) => None, } } } -impl From for Error { - fn from(e: CheckError) -> Self { +impl From for ClarityError { + fn from(e: StaticCheckError) -> Self { match *e.err { - CheckErrors::CostOverflow => { - Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) + CheckErrorKind::CostOverflow => { + ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - CheckErrors::CostBalanceExceeded(a, b) => Error::CostError(a, b), - CheckErrors::MemoryBalanceExceeded(_a, _b) => { - Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) + CheckErrorKind::CostBalanceExceeded(a, b) => ClarityError::CostError(a, b), + CheckErrorKind::MemoryBalanceExceeded(_a, _b) => { + ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - CheckErrors::ExecutionTimeExpired => { - Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) + CheckErrorKind::ExecutionTimeExpired => { + ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - _ => Error::Analysis(e), + _ => ClarityError::StaticCheck(e), } } } -impl From for Error { - fn from(e: InterpreterError) -> Self { +/// Converts [`VmExecutionError`] to [`ClarityError`] for transaction execution contexts. +/// +/// This conversion is used in: +/// - [`TransactionConnection::initialize_smart_contract`] +/// - [`TransactionConnection::run_contract_call`] +/// - [`TransactionConnection::run_stx_transfer`] +/// +/// # Notes +/// +/// - [`CheckErrorKind::MemoryBalanceExceeded`] and [`CheckErrorKind::CostComputationFailed`] +/// are intentionally not converted to [`ClarityError::CostError`]. +/// Instead, they remain wrapped in `ClarityError::Interpreter(VmExecutionError::Unchecked(CheckErrorKind::MemoryBalanceExceeded))`, +/// which causes the transaction to fail, but still be included in the block. +/// +/// - This behavior differs from direct conversions of [`StaticCheckError`] and [`ParseError`] to [`ClarityError`], +/// where [`CheckErrorKind::MemoryBalanceExceeded`] is converted to [`ClarityError::CostError`], +/// during contract analysis. +/// +/// As a result: +/// - A `MemoryBalanceExceeded` during contract analysis causes the block to be rejected. +/// - A `MemoryBalanceExceeded` during execution (initialization or contract call) +/// causes the transaction to fail, but the block remains valid. +impl From for ClarityError { + fn from(e: VmExecutionError) -> Self { match &e { - InterpreterError::Unchecked(CheckErrors::CostBalanceExceeded(a, b)) => { - Error::CostError(a.clone(), b.clone()) + VmExecutionError::Unchecked(CheckErrorKind::CostBalanceExceeded(a, b)) => { + ClarityError::CostError(a.clone(), b.clone()) } - InterpreterError::Unchecked(CheckErrors::CostOverflow) => { - Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) + VmExecutionError::Unchecked(CheckErrorKind::CostOverflow) => { + ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - InterpreterError::Unchecked(CheckErrors::ExecutionTimeExpired) => { - Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) + VmExecutionError::Unchecked(CheckErrorKind::ExecutionTimeExpired) => { + ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - _ => Error::Interpreter(e), + _ => ClarityError::Interpreter(e), } } } -impl From for Error { +impl From for ClarityError { fn from(e: ParseError) -> Self { match *e.err { - ParseErrors::CostOverflow => { - Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) + ParseErrorKind::CostOverflow => { + ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - ParseErrors::CostBalanceExceeded(a, b) => Error::CostError(a, b), - ParseErrors::MemoryBalanceExceeded(_a, _b) => { - Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) + ParseErrorKind::CostBalanceExceeded(a, b) => ClarityError::CostError(a, b), + ParseErrorKind::MemoryBalanceExceeded(_a, _b) => { + ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - ParseErrors::ExecutionTimeExpired => { - Error::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) + ParseErrorKind::ExecutionTimeExpired => { + ClarityError::CostError(ExecutionCost::max_value(), ExecutionCost::max_value()) } - _ => Error::Parse(e), + _ => ClarityError::Parse(e), } } } @@ -143,9 +178,9 @@ pub trait ClarityConnection { sponsor: Option, cost_track: LimitedCostTracker, to_do: F, - ) -> Result + ) -> Result where - F: FnOnce(&mut Environment) -> Result, + F: FnOnce(&mut Environment) -> Result, { let epoch_id = self.get_epoch(); let clarity_version = ClarityVersion::default_for_epoch(epoch_id); @@ -192,7 +227,7 @@ pub trait TransactionConnection: ClarityConnection { where A: FnOnce(&AssetMap, &mut ClarityDatabase) -> Option, F: FnOnce(&mut OwnedEnvironment) -> Result<(R, AssetMap, Vec), E>, - E: From; + E: From; /// Do something with the analysis database and cost tracker /// instance of this transaction connection. This is a low-level @@ -209,7 +244,7 @@ pub trait TransactionConnection: ClarityConnection { identifier: &QualifiedContractIdentifier, clarity_version: ClarityVersion, contract_content: &str, - ) -> Result<(ContractAST, ContractAnalysis), Error> { + ) -> Result<(ContractAST, ContractAnalysis), ClarityError> { let epoch_id = self.get_epoch(); self.with_analysis_db(|db, mut cost_track| { @@ -254,7 +289,7 @@ pub trait TransactionConnection: ClarityConnection { &mut self, identifier: &QualifiedContractIdentifier, contract_analysis: &ContractAnalysis, - ) -> Result<(), CheckError> { + ) -> Result<(), StaticCheckError> { self.with_analysis_db(|db, cost_tracker| { db.begin(); let result = db.insert_contract(identifier, contract_analysis); @@ -262,13 +297,13 @@ pub trait TransactionConnection: ClarityConnection { Ok(_) => { let result = db .commit() - .map_err(|e| CheckErrors::Expects(format!("{e:?}")).into()); + .map_err(|e| CheckErrorKind::Expects(format!("{e:?}")).into()); (cost_tracker, result) } Err(e) => { let result = db .roll_back() - .map_err(|e| CheckErrors::Expects(format!("{e:?}")).into()); + .map_err(|e| CheckErrorKind::Expects(format!("{e:?}")).into()); if result.is_err() { (cost_tracker, result) } else { @@ -287,12 +322,12 @@ pub trait TransactionConnection: ClarityConnection { to: &PrincipalData, amount: u128, memo: &BuffData, - ) -> Result<(Value, AssetMap, Vec), Error> { + ) -> Result<(Value, AssetMap, Vec), ClarityError> { self.with_abort_callback( |vm_env| { vm_env .stx_transfer(from, to, amount, memo) - .map_err(Error::from) + .map_err(ClarityError::from) }, |_, _| None, ) @@ -314,7 +349,7 @@ pub trait TransactionConnection: ClarityConnection { args: &[Value], abort_call_back: F, max_execution_time: Option, - ) -> Result<(Value, AssetMap, Vec), Error> + ) -> Result<(Value, AssetMap, Vec), ClarityError> where F: FnOnce(&AssetMap, &mut ClarityDatabase) -> Option, { @@ -338,13 +373,13 @@ pub trait TransactionConnection: ClarityConnection { public_function, &expr_args, ) - .map_err(Error::from) + .map_err(ClarityError::from) }, abort_call_back, ) .and_then(|(value, assets_modified, tx_events, reason)| { if let Some(reason) = reason { - Err(Error::AbortedByCallback { + Err(ClarityError::AbortedByCallback { output: Some(Box::new(value)), assets_modified: Box::new(assets_modified), tx_events, @@ -371,7 +406,7 @@ pub trait TransactionConnection: ClarityConnection { sponsor: Option, abort_call_back: F, max_execution_time: Option, - ) -> Result<(AssetMap, Vec), Error> + ) -> Result<(AssetMap, Vec), ClarityError> where F: FnOnce(&AssetMap, &mut ClarityDatabase) -> Option, { @@ -390,12 +425,12 @@ pub trait TransactionConnection: ClarityConnection { contract_str, sponsor, ) - .map_err(Error::from) + .map_err(ClarityError::from) }, abort_call_back, )?; if let Some(reason) = reason { - Err(Error::AbortedByCallback { + Err(ClarityError::AbortedByCallback { output: None, assets_modified: Box::new(assets_modified), tx_events, diff --git a/clarity/src/vm/contexts.rs b/clarity/src/vm/contexts.rs index 8d26da204b2..e0d664a0cf9 100644 --- a/clarity/src/vm/contexts.rs +++ b/clarity/src/vm/contexts.rs @@ -21,6 +21,7 @@ use std::time::{Duration, Instant}; pub use clarity_types::errors::StackTrace; use clarity_types::representations::ClarityName; +use clarity_types::VmExecutionError; use serde::Serialize; use serde_json::json; use stacks_common::types::chainstate::StacksBlockId; @@ -36,9 +37,7 @@ use crate::vm::database::{ ClarityDatabase, DataMapMetadata, DataVariableMetadata, FungibleTokenMetadata, NonFungibleTokenMetadata, }; -use crate::vm::errors::{ - CheckErrors, InterpreterError, InterpreterResult as Result, RuntimeErrorType, -}; +use crate::vm::errors::{CheckErrorKind, RuntimeError, VmInternalError}; use crate::vm::events::*; use crate::vm::representations::SymbolicExpression; use crate::vm::types::signatures::FunctionSignature; @@ -50,6 +49,7 @@ use crate::vm::version::ClarityVersion; use crate::vm::{ast, eval, is_reserved, stx_transfer_consolidated}; pub const MAX_CONTEXT_DEPTH: u16 = 256; +pub const MAX_EVENTS_BATCH: u64 = 50 * 1024 * 1024; // TODO: // hide the environment's instance variables. @@ -221,7 +221,7 @@ pub enum ExecutionTimeTracker { */ pub struct GlobalContext<'a, 'hooks> { asset_maps: Vec, - pub event_batches: Vec, + pub event_batches: Vec<(EventBatch, u64)>, pub database: ClarityDatabase<'a>, read_only: Vec, pub cost_track: LimitedCostTracker, @@ -288,19 +288,27 @@ impl AssetMap { } // This will get the next amount for a (principal, stx) entry in the stx table. - fn get_next_stx_amount(&self, principal: &PrincipalData, amount: u128) -> Result { + fn get_next_stx_amount( + &self, + principal: &PrincipalData, + amount: u128, + ) -> Result { let current_amount = self.stx_map.get(principal).unwrap_or(&0); current_amount .checked_add(amount) - .ok_or(RuntimeErrorType::ArithmeticOverflow.into()) + .ok_or(RuntimeError::ArithmeticOverflow.into()) } // This will get the next amount for a (principal, stx) entry in the burn table. - fn get_next_stx_burn_amount(&self, principal: &PrincipalData, amount: u128) -> Result { + fn get_next_stx_burn_amount( + &self, + principal: &PrincipalData, + amount: u128, + ) -> Result { let current_amount = self.burn_map.get(principal).unwrap_or(&0); current_amount .checked_add(amount) - .ok_or(RuntimeErrorType::ArithmeticOverflow.into()) + .ok_or(RuntimeError::ArithmeticOverflow.into()) } // This will get the next amount for a (principal, asset) entry in the asset table. @@ -309,7 +317,7 @@ impl AssetMap { principal: &PrincipalData, asset: &AssetIdentifier, amount: u128, - ) -> Result { + ) -> Result { let current_amount = self .token_map .get(principal) @@ -317,17 +325,25 @@ impl AssetMap { .unwrap_or(&0); current_amount .checked_add(amount) - .ok_or(RuntimeErrorType::ArithmeticOverflow.into()) + .ok_or(RuntimeError::ArithmeticOverflow.into()) } - pub fn add_stx_transfer(&mut self, principal: &PrincipalData, amount: u128) -> Result<()> { + pub fn add_stx_transfer( + &mut self, + principal: &PrincipalData, + amount: u128, + ) -> Result<(), VmExecutionError> { let next_amount = self.get_next_stx_amount(principal, amount)?; self.stx_map.insert(principal.clone(), next_amount); Ok(()) } - pub fn add_stx_burn(&mut self, principal: &PrincipalData, amount: u128) -> Result<()> { + pub fn add_stx_burn( + &mut self, + principal: &PrincipalData, + amount: u128, + ) -> Result<(), VmExecutionError> { let next_amount = self.get_next_stx_burn_amount(principal, amount)?; self.burn_map.insert(principal.clone(), next_amount); @@ -354,7 +370,7 @@ impl AssetMap { principal: &PrincipalData, asset: AssetIdentifier, amount: u128, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let next_amount = self.get_next_amount(principal, &asset, amount)?; let principal_map = self.token_map.entry(principal.clone()).or_default(); @@ -372,7 +388,7 @@ impl AssetMap { // This will add any asset transfer data from other to self, // aborting _all_ changes in the event of an error, leaving self unchanged - pub fn commit_other(&mut self, mut other: AssetMap) -> Result<()> { + pub fn commit_other(&mut self, mut other: AssetMap) -> Result<(), VmExecutionError> { let mut to_add = Vec::new(); let mut stx_to_add = Vec::with_capacity(other.stx_map.len()); let mut stx_burn_to_add = Vec::with_capacity(other.burn_map.len()); @@ -467,12 +483,12 @@ impl AssetMap { self.burn_map.get(principal).copied() } - pub fn get_stx_burned_total(&self) -> Result { + pub fn get_stx_burned_total(&self) -> Result { let mut total: u128 = 0; for principal in self.burn_map.keys() { total = total .checked_add(*self.burn_map.get(principal).unwrap_or(&0u128)) - .ok_or_else(|| InterpreterError::Expect("BURN OVERFLOW".into()))?; + .ok_or_else(|| VmInternalError::Expect("BURN OVERFLOW".into()))?; } Ok(total) } @@ -656,7 +672,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { f: F, ) -> std::result::Result<(A, AssetMap, Vec), E> where - E: From, + E: From, F: FnOnce(&mut Environment) -> std::result::Result, { assert!(self.context.is_top_level()); @@ -691,7 +707,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { contract_identifier: QualifiedContractIdentifier, contract_content: &str, sponsor: Option, - ) -> Result<((), AssetMap, Vec)> { + ) -> Result<((), AssetMap, Vec), VmExecutionError> { self.execute_in_env( contract_identifier.issuer.clone().into(), sponsor, @@ -706,7 +722,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { version: ClarityVersion, contract_content: &str, sponsor: Option, - ) -> Result<((), AssetMap, Vec)> { + ) -> Result<((), AssetMap, Vec), VmExecutionError> { self.execute_in_env( contract_identifier.issuer.clone().into(), sponsor, @@ -725,7 +741,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { contract_content: &ContractAST, contract_string: &str, sponsor: Option, - ) -> Result<((), AssetMap, Vec)> { + ) -> Result<((), AssetMap, Vec), VmExecutionError> { self.execute_in_env( contract_identifier.issuer.clone().into(), sponsor, @@ -751,7 +767,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { contract_identifier: QualifiedContractIdentifier, tx_name: &str, args: &[SymbolicExpression], - ) -> Result<(Value, AssetMap, Vec)> { + ) -> Result<(Value, AssetMap, Vec), VmExecutionError> { self.execute_in_env(sender, sponsor, None, |exec_env| { exec_env.execute_contract(&contract_identifier, tx_name, args, false) }) @@ -763,7 +779,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { to: &PrincipalData, amount: u128, memo: &BuffData, - ) -> Result<(Value, AssetMap, Vec)> { + ) -> Result<(Value, AssetMap, Vec), VmExecutionError> { self.execute_in_env(from.clone(), None, None, |exec_env| { exec_env.stx_transfer(from, to, amount, memo) }) @@ -775,29 +791,24 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { #[cfg(any(test, feature = "testing"))] pub fn stx_faucet(&mut self, recipient: &PrincipalData, amount: u128) { - self.execute_in_env::<_, _, crate::vm::errors::Error>( - recipient.clone(), - None, - None, - |env| { - let mut snapshot = env - .global_context - .database - .get_stx_balance_snapshot(recipient) - .unwrap(); + self.execute_in_env::<_, _, VmExecutionError>(recipient.clone(), None, None, |env| { + let mut snapshot = env + .global_context + .database + .get_stx_balance_snapshot(recipient) + .unwrap(); - snapshot.credit(amount).unwrap(); - snapshot.save().unwrap(); + snapshot.credit(amount).unwrap(); + snapshot.save().unwrap(); - env.global_context - .database - .increment_ustx_liquid_supply(amount) - .unwrap(); + env.global_context + .database + .increment_ustx_liquid_supply(amount) + .unwrap(); - let res: std::result::Result<(), crate::vm::errors::Error> = Ok(()); - res - }, - ) + let res: std::result::Result<(), VmExecutionError> = Ok(()); + res + }) .unwrap(); } @@ -805,7 +816,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { pub fn eval_raw( &mut self, program: &str, - ) -> Result<(Value, AssetMap, Vec)> { + ) -> Result<(Value, AssetMap, Vec), VmExecutionError> { self.execute_in_env( QualifiedContractIdentifier::transient().issuer.into(), None, @@ -818,7 +829,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { &mut self, contract: &QualifiedContractIdentifier, program: &str, - ) -> Result<(Value, AssetMap, Vec)> { + ) -> Result<(Value, AssetMap, Vec), VmExecutionError> { self.execute_in_env( QualifiedContractIdentifier::transient().issuer.into(), None, @@ -831,10 +842,10 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { self.context.begin(); } - pub fn commit(&mut self) -> Result<(AssetMap, EventBatch)> { + pub fn commit(&mut self) -> Result<(AssetMap, EventBatch), VmExecutionError> { let (asset_map, event_batch) = self.context.commit()?; - let asset_map = asset_map.ok_or(InterpreterError::FailedToConstructAssetTable)?; - let event_batch = event_batch.ok_or(InterpreterError::FailedToConstructEventBatch)?; + let asset_map = asset_map.ok_or(VmInternalError::FailedToConstructAssetTable)?; + let event_batch = event_batch.ok_or(VmInternalError::FailedToConstructEventBatch)?; Ok((asset_map, event_batch)) } @@ -988,7 +999,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { &mut self, contract_identifier: &QualifiedContractIdentifier, program: &str, - ) -> Result { + ) -> Result { let clarity_version = self.contract_context.clarity_version; let parsed = ast::build_ast( @@ -1001,7 +1012,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { .expressions; if parsed.is_empty() { - return Err(RuntimeErrorType::ParseError( + return Err(RuntimeError::TypeParseFailure( "Expected a program of at least length 1".to_string(), ) .into()); @@ -1036,7 +1047,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { result } - pub fn eval_raw(&mut self, program: &str) -> Result { + pub fn eval_raw(&mut self, program: &str) -> Result { let contract_id = QualifiedContractIdentifier::transient(); let clarity_version = self.contract_context.clarity_version; @@ -1050,7 +1061,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { .expressions; if parsed.is_empty() { - return Err(RuntimeErrorType::ParseError( + return Err(RuntimeError::TypeParseFailure( "Expected a program of at least length 1".to_string(), ) .into()); @@ -1091,7 +1102,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { tx_name: &str, args: &[SymbolicExpression], read_only: bool, - ) -> Result { + ) -> Result { self.inner_execute_contract(contract, tx_name, args, read_only, false) } @@ -1104,7 +1115,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { tx_name: &str, args: &[SymbolicExpression], read_only: bool, - ) -> Result { + ) -> Result { self.inner_execute_contract(contract, tx_name, args, read_only, true) } @@ -1121,7 +1132,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { args: &[SymbolicExpression], read_only: bool, allow_private: bool, - ) -> Result { + ) -> Result { let contract_size = self .global_context .database @@ -1134,17 +1145,17 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { let contract = self.global_context.database.get_contract(contract_identifier)?; let func = contract.contract_context.lookup_function(tx_name) - .ok_or_else(|| { CheckErrors::UndefinedFunction(tx_name.to_string()) })?; + .ok_or_else(|| { CheckErrorKind::UndefinedFunction(tx_name.to_string()) })?; if !allow_private && !func.is_public() { - return Err(CheckErrors::NoSuchPublicFunction(contract_identifier.to_string(), tx_name.to_string()).into()); + return Err(CheckErrorKind::NoSuchPublicFunction(contract_identifier.to_string(), tx_name.to_string()).into()); } else if read_only && !func.is_read_only() { - return Err(CheckErrors::PublicFunctionNotReadOnly(contract_identifier.to_string(), tx_name.to_string()).into()); + return Err(CheckErrorKind::PublicFunctionNotReadOnly(contract_identifier.to_string(), tx_name.to_string()).into()); } - let args: Result> = args.iter() + let args: Result, VmExecutionError> = args.iter() .map(|arg| { let value = arg.match_atom_value() - .ok_or_else(|| InterpreterError::InterpreterError(format!("Passed non-value expression to exec_tx on {tx_name}!")))?; + .ok_or_else(|| VmInternalError::InvariantViolation(format!("Passed non-value expression to exec_tx on {tx_name}!")))?; // sanitize contract-call inputs in epochs >= 2.4 // testing todo: ensure sanitize_value() preserves trait callability! let expected_type = TypeSignature::type_of(value)?; @@ -1152,7 +1163,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { self.epoch(), &expected_type, value.clone(), - ).ok_or_else(|| CheckErrors::TypeValueError( + ).ok_or_else(|| CheckErrorKind::TypeValueError( Box::new(expected_type), Box::new(value.clone()), ) @@ -1166,7 +1177,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { let func_identifier = func.get_identifier(); if self.call_stack.contains(&func_identifier) { - return Err(CheckErrors::CircularReference(vec![func_identifier.to_string()]).into()) + return Err(CheckErrorKind::CircularReference(vec![func_identifier.to_string()]).into()) } self.call_stack.insert(&func_identifier, true); let res = self.execute_function_as_transaction(&func, &args, Some(&contract.contract_context), allow_private); @@ -1198,7 +1209,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { args: &[Value], next_contract_context: Option<&ContractContext>, allow_private: bool, - ) -> Result { + ) -> Result { let make_read_only = function.is_read_only(); if make_read_only { @@ -1235,7 +1246,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { bhh: StacksBlockId, closure: &SymbolicExpression, local: &LocalContext, - ) -> Result { + ) -> Result { self.global_context.begin_read_only(); let result = self @@ -1248,7 +1259,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { .database .set_block_hash(prior_bhh, true) .map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "ERROR: Failed to restore prior active block after time-shifted evaluation." .into()) })?; @@ -1264,7 +1275,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { &mut self, contract_identifier: QualifiedContractIdentifier, contract_content: &str, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let clarity_version = self.contract_context.clarity_version; let contract_ast = ast::build_ast( @@ -1288,7 +1299,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { contract_version: ClarityVersion, contract_content: &ContractAST, contract_string: &str, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { self.global_context.begin(); // wrap in a closure so that `?` can be caught and the global_context can roll_back() @@ -1306,7 +1317,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { .has_contract(&contract_identifier) { return Err( - CheckErrors::ContractAlreadyExists(contract_identifier.to_string()).into(), + CheckErrorKind::ContractAlreadyExists(contract_identifier.to_string()).into(), ); } @@ -1360,7 +1371,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { to: &PrincipalData, amount: u128, memo: &BuffData, - ) -> Result { + ) -> Result { self.global_context.begin(); let result = stx_transfer_consolidated(self, from, to, amount, memo); match result { @@ -1371,7 +1382,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { } Err(_) => { self.global_context.roll_back()?; - Err(InterpreterError::InsufficientBalance.into()) + Err(VmInternalError::InsufficientBalance.into()) } }, Err(e) => { @@ -1384,7 +1395,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { pub fn run_as_transaction(&mut self, f: F) -> std::result::Result where F: FnOnce(&mut Self) -> std::result::Result, - E: From, + E: From, { self.global_context.begin(); let result = f(self); @@ -1400,10 +1411,28 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { } } - pub fn push_to_event_batch(&mut self, event: StacksTransactionEvent) { - if let Some(batch) = self.global_context.event_batches.last_mut() { + fn push_to_event_batch( + &mut self, + event: StacksTransactionEvent, + ) -> Result<(), VmExecutionError> { + let size = if let StacksTransactionEvent::SmartContractEvent(ref ev) = event { + ev.value.size().map_err(|e| { + VmInternalError::Expect(format!("Could not calculate event size: {e}")) + })? + } else { + 0 + }; + if let Some((batch, total_size)) = self.global_context.event_batches.last_mut() { batch.events.push(event); + *total_size = total_size.saturating_add(size.into()); + if *total_size >= MAX_EVENTS_BATCH { + return Err(VmInternalError::Expect(format!( + "Event batch grew too large during execution" + )) + .into()); + } } + Ok(()) } pub fn construct_print_transaction_event( @@ -1418,13 +1447,13 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { StacksTransactionEvent::SmartContractEvent(print_event) } - pub fn register_print_event(&mut self, value: Value) -> Result<()> { + pub fn register_print_event(&mut self, value: Value) -> Result<(), VmExecutionError> { let event = Self::construct_print_transaction_event( &self.contract_context.contract_identifier, &value, ); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } @@ -1434,7 +1463,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { recipient: PrincipalData, amount: u128, memo: BuffData, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let event_data = STXTransferEventData { sender, recipient, @@ -1443,15 +1472,19 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { }; let event = StacksTransactionEvent::STXEvent(STXEventType::STXTransferEvent(event_data)); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } - pub fn register_stx_burn_event(&mut self, sender: PrincipalData, amount: u128) -> Result<()> { + pub fn register_stx_burn_event( + &mut self, + sender: PrincipalData, + amount: u128, + ) -> Result<(), VmExecutionError> { let event_data = STXBurnEventData { sender, amount }; let event = StacksTransactionEvent::STXEvent(STXEventType::STXBurnEvent(event_data)); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } @@ -1461,7 +1494,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { recipient: PrincipalData, value: Value, asset_identifier: AssetIdentifier, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let event_data = NFTTransferEventData { sender, recipient, @@ -1470,7 +1503,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { }; let event = StacksTransactionEvent::NFTEvent(NFTEventType::NFTTransferEvent(event_data)); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } @@ -1479,7 +1512,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { recipient: PrincipalData, value: Value, asset_identifier: AssetIdentifier, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let event_data = NFTMintEventData { recipient, asset_identifier, @@ -1487,7 +1520,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { }; let event = StacksTransactionEvent::NFTEvent(NFTEventType::NFTMintEvent(event_data)); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } @@ -1496,7 +1529,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { sender: PrincipalData, value: Value, asset_identifier: AssetIdentifier, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let event_data = NFTBurnEventData { sender, asset_identifier, @@ -1504,7 +1537,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { }; let event = StacksTransactionEvent::NFTEvent(NFTEventType::NFTBurnEvent(event_data)); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } @@ -1514,7 +1547,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { recipient: PrincipalData, amount: u128, asset_identifier: AssetIdentifier, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let event_data = FTTransferEventData { sender, recipient, @@ -1523,7 +1556,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { }; let event = StacksTransactionEvent::FTEvent(FTEventType::FTTransferEvent(event_data)); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } @@ -1532,7 +1565,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { recipient: PrincipalData, amount: u128, asset_identifier: AssetIdentifier, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let event_data = FTMintEventData { recipient, asset_identifier, @@ -1540,7 +1573,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { }; let event = StacksTransactionEvent::FTEvent(FTEventType::FTMintEvent(event_data)); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } @@ -1549,7 +1582,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { sender: PrincipalData, amount: u128, asset_identifier: AssetIdentifier, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let event_data = FTBurnEventData { sender, asset_identifier, @@ -1557,7 +1590,7 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { }; let event = StacksTransactionEvent::FTEvent(FTEventType::FTBurnEvent(event_data)); - self.push_to_event_batch(event); + self.push_to_event_batch(event)?; Ok(()) } } @@ -1596,16 +1629,16 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { } } - fn get_asset_map(&mut self) -> Result<&mut AssetMap> { + fn get_asset_map(&mut self) -> Result<&mut AssetMap, VmExecutionError> { self.asset_maps .last_mut() - .ok_or_else(|| InterpreterError::Expect("Failed to obtain asset map".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to obtain asset map".into()).into()) } - pub fn get_readonly_asset_map(&mut self) -> Result<&AssetMap> { + pub fn get_readonly_asset_map(&mut self) -> Result<&AssetMap, VmExecutionError> { self.asset_maps .last() - .ok_or_else(|| InterpreterError::Expect("Failed to obtain asset map".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to obtain asset map".into()).into()) } pub fn log_asset_transfer( @@ -1614,7 +1647,7 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { contract_identifier: &QualifiedContractIdentifier, asset_name: &ClarityName, transfered: Value, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let asset_identifier = AssetIdentifier { contract_identifier: contract_identifier.clone(), asset_name: asset_name.clone(), @@ -1630,7 +1663,7 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { contract_identifier: &QualifiedContractIdentifier, asset_name: &ClarityName, transfered: u128, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let asset_identifier = AssetIdentifier { contract_identifier: contract_identifier.clone(), asset_name: asset_name.clone(), @@ -1639,22 +1672,34 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { .add_token_transfer(sender, asset_identifier, transfered) } - pub fn log_stx_transfer(&mut self, sender: &PrincipalData, transfered: u128) -> Result<()> { + pub fn log_stx_transfer( + &mut self, + sender: &PrincipalData, + transfered: u128, + ) -> Result<(), VmExecutionError> { self.get_asset_map()?.add_stx_transfer(sender, transfered) } - pub fn log_stx_burn(&mut self, sender: &PrincipalData, transfered: u128) -> Result<()> { + pub fn log_stx_burn( + &mut self, + sender: &PrincipalData, + transfered: u128, + ) -> Result<(), VmExecutionError> { self.get_asset_map()?.add_stx_burn(sender, transfered) } - pub fn log_stacking(&mut self, sender: &PrincipalData, amount: u128) -> Result<()> { + pub fn log_stacking( + &mut self, + sender: &PrincipalData, + amount: u128, + ) -> Result<(), VmExecutionError> { self.get_asset_map()?.add_stacking(sender, amount); Ok(()) } - pub fn execute(&mut self, f: F) -> Result + pub fn execute(&mut self, f: F) -> Result where - F: FnOnce(&mut Self) -> Result, + F: FnOnce(&mut Self) -> Result, { self.begin(); let result = f(self).or_else(|e| { @@ -1676,7 +1721,7 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { f: F, ) -> std::result::Result where - E: From, + E: From, F: FnOnce(&mut Environment) -> std::result::Result, { self.begin(); @@ -1710,7 +1755,12 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { pub fn begin(&mut self) { self.asset_maps.push(AssetMap::new()); - self.event_batches.push(EventBatch::new()); + let total_size = self + .event_batches + .last() + .map(|(_, total_size)| *total_size) + .unwrap_or(0); + self.event_batches.push((EventBatch::new(), total_size)); self.database.begin(); let read_only = self.is_read_only(); self.read_only.push(read_only); @@ -1718,19 +1768,24 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { pub fn begin_read_only(&mut self) { self.asset_maps.push(AssetMap::new()); - self.event_batches.push(EventBatch::new()); + let total_size = self + .event_batches + .last() + .map(|(_, total_size)| *total_size) + .unwrap_or(0); + self.event_batches.push((EventBatch::new(), total_size)); self.database.begin(); self.read_only.push(true); } - pub fn commit(&mut self) -> Result<(Option, Option)> { + pub fn commit(&mut self) -> Result<(Option, Option), VmExecutionError> { trace!("Calling commit"); self.read_only.pop(); let asset_map = self.asset_maps.pop().ok_or_else(|| { - InterpreterError::Expect("ERROR: Committed non-nested context.".into()) + VmInternalError::Expect("ERROR: Committed non-nested context.".into()) })?; - let mut event_batch = self.event_batches.pop().ok_or_else(|| { - InterpreterError::Expect("ERROR: Committed non-nested context.".into()) + let (mut event_batch, new_total_size) = self.event_batches.pop().ok_or_else(|| { + VmInternalError::Expect("ERROR: Committed non-nested context.".into()) })?; let out_map = match self.asset_maps.last_mut() { @@ -1745,8 +1800,9 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { }; let out_batch = match self.event_batches.last_mut() { - Some(tail_back) => { + Some((tail_back, total_size)) => { tail_back.events.append(&mut event_batch.events); + *total_size = new_total_size; None } None => Some(event_batch), @@ -1756,18 +1812,18 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { Ok((out_map, out_batch)) } - pub fn roll_back(&mut self) -> Result<()> { + pub fn roll_back(&mut self) -> Result<(), VmExecutionError> { let popped = self.asset_maps.pop(); if popped.is_none() { - return Err(InterpreterError::Expect("Expected entry to rollback".into()).into()); + return Err(VmInternalError::Expect("Expected entry to rollback".into()).into()); } let popped = self.read_only.pop(); if popped.is_none() { - return Err(InterpreterError::Expect("Expected entry to rollback".into()).into()); + return Err(VmInternalError::Expect("Expected entry to rollback".into()).into()); } let popped = self.event_batches.pop(); if popped.is_none() { - return Err(InterpreterError::Expect("Expected entry to rollback".into()).into()); + return Err(VmInternalError::Expect("Expected entry to rollback".into()).into()); } self.database.roll_back() @@ -1778,9 +1834,9 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { // clarity = { version = "*", features = ["devtools"] } pub fn handle_tx_result( &mut self, - result: Result, + result: Result, allow_private: bool, - ) -> Result { + ) -> Result { if let Ok(result) = result { if let Value::Response(data) = result { if data.committed { @@ -1793,7 +1849,7 @@ impl<'a, 'hooks> GlobalContext<'a, 'hooks> { self.commit()?; Ok(result) } else { - Err(CheckErrors::PublicFunctionMustReturnResponse(Box::new( + Err(CheckErrorKind::PublicFunctionMustReturnResponse(Box::new( TypeSignature::type_of(&result)?, )) .into()) @@ -1912,9 +1968,9 @@ impl<'a> LocalContext<'a> { } } - pub fn extend(&'a self) -> Result> { + pub fn extend(&'a self) -> Result, VmExecutionError> { if self.depth >= MAX_CONTEXT_DEPTH { - Err(RuntimeErrorType::MaxContextDepthReached.into()) + Err(RuntimeError::MaxContextDepthReached.into()) } else { Ok(LocalContext { function_context: Some(self.function_context()), @@ -1985,23 +2041,27 @@ impl CallStack { self.apply_depth -= 1; } - pub fn remove(&mut self, function: &FunctionIdentifier, tracked: bool) -> Result<()> { + pub fn remove( + &mut self, + function: &FunctionIdentifier, + tracked: bool, + ) -> Result<(), VmExecutionError> { if let Some(removed) = self.stack.pop() { if removed != *function { - return Err(InterpreterError::InterpreterError( + return Err(VmInternalError::InvariantViolation( "Tried to remove item from empty call stack.".to_string(), ) .into()); } if tracked && !self.set.remove(function) { - return Err(InterpreterError::InterpreterError( + return Err(VmInternalError::InvariantViolation( "Tried to remove tracked function from call stack, but could not find in current context.".into() ) .into()); } Ok(()) } else { - Err(InterpreterError::InterpreterError( + Err(VmInternalError::InvariantViolation( "Tried to remove item from empty call stack.".to_string(), ) .into()) @@ -2202,7 +2262,7 @@ mod test { &BuffData::empty(), ) .unwrap_err(); - assert_eq!(e.to_string(), "Interpreter(InsufficientBalance)"); + assert_eq!(e.to_string(), "Internal(InsufficientBalance)"); } #[test] diff --git a/clarity/src/vm/contracts.rs b/clarity/src/vm/contracts.rs index 17493a978f8..23c0ecdd6d4 100644 --- a/clarity/src/vm/contracts.rs +++ b/clarity/src/vm/contracts.rs @@ -18,7 +18,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::ast::ContractAST; use crate::vm::contexts::{ContractContext, GlobalContext}; -use crate::vm::errors::InterpreterResult as Result; +use crate::vm::errors::VmExecutionError; use crate::vm::eval_all; use crate::vm::types::{PrincipalData, QualifiedContractIdentifier}; use crate::vm::version::ClarityVersion; @@ -37,7 +37,7 @@ impl Contract { sponsor: Option, global_context: &mut GlobalContext, version: ClarityVersion, - ) -> Result { + ) -> Result { let mut contract_context = ContractContext::new(contract_identifier, version); eval_all( diff --git a/clarity/src/vm/costs/cost_functions.rs b/clarity/src/vm/costs/cost_functions.rs index b51179e2ea8..0f59e92232d 100644 --- a/clarity/src/vm/costs/cost_functions.rs +++ b/clarity/src/vm/costs/cost_functions.rs @@ -13,9 +13,8 @@ // // You should have received a copy of the GNU General Public License // along with this program. If not, see . - use super::ExecutionCost; -use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; +use crate::vm::errors::{RuntimeError, VmExecutionError}; define_named_enum!(ClarityCostFunction { AnalysisTypeAnnotate("cost_analysis_type_annotate"), @@ -170,20 +169,20 @@ define_named_enum!(ClarityCostFunction { pub fn linear(n: u64, a: u64, b: u64) -> u64 { a.saturating_mul(n).saturating_add(b) } -pub fn logn(n: u64, a: u64, b: u64) -> InterpreterResult { +pub fn logn(n: u64, a: u64, b: u64) -> Result { if n < 1 { - return Err(crate::vm::errors::Error::Runtime( - RuntimeErrorType::Arithmetic("log2 must be passed a positive integer".to_string()), + return Err(VmExecutionError::Runtime( + RuntimeError::Arithmetic("log2 must be passed a positive integer".to_string()), Some(vec![]), )); } let nlog2 = u64::from(64 - 1 - n.leading_zeros()); Ok(a.saturating_mul(nlog2).saturating_add(b)) } -pub fn nlogn(n: u64, a: u64, b: u64) -> InterpreterResult { +pub fn nlogn(n: u64, a: u64, b: u64) -> Result { if n < 1 { - return Err(crate::vm::errors::Error::Runtime( - RuntimeErrorType::Arithmetic("log2 must be passed a positive integer".to_string()), + return Err(VmExecutionError::Runtime( + RuntimeError::Arithmetic("log2 must be passed a positive integer".to_string()), Some(vec![]), )); } @@ -192,154 +191,154 @@ pub fn nlogn(n: u64, a: u64, b: u64) -> InterpreterResult { } pub trait CostValues { - fn cost_analysis_type_annotate(n: u64) -> InterpreterResult; - fn cost_analysis_type_check(n: u64) -> InterpreterResult; - fn cost_analysis_type_lookup(n: u64) -> InterpreterResult; - fn cost_analysis_visit(n: u64) -> InterpreterResult; - fn cost_analysis_iterable_func(n: u64) -> InterpreterResult; - fn cost_analysis_option_cons(n: u64) -> InterpreterResult; - fn cost_analysis_option_check(n: u64) -> InterpreterResult; - fn cost_analysis_bind_name(n: u64) -> InterpreterResult; - fn cost_analysis_list_items_check(n: u64) -> InterpreterResult; - fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult; - fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult; - fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult; - fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult; - fn cost_analysis_check_let(n: u64) -> InterpreterResult; - fn cost_analysis_lookup_function(n: u64) -> InterpreterResult; - fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult; - fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult; - fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult; - fn cost_ast_parse(n: u64) -> InterpreterResult; - fn cost_ast_cycle_detection(n: u64) -> InterpreterResult; - fn cost_analysis_storage(n: u64) -> InterpreterResult; - fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult; - fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult; - fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult; - fn cost_lookup_variable_depth(n: u64) -> InterpreterResult; - fn cost_lookup_variable_size(n: u64) -> InterpreterResult; - fn cost_lookup_function(n: u64) -> InterpreterResult; - fn cost_bind_name(n: u64) -> InterpreterResult; - fn cost_inner_type_check_cost(n: u64) -> InterpreterResult; - fn cost_user_function_application(n: u64) -> InterpreterResult; - fn cost_let(n: u64) -> InterpreterResult; - fn cost_if(n: u64) -> InterpreterResult; - fn cost_asserts(n: u64) -> InterpreterResult; - fn cost_map(n: u64) -> InterpreterResult; - fn cost_filter(n: u64) -> InterpreterResult; - fn cost_len(n: u64) -> InterpreterResult; - fn cost_element_at(n: u64) -> InterpreterResult; - fn cost_index_of(n: u64) -> InterpreterResult; - fn cost_fold(n: u64) -> InterpreterResult; - fn cost_list_cons(n: u64) -> InterpreterResult; - fn cost_type_parse_step(n: u64) -> InterpreterResult; - fn cost_tuple_get(n: u64) -> InterpreterResult; - fn cost_tuple_merge(n: u64) -> InterpreterResult; - fn cost_tuple_cons(n: u64) -> InterpreterResult; - fn cost_add(n: u64) -> InterpreterResult; - fn cost_sub(n: u64) -> InterpreterResult; - fn cost_mul(n: u64) -> InterpreterResult; - fn cost_div(n: u64) -> InterpreterResult; - fn cost_geq(n: u64) -> InterpreterResult; - fn cost_leq(n: u64) -> InterpreterResult; - fn cost_le(n: u64) -> InterpreterResult; - fn cost_ge(n: u64) -> InterpreterResult; - fn cost_int_cast(n: u64) -> InterpreterResult; - fn cost_mod(n: u64) -> InterpreterResult; - fn cost_pow(n: u64) -> InterpreterResult; - fn cost_sqrti(n: u64) -> InterpreterResult; - fn cost_log2(n: u64) -> InterpreterResult; - fn cost_xor(n: u64) -> InterpreterResult; - fn cost_not(n: u64) -> InterpreterResult; - fn cost_eq(n: u64) -> InterpreterResult; - fn cost_begin(n: u64) -> InterpreterResult; - fn cost_hash160(n: u64) -> InterpreterResult; - fn cost_sha256(n: u64) -> InterpreterResult; - fn cost_sha512(n: u64) -> InterpreterResult; - fn cost_sha512t256(n: u64) -> InterpreterResult; - fn cost_keccak256(n: u64) -> InterpreterResult; - fn cost_secp256k1recover(n: u64) -> InterpreterResult; - fn cost_secp256k1verify(n: u64) -> InterpreterResult; - fn cost_print(n: u64) -> InterpreterResult; - fn cost_some_cons(n: u64) -> InterpreterResult; - fn cost_ok_cons(n: u64) -> InterpreterResult; - fn cost_err_cons(n: u64) -> InterpreterResult; - fn cost_default_to(n: u64) -> InterpreterResult; - fn cost_unwrap_ret(n: u64) -> InterpreterResult; - fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult; - fn cost_is_okay(n: u64) -> InterpreterResult; - fn cost_is_none(n: u64) -> InterpreterResult; - fn cost_is_err(n: u64) -> InterpreterResult; - fn cost_is_some(n: u64) -> InterpreterResult; - fn cost_unwrap(n: u64) -> InterpreterResult; - fn cost_unwrap_err(n: u64) -> InterpreterResult; - fn cost_try_ret(n: u64) -> InterpreterResult; - fn cost_match(n: u64) -> InterpreterResult; - fn cost_or(n: u64) -> InterpreterResult; - fn cost_and(n: u64) -> InterpreterResult; - fn cost_append(n: u64) -> InterpreterResult; - fn cost_concat(n: u64) -> InterpreterResult; - fn cost_as_max_len(n: u64) -> InterpreterResult; - fn cost_contract_call(n: u64) -> InterpreterResult; - fn cost_contract_of(n: u64) -> InterpreterResult; - fn cost_principal_of(n: u64) -> InterpreterResult; - fn cost_at_block(n: u64) -> InterpreterResult; - fn cost_load_contract(n: u64) -> InterpreterResult; - fn cost_create_map(n: u64) -> InterpreterResult; - fn cost_create_var(n: u64) -> InterpreterResult; - fn cost_create_nft(n: u64) -> InterpreterResult; - fn cost_create_ft(n: u64) -> InterpreterResult; - fn cost_fetch_entry(n: u64) -> InterpreterResult; - fn cost_set_entry(n: u64) -> InterpreterResult; - fn cost_fetch_var(n: u64) -> InterpreterResult; - fn cost_set_var(n: u64) -> InterpreterResult; - fn cost_contract_storage(n: u64) -> InterpreterResult; - fn cost_block_info(n: u64) -> InterpreterResult; - fn cost_stx_balance(n: u64) -> InterpreterResult; - fn cost_stx_transfer(n: u64) -> InterpreterResult; - fn cost_ft_mint(n: u64) -> InterpreterResult; - fn cost_ft_transfer(n: u64) -> InterpreterResult; - fn cost_ft_balance(n: u64) -> InterpreterResult; - fn cost_ft_get_supply(n: u64) -> InterpreterResult; - fn cost_ft_burn(n: u64) -> InterpreterResult; - fn cost_nft_mint(n: u64) -> InterpreterResult; - fn cost_nft_transfer(n: u64) -> InterpreterResult; - fn cost_nft_owner(n: u64) -> InterpreterResult; - fn cost_nft_burn(n: u64) -> InterpreterResult; - fn poison_microblock(n: u64) -> InterpreterResult; - fn cost_buff_to_int_le(n: u64) -> InterpreterResult; - fn cost_buff_to_uint_le(n: u64) -> InterpreterResult; - fn cost_buff_to_int_be(n: u64) -> InterpreterResult; - fn cost_buff_to_uint_be(n: u64) -> InterpreterResult; - fn cost_is_standard(n: u64) -> InterpreterResult; - fn cost_principal_destruct(n: u64) -> InterpreterResult; - fn cost_principal_construct(n: u64) -> InterpreterResult; - fn cost_string_to_int(n: u64) -> InterpreterResult; - fn cost_string_to_uint(n: u64) -> InterpreterResult; - fn cost_int_to_ascii(n: u64) -> InterpreterResult; - fn cost_int_to_utf8(n: u64) -> InterpreterResult; - fn cost_burn_block_info(n: u64) -> InterpreterResult; - fn cost_stx_account(n: u64) -> InterpreterResult; - fn cost_slice(n: u64) -> InterpreterResult; - fn cost_to_consensus_buff(n: u64) -> InterpreterResult; - fn cost_from_consensus_buff(n: u64) -> InterpreterResult; - fn cost_stx_transfer_memo(n: u64) -> InterpreterResult; - fn cost_replace_at(n: u64) -> InterpreterResult; - fn cost_as_contract(n: u64) -> InterpreterResult; - fn cost_bitwise_and(n: u64) -> InterpreterResult; - fn cost_bitwise_or(n: u64) -> InterpreterResult; - fn cost_bitwise_not(n: u64) -> InterpreterResult; - fn cost_bitwise_left_shift(n: u64) -> InterpreterResult; - fn cost_bitwise_right_shift(n: u64) -> InterpreterResult; - fn cost_contract_hash(n: u64) -> InterpreterResult; - fn cost_to_ascii(n: u64) -> InterpreterResult; - fn cost_restrict_assets(n: u64) -> InterpreterResult; - fn cost_as_contract_safe(n: u64) -> InterpreterResult; - fn cost_secp256r1verify(n: u64) -> InterpreterResult; + fn cost_analysis_type_annotate(n: u64) -> Result; + fn cost_analysis_type_check(n: u64) -> Result; + fn cost_analysis_type_lookup(n: u64) -> Result; + fn cost_analysis_visit(n: u64) -> Result; + fn cost_analysis_iterable_func(n: u64) -> Result; + fn cost_analysis_option_cons(n: u64) -> Result; + fn cost_analysis_option_check(n: u64) -> Result; + fn cost_analysis_bind_name(n: u64) -> Result; + fn cost_analysis_list_items_check(n: u64) -> Result; + fn cost_analysis_check_tuple_get(n: u64) -> Result; + fn cost_analysis_check_tuple_merge(n: u64) -> Result; + fn cost_analysis_check_tuple_cons(n: u64) -> Result; + fn cost_analysis_tuple_items_check(n: u64) -> Result; + fn cost_analysis_check_let(n: u64) -> Result; + fn cost_analysis_lookup_function(n: u64) -> Result; + fn cost_analysis_lookup_function_types(n: u64) -> Result; + fn cost_analysis_lookup_variable_const(n: u64) -> Result; + fn cost_analysis_lookup_variable_depth(n: u64) -> Result; + fn cost_ast_parse(n: u64) -> Result; + fn cost_ast_cycle_detection(n: u64) -> Result; + fn cost_analysis_storage(n: u64) -> Result; + fn cost_analysis_use_trait_entry(n: u64) -> Result; + fn cost_analysis_get_function_entry(n: u64) -> Result; + fn cost_analysis_fetch_contract_entry(n: u64) -> Result; + fn cost_lookup_variable_depth(n: u64) -> Result; + fn cost_lookup_variable_size(n: u64) -> Result; + fn cost_lookup_function(n: u64) -> Result; + fn cost_bind_name(n: u64) -> Result; + fn cost_inner_type_check_cost(n: u64) -> Result; + fn cost_user_function_application(n: u64) -> Result; + fn cost_let(n: u64) -> Result; + fn cost_if(n: u64) -> Result; + fn cost_asserts(n: u64) -> Result; + fn cost_map(n: u64) -> Result; + fn cost_filter(n: u64) -> Result; + fn cost_len(n: u64) -> Result; + fn cost_element_at(n: u64) -> Result; + fn cost_index_of(n: u64) -> Result; + fn cost_fold(n: u64) -> Result; + fn cost_list_cons(n: u64) -> Result; + fn cost_type_parse_step(n: u64) -> Result; + fn cost_tuple_get(n: u64) -> Result; + fn cost_tuple_merge(n: u64) -> Result; + fn cost_tuple_cons(n: u64) -> Result; + fn cost_add(n: u64) -> Result; + fn cost_sub(n: u64) -> Result; + fn cost_mul(n: u64) -> Result; + fn cost_div(n: u64) -> Result; + fn cost_geq(n: u64) -> Result; + fn cost_leq(n: u64) -> Result; + fn cost_le(n: u64) -> Result; + fn cost_ge(n: u64) -> Result; + fn cost_int_cast(n: u64) -> Result; + fn cost_mod(n: u64) -> Result; + fn cost_pow(n: u64) -> Result; + fn cost_sqrti(n: u64) -> Result; + fn cost_log2(n: u64) -> Result; + fn cost_xor(n: u64) -> Result; + fn cost_not(n: u64) -> Result; + fn cost_eq(n: u64) -> Result; + fn cost_begin(n: u64) -> Result; + fn cost_hash160(n: u64) -> Result; + fn cost_sha256(n: u64) -> Result; + fn cost_sha512(n: u64) -> Result; + fn cost_sha512t256(n: u64) -> Result; + fn cost_keccak256(n: u64) -> Result; + fn cost_secp256k1recover(n: u64) -> Result; + fn cost_secp256k1verify(n: u64) -> Result; + fn cost_print(n: u64) -> Result; + fn cost_some_cons(n: u64) -> Result; + fn cost_ok_cons(n: u64) -> Result; + fn cost_err_cons(n: u64) -> Result; + fn cost_default_to(n: u64) -> Result; + fn cost_unwrap_ret(n: u64) -> Result; + fn cost_unwrap_err_or_ret(n: u64) -> Result; + fn cost_is_okay(n: u64) -> Result; + fn cost_is_none(n: u64) -> Result; + fn cost_is_err(n: u64) -> Result; + fn cost_is_some(n: u64) -> Result; + fn cost_unwrap(n: u64) -> Result; + fn cost_unwrap_err(n: u64) -> Result; + fn cost_try_ret(n: u64) -> Result; + fn cost_match(n: u64) -> Result; + fn cost_or(n: u64) -> Result; + fn cost_and(n: u64) -> Result; + fn cost_append(n: u64) -> Result; + fn cost_concat(n: u64) -> Result; + fn cost_as_max_len(n: u64) -> Result; + fn cost_contract_call(n: u64) -> Result; + fn cost_contract_of(n: u64) -> Result; + fn cost_principal_of(n: u64) -> Result; + fn cost_at_block(n: u64) -> Result; + fn cost_load_contract(n: u64) -> Result; + fn cost_create_map(n: u64) -> Result; + fn cost_create_var(n: u64) -> Result; + fn cost_create_nft(n: u64) -> Result; + fn cost_create_ft(n: u64) -> Result; + fn cost_fetch_entry(n: u64) -> Result; + fn cost_set_entry(n: u64) -> Result; + fn cost_fetch_var(n: u64) -> Result; + fn cost_set_var(n: u64) -> Result; + fn cost_contract_storage(n: u64) -> Result; + fn cost_block_info(n: u64) -> Result; + fn cost_stx_balance(n: u64) -> Result; + fn cost_stx_transfer(n: u64) -> Result; + fn cost_ft_mint(n: u64) -> Result; + fn cost_ft_transfer(n: u64) -> Result; + fn cost_ft_balance(n: u64) -> Result; + fn cost_ft_get_supply(n: u64) -> Result; + fn cost_ft_burn(n: u64) -> Result; + fn cost_nft_mint(n: u64) -> Result; + fn cost_nft_transfer(n: u64) -> Result; + fn cost_nft_owner(n: u64) -> Result; + fn cost_nft_burn(n: u64) -> Result; + fn poison_microblock(n: u64) -> Result; + fn cost_buff_to_int_le(n: u64) -> Result; + fn cost_buff_to_uint_le(n: u64) -> Result; + fn cost_buff_to_int_be(n: u64) -> Result; + fn cost_buff_to_uint_be(n: u64) -> Result; + fn cost_is_standard(n: u64) -> Result; + fn cost_principal_destruct(n: u64) -> Result; + fn cost_principal_construct(n: u64) -> Result; + fn cost_string_to_int(n: u64) -> Result; + fn cost_string_to_uint(n: u64) -> Result; + fn cost_int_to_ascii(n: u64) -> Result; + fn cost_int_to_utf8(n: u64) -> Result; + fn cost_burn_block_info(n: u64) -> Result; + fn cost_stx_account(n: u64) -> Result; + fn cost_slice(n: u64) -> Result; + fn cost_to_consensus_buff(n: u64) -> Result; + fn cost_from_consensus_buff(n: u64) -> Result; + fn cost_stx_transfer_memo(n: u64) -> Result; + fn cost_replace_at(n: u64) -> Result; + fn cost_as_contract(n: u64) -> Result; + fn cost_bitwise_and(n: u64) -> Result; + fn cost_bitwise_or(n: u64) -> Result; + fn cost_bitwise_not(n: u64) -> Result; + fn cost_bitwise_left_shift(n: u64) -> Result; + fn cost_bitwise_right_shift(n: u64) -> Result; + fn cost_contract_hash(n: u64) -> Result; + fn cost_to_ascii(n: u64) -> Result; + fn cost_restrict_assets(n: u64) -> Result; + fn cost_as_contract_safe(n: u64) -> Result; + fn cost_secp256r1verify(n: u64) -> Result; } impl ClarityCostFunction { - pub fn eval(&self, n: u64) -> InterpreterResult { + pub fn eval(&self, n: u64) -> Result { match self { ClarityCostFunction::AnalysisTypeAnnotate => C::cost_analysis_type_annotate(n), ClarityCostFunction::AnalysisTypeCheck => C::cost_analysis_type_check(n), @@ -493,7 +492,7 @@ impl ClarityCostFunction { ClarityCostFunction::RestrictAssets => C::cost_restrict_assets(n), ClarityCostFunction::AsContractSafe => C::cost_as_contract_safe(n), ClarityCostFunction::Secp256r1verify => C::cost_secp256r1verify(n), - ClarityCostFunction::Unimplemented => Err(RuntimeErrorType::NotImplemented.into()), + ClarityCostFunction::Unimplemented => Err(RuntimeError::NotImplemented.into()), } } } diff --git a/clarity/src/vm/costs/costs_1.rs b/clarity/src/vm/costs/costs_1.rs index fa16282da84..f702cd1a463 100644 --- a/clarity/src/vm/costs/costs_1.rs +++ b/clarity/src/vm/costs/costs_1.rs @@ -16,92 +16,92 @@ /// This file implements the cost functions from costs.clar in Rust. use super::cost_functions::{linear, logn, nlogn, CostValues}; use super::ExecutionCost; -use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; +use crate::vm::errors::{RuntimeError, VmExecutionError}; pub struct Costs1; impl CostValues for Costs1 { - fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + fn cost_analysis_type_annotate(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_type_check(n: u64) -> InterpreterResult { + fn cost_analysis_type_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + fn cost_analysis_type_lookup(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_visit(_n: u64) -> InterpreterResult { + fn cost_analysis_visit(_n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + fn cost_analysis_iterable_func(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_option_cons(_n: u64) -> InterpreterResult { + fn cost_analysis_option_cons(_n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_analysis_option_check(_n: u64) -> InterpreterResult { + fn cost_analysis_option_check(_n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + fn cost_analysis_bind_name(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_list_items_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_get(n: u64) -> Result { Ok(ExecutionCost::runtime(logn(n, 1000, 1000)?)) } - fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_merge(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 1000, 1000)?)) } - fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_tuple_items_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_check_let(n: u64) -> InterpreterResult { + fn cost_analysis_check_let(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_lookup_function(_n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function(_n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function_types(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_lookup_variable_const(_n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_const(_n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_depth(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 1000, 1000)?)) } - fn cost_ast_parse(n: u64) -> InterpreterResult { + fn cost_ast_parse(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 10000, 1000))) } - fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + fn cost_ast_cycle_detection(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_storage(n: u64) -> InterpreterResult { + fn cost_analysis_storage(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: linear(n, 1, 1), @@ -111,7 +111,7 @@ impl CostValues for Costs1 { }) } - fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + fn cost_analysis_use_trait_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: linear(n, 1, 1), @@ -121,7 +121,7 @@ impl CostValues for Costs1 { }) } - fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + fn cost_analysis_get_function_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 0, @@ -131,7 +131,7 @@ impl CostValues for Costs1 { }) } - fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + fn cost_analysis_fetch_contract_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 0, @@ -141,275 +141,275 @@ impl CostValues for Costs1 { }) } - fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_lookup_variable_depth(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + fn cost_lookup_variable_size(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 0))) } - fn cost_lookup_function(_n: u64) -> InterpreterResult { + fn cost_lookup_function(_n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_bind_name(_n: u64) -> InterpreterResult { + fn cost_bind_name(_n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + fn cost_inner_type_check_cost(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_user_function_application(n: u64) -> InterpreterResult { + fn cost_user_function_application(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_let(n: u64) -> InterpreterResult { + fn cost_let(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_if(n: u64) -> InterpreterResult { + fn cost_if(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_asserts(n: u64) -> InterpreterResult { + fn cost_asserts(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_map(n: u64) -> InterpreterResult { + fn cost_map(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_filter(n: u64) -> InterpreterResult { + fn cost_filter(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_len(n: u64) -> InterpreterResult { + fn cost_len(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_element_at(n: u64) -> InterpreterResult { + fn cost_element_at(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_index_of(n: u64) -> InterpreterResult { + fn cost_index_of(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_fold(n: u64) -> InterpreterResult { + fn cost_fold(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_list_cons(n: u64) -> InterpreterResult { + fn cost_list_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_type_parse_step(n: u64) -> InterpreterResult { + fn cost_type_parse_step(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_tuple_get(n: u64) -> InterpreterResult { + fn cost_tuple_get(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 1000, 1000)?)) } - fn cost_tuple_merge(n: u64) -> InterpreterResult { + fn cost_tuple_merge(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_tuple_cons(n: u64) -> InterpreterResult { + fn cost_tuple_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 1000, 1000)?)) } - fn cost_add(n: u64) -> InterpreterResult { + fn cost_add(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_sub(n: u64) -> InterpreterResult { + fn cost_sub(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_mul(n: u64) -> InterpreterResult { + fn cost_mul(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_div(n: u64) -> InterpreterResult { + fn cost_div(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_geq(n: u64) -> InterpreterResult { + fn cost_geq(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_leq(n: u64) -> InterpreterResult { + fn cost_leq(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_le(n: u64) -> InterpreterResult { + fn cost_le(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_ge(n: u64) -> InterpreterResult { + fn cost_ge(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_int_cast(n: u64) -> InterpreterResult { + fn cost_int_cast(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_mod(n: u64) -> InterpreterResult { + fn cost_mod(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_pow(n: u64) -> InterpreterResult { + fn cost_pow(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_sqrti(n: u64) -> InterpreterResult { + fn cost_sqrti(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_log2(n: u64) -> InterpreterResult { + fn cost_log2(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_xor(n: u64) -> InterpreterResult { + fn cost_xor(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_not(n: u64) -> InterpreterResult { + fn cost_not(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_eq(n: u64) -> InterpreterResult { + fn cost_eq(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_begin(n: u64) -> InterpreterResult { + fn cost_begin(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_hash160(n: u64) -> InterpreterResult { + fn cost_hash160(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_sha256(n: u64) -> InterpreterResult { + fn cost_sha256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_sha512(n: u64) -> InterpreterResult { + fn cost_sha512(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_sha512t256(n: u64) -> InterpreterResult { + fn cost_sha512t256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_keccak256(n: u64) -> InterpreterResult { + fn cost_keccak256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_secp256k1recover(n: u64) -> InterpreterResult { + fn cost_secp256k1recover(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_secp256k1verify(n: u64) -> InterpreterResult { + fn cost_secp256k1verify(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_print(n: u64) -> InterpreterResult { + fn cost_print(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_some_cons(n: u64) -> InterpreterResult { + fn cost_some_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_ok_cons(n: u64) -> InterpreterResult { + fn cost_ok_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_err_cons(n: u64) -> InterpreterResult { + fn cost_err_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_default_to(n: u64) -> InterpreterResult { + fn cost_default_to(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_unwrap_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_err_or_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_is_okay(n: u64) -> InterpreterResult { + fn cost_is_okay(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_is_none(n: u64) -> InterpreterResult { + fn cost_is_none(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_is_err(n: u64) -> InterpreterResult { + fn cost_is_err(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_is_some(n: u64) -> InterpreterResult { + fn cost_is_some(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_unwrap(n: u64) -> InterpreterResult { + fn cost_unwrap(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_unwrap_err(n: u64) -> InterpreterResult { + fn cost_unwrap_err(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_try_ret(n: u64) -> InterpreterResult { + fn cost_try_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_match(n: u64) -> InterpreterResult { + fn cost_match(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_or(n: u64) -> InterpreterResult { + fn cost_or(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_and(n: u64) -> InterpreterResult { + fn cost_and(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_append(n: u64) -> InterpreterResult { + fn cost_append(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_concat(n: u64) -> InterpreterResult { + fn cost_concat(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_as_max_len(n: u64) -> InterpreterResult { + fn cost_as_max_len(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_contract_call(n: u64) -> InterpreterResult { + fn cost_contract_call(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_contract_of(n: u64) -> InterpreterResult { + fn cost_contract_of(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_principal_of(n: u64) -> InterpreterResult { + fn cost_principal_of(n: u64) -> Result { Ok(ExecutionCost::runtime(1000)) } - fn cost_at_block(n: u64) -> InterpreterResult { + fn cost_at_block(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 0, @@ -419,7 +419,7 @@ impl CostValues for Costs1 { }) } - fn cost_load_contract(n: u64) -> InterpreterResult { + fn cost_load_contract(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 0, @@ -430,7 +430,7 @@ impl CostValues for Costs1 { }) } - fn cost_create_map(n: u64) -> InterpreterResult { + fn cost_create_map(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: linear(n, 1, 1), @@ -440,7 +440,7 @@ impl CostValues for Costs1 { }) } - fn cost_create_var(n: u64) -> InterpreterResult { + fn cost_create_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: linear(n, 1, 1), @@ -450,7 +450,7 @@ impl CostValues for Costs1 { }) } - fn cost_create_nft(n: u64) -> InterpreterResult { + fn cost_create_nft(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: linear(n, 1, 1), @@ -460,7 +460,7 @@ impl CostValues for Costs1 { }) } - fn cost_create_ft(n: u64) -> InterpreterResult { + fn cost_create_ft(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 1, @@ -470,7 +470,7 @@ impl CostValues for Costs1 { }) } - fn cost_fetch_entry(n: u64) -> InterpreterResult { + fn cost_fetch_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 0, @@ -480,7 +480,7 @@ impl CostValues for Costs1 { }) } - fn cost_set_entry(n: u64) -> InterpreterResult { + fn cost_set_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: linear(n, 1, 1), @@ -490,7 +490,7 @@ impl CostValues for Costs1 { }) } - fn cost_fetch_var(n: u64) -> InterpreterResult { + fn cost_fetch_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 0, @@ -500,7 +500,7 @@ impl CostValues for Costs1 { }) } - fn cost_set_var(n: u64) -> InterpreterResult { + fn cost_set_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: linear(n, 1, 1), @@ -510,7 +510,7 @@ impl CostValues for Costs1 { }) } - fn cost_contract_storage(n: u64) -> InterpreterResult { + fn cost_contract_storage(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: linear(n, 1, 1), @@ -520,7 +520,7 @@ impl CostValues for Costs1 { }) } - fn cost_block_info(n: u64) -> InterpreterResult { + fn cost_block_info(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 0, @@ -530,7 +530,7 @@ impl CostValues for Costs1 { }) } - fn cost_stx_balance(n: u64) -> InterpreterResult { + fn cost_stx_balance(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 0, @@ -540,7 +540,7 @@ impl CostValues for Costs1 { }) } - fn cost_stx_transfer(n: u64) -> InterpreterResult { + fn cost_stx_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 1, @@ -550,7 +550,7 @@ impl CostValues for Costs1 { }) } - fn cost_ft_mint(n: u64) -> InterpreterResult { + fn cost_ft_mint(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 1, @@ -560,7 +560,7 @@ impl CostValues for Costs1 { }) } - fn cost_ft_transfer(n: u64) -> InterpreterResult { + fn cost_ft_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 1, @@ -570,7 +570,7 @@ impl CostValues for Costs1 { }) } - fn cost_ft_balance(n: u64) -> InterpreterResult { + fn cost_ft_balance(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 0, @@ -580,7 +580,7 @@ impl CostValues for Costs1 { }) } - fn cost_nft_mint(n: u64) -> InterpreterResult { + fn cost_nft_mint(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 1, @@ -590,7 +590,7 @@ impl CostValues for Costs1 { }) } - fn cost_nft_transfer(n: u64) -> InterpreterResult { + fn cost_nft_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 1, @@ -600,7 +600,7 @@ impl CostValues for Costs1 { }) } - fn cost_nft_owner(n: u64) -> InterpreterResult { + fn cost_nft_owner(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 0, @@ -610,7 +610,7 @@ impl CostValues for Costs1 { }) } - fn cost_ft_get_supply(n: u64) -> InterpreterResult { + fn cost_ft_get_supply(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 0, @@ -620,7 +620,7 @@ impl CostValues for Costs1 { }) } - fn cost_ft_burn(n: u64) -> InterpreterResult { + fn cost_ft_burn(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 1, @@ -630,7 +630,7 @@ impl CostValues for Costs1 { }) } - fn cost_nft_burn(n: u64) -> InterpreterResult { + fn cost_nft_burn(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 1, @@ -640,7 +640,7 @@ impl CostValues for Costs1 { }) } - fn poison_microblock(n: u64) -> InterpreterResult { + fn poison_microblock(n: u64) -> Result { Ok(ExecutionCost { runtime: 1000, write_length: 1, @@ -650,119 +650,119 @@ impl CostValues for Costs1 { }) } - fn cost_buff_to_int_le(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_int_le(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_uint_le(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_int_be(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_int_be(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_uint_be(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_is_standard(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_is_standard(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_principal_destruct(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_principal_destruct(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_principal_construct(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_principal_construct(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_string_to_int(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_string_to_int(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_string_to_uint(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_string_to_uint(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_int_to_ascii(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_int_to_ascii(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_int_to_utf8(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_int_to_utf8(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_burn_block_info(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_burn_block_info(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_stx_account(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_stx_account(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_slice(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_slice(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_to_consensus_buff(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_to_consensus_buff(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_from_consensus_buff(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_from_consensus_buff(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_stx_transfer_memo(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_replace_at(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_replace_at(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_as_contract(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_as_contract(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_and(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_and(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_or(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_or(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_not(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_not(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_left_shift(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_right_shift(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_contract_hash(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_contract_hash(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_to_ascii(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_to_ascii(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_restrict_assets(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_restrict_assets(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_as_contract_safe(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_as_contract_safe(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_secp256r1verify(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_secp256r1verify(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } } diff --git a/clarity/src/vm/costs/costs_2.rs b/clarity/src/vm/costs/costs_2.rs index 8c44f814063..7042db2dcf4 100644 --- a/clarity/src/vm/costs/costs_2.rs +++ b/clarity/src/vm/costs/costs_2.rs @@ -16,92 +16,92 @@ /// This file implements the cost functions from costs-2.clar in Rust. use super::cost_functions::{linear, logn, nlogn, CostValues}; use super::ExecutionCost; -use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; +use crate::vm::errors::{RuntimeError, VmExecutionError}; pub struct Costs2; impl CostValues for Costs2 { - fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + fn cost_analysis_type_annotate(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 9))) } - fn cost_analysis_type_check(n: u64) -> InterpreterResult { + fn cost_analysis_type_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 113, 1))) } - fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + fn cost_analysis_type_lookup(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 6))) } - fn cost_analysis_visit(n: u64) -> InterpreterResult { + fn cost_analysis_visit(n: u64) -> Result { Ok(ExecutionCost::runtime(1)) } - fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + fn cost_analysis_iterable_func(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 14))) } - fn cost_analysis_option_cons(n: u64) -> InterpreterResult { + fn cost_analysis_option_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(6)) } - fn cost_analysis_option_check(n: u64) -> InterpreterResult { + fn cost_analysis_option_check(n: u64) -> Result { Ok(ExecutionCost::runtime(3)) } - fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + fn cost_analysis_bind_name(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 176))) } - fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_list_items_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 4))) } - fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_get(n: u64) -> Result { Ok(ExecutionCost::runtime(logn(n, 1, 2)?)) } - fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_merge(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 3, 5)?)) } - fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_tuple_items_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 59))) } - fn cost_analysis_check_let(n: u64) -> InterpreterResult { + fn cost_analysis_check_let(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 12))) } - fn cost_analysis_lookup_function(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function(n: u64) -> Result { Ok(ExecutionCost::runtime(20)) } - fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function_types(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 28))) } - fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_const(n: u64) -> Result { Ok(ExecutionCost::runtime(15)) } - fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_depth(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 1, 34)?)) } - fn cost_ast_parse(n: u64) -> InterpreterResult { + fn cost_ast_parse(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 172, 287441))) } - fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + fn cost_ast_cycle_detection(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 141, 72))) } - fn cost_analysis_storage(n: u64) -> InterpreterResult { + fn cost_analysis_storage(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 2, 100), write_length: linear(n, 1, 1), @@ -111,7 +111,7 @@ impl CostValues for Costs2 { }) } - fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + fn cost_analysis_use_trait_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 723), write_length: linear(n, 1, 1), @@ -121,7 +121,7 @@ impl CostValues for Costs2 { }) } - fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + fn cost_analysis_get_function_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 81, 1303), write_length: 0, @@ -131,7 +131,7 @@ impl CostValues for Costs2 { }) } - fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + fn cost_analysis_fetch_contract_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 0, @@ -141,275 +141,275 @@ impl CostValues for Costs2 { }) } - fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_lookup_variable_depth(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 14))) } - fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + fn cost_lookup_variable_size(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 1))) } - fn cost_lookup_function(n: u64) -> InterpreterResult { + fn cost_lookup_function(n: u64) -> Result { Ok(ExecutionCost::runtime(16)) } - fn cost_bind_name(n: u64) -> InterpreterResult { + fn cost_bind_name(n: u64) -> Result { Ok(ExecutionCost::runtime(256)) } - fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + fn cost_inner_type_check_cost(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 9))) } - fn cost_user_function_application(n: u64) -> InterpreterResult { + fn cost_user_function_application(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 26, 140))) } - fn cost_let(n: u64) -> InterpreterResult { + fn cost_let(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 146, 862))) } - fn cost_if(n: u64) -> InterpreterResult { + fn cost_if(n: u64) -> Result { Ok(ExecutionCost::runtime(200)) } - fn cost_asserts(n: u64) -> InterpreterResult { + fn cost_asserts(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_map(n: u64) -> InterpreterResult { + fn cost_map(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1210, 3314))) } - fn cost_filter(n: u64) -> InterpreterResult { + fn cost_filter(n: u64) -> Result { Ok(ExecutionCost::runtime(460)) } - fn cost_len(n: u64) -> InterpreterResult { + fn cost_len(n: u64) -> Result { Ok(ExecutionCost::runtime(486)) } - fn cost_element_at(n: u64) -> InterpreterResult { + fn cost_element_at(n: u64) -> Result { Ok(ExecutionCost::runtime(619)) } - fn cost_index_of(n: u64) -> InterpreterResult { + fn cost_index_of(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 243))) } - fn cost_fold(n: u64) -> InterpreterResult { + fn cost_fold(n: u64) -> Result { Ok(ExecutionCost::runtime(483)) } - fn cost_list_cons(n: u64) -> InterpreterResult { + fn cost_list_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 198))) } - fn cost_type_parse_step(n: u64) -> InterpreterResult { + fn cost_type_parse_step(n: u64) -> Result { Ok(ExecutionCost::runtime(5)) } - fn cost_tuple_get(n: u64) -> InterpreterResult { + fn cost_tuple_get(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 4, 1780)?)) } - fn cost_tuple_merge(n: u64) -> InterpreterResult { + fn cost_tuple_merge(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 4, 646))) } - fn cost_tuple_cons(n: u64) -> InterpreterResult { + fn cost_tuple_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 11, 1101)?)) } - fn cost_add(n: u64) -> InterpreterResult { + fn cost_add(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 157))) } - fn cost_sub(n: u64) -> InterpreterResult { + fn cost_sub(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 157))) } - fn cost_mul(n: u64) -> InterpreterResult { + fn cost_mul(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 157))) } - fn cost_div(n: u64) -> InterpreterResult { + fn cost_div(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 157))) } - fn cost_geq(n: u64) -> InterpreterResult { + fn cost_geq(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_leq(n: u64) -> InterpreterResult { + fn cost_leq(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_le(n: u64) -> InterpreterResult { + fn cost_le(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_ge(n: u64) -> InterpreterResult { + fn cost_ge(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_int_cast(n: u64) -> InterpreterResult { + fn cost_int_cast(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_mod(n: u64) -> InterpreterResult { + fn cost_mod(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_pow(n: u64) -> InterpreterResult { + fn cost_pow(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_sqrti(n: u64) -> InterpreterResult { + fn cost_sqrti(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_log2(n: u64) -> InterpreterResult { + fn cost_log2(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_xor(n: u64) -> InterpreterResult { + fn cost_xor(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_not(n: u64) -> InterpreterResult { + fn cost_not(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_eq(n: u64) -> InterpreterResult { + fn cost_eq(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 7, 172))) } - fn cost_begin(n: u64) -> InterpreterResult { + fn cost_begin(n: u64) -> Result { Ok(ExecutionCost::runtime(202)) } - fn cost_hash160(n: u64) -> InterpreterResult { + fn cost_hash160(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 201))) } - fn cost_sha256(n: u64) -> InterpreterResult { + fn cost_sha256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 100))) } - fn cost_sha512(n: u64) -> InterpreterResult { + fn cost_sha512(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 176))) } - fn cost_sha512t256(n: u64) -> InterpreterResult { + fn cost_sha512t256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 188))) } - fn cost_keccak256(n: u64) -> InterpreterResult { + fn cost_keccak256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 221))) } - fn cost_secp256k1recover(n: u64) -> InterpreterResult { + fn cost_secp256k1recover(n: u64) -> Result { Ok(ExecutionCost::runtime(14344)) } - fn cost_secp256k1verify(n: u64) -> InterpreterResult { + fn cost_secp256k1verify(n: u64) -> Result { Ok(ExecutionCost::runtime(13540)) } - fn cost_print(n: u64) -> InterpreterResult { + fn cost_print(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 3, 1413))) } - fn cost_some_cons(n: u64) -> InterpreterResult { + fn cost_some_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(230)) } - fn cost_ok_cons(n: u64) -> InterpreterResult { + fn cost_ok_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(230)) } - fn cost_err_cons(n: u64) -> InterpreterResult { + fn cost_err_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(230)) } - fn cost_default_to(n: u64) -> InterpreterResult { + fn cost_default_to(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_unwrap_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(339)) } - fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_err_or_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(339)) } - fn cost_is_okay(n: u64) -> InterpreterResult { + fn cost_is_okay(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_is_none(n: u64) -> InterpreterResult { + fn cost_is_none(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_is_err(n: u64) -> InterpreterResult { + fn cost_is_err(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_is_some(n: u64) -> InterpreterResult { + fn cost_is_some(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_unwrap(n: u64) -> InterpreterResult { + fn cost_unwrap(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_unwrap_err(n: u64) -> InterpreterResult { + fn cost_unwrap_err(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_try_ret(n: u64) -> InterpreterResult { + fn cost_try_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_match(n: u64) -> InterpreterResult { + fn cost_match(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_or(n: u64) -> InterpreterResult { + fn cost_or(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 3, 149))) } - fn cost_and(n: u64) -> InterpreterResult { + fn cost_and(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 3, 149))) } - fn cost_append(n: u64) -> InterpreterResult { + fn cost_append(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 71, 176))) } - fn cost_concat(n: u64) -> InterpreterResult { + fn cost_concat(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 75, 244))) } - fn cost_as_max_len(n: u64) -> InterpreterResult { + fn cost_as_max_len(n: u64) -> Result { Ok(ExecutionCost::runtime(475)) } - fn cost_contract_call(n: u64) -> InterpreterResult { + fn cost_contract_call(n: u64) -> Result { Ok(ExecutionCost::runtime(153)) } - fn cost_contract_of(n: u64) -> InterpreterResult { + fn cost_contract_of(n: u64) -> Result { Ok(ExecutionCost::runtime(13400)) } - fn cost_principal_of(n: u64) -> InterpreterResult { + fn cost_principal_of(n: u64) -> Result { Ok(ExecutionCost::runtime(999)) } - fn cost_at_block(n: u64) -> InterpreterResult { + fn cost_at_block(n: u64) -> Result { Ok(ExecutionCost { runtime: 210, write_length: 0, @@ -419,7 +419,7 @@ impl CostValues for Costs2 { }) } - fn cost_load_contract(n: u64) -> InterpreterResult { + fn cost_load_contract(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 157), write_length: 0, @@ -430,7 +430,7 @@ impl CostValues for Costs2 { }) } - fn cost_create_map(n: u64) -> InterpreterResult { + fn cost_create_map(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1631), write_length: linear(n, 1, 1), @@ -440,7 +440,7 @@ impl CostValues for Costs2 { }) } - fn cost_create_var(n: u64) -> InterpreterResult { + fn cost_create_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 7, 2152), write_length: linear(n, 1, 1), @@ -450,7 +450,7 @@ impl CostValues for Costs2 { }) } - fn cost_create_nft(n: u64) -> InterpreterResult { + fn cost_create_nft(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1610), write_length: linear(n, 1, 1), @@ -460,7 +460,7 @@ impl CostValues for Costs2 { }) } - fn cost_create_ft(n: u64) -> InterpreterResult { + fn cost_create_ft(n: u64) -> Result { Ok(ExecutionCost { runtime: 1972, write_length: 1, @@ -470,7 +470,7 @@ impl CostValues for Costs2 { }) } - fn cost_fetch_entry(n: u64) -> InterpreterResult { + fn cost_fetch_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1539), write_length: 0, @@ -480,7 +480,7 @@ impl CostValues for Costs2 { }) } - fn cost_set_entry(n: u64) -> InterpreterResult { + fn cost_set_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 4, 2204), write_length: linear(n, 1, 1), @@ -490,7 +490,7 @@ impl CostValues for Costs2 { }) } - fn cost_fetch_var(n: u64) -> InterpreterResult { + fn cost_fetch_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 543), write_length: 0, @@ -500,7 +500,7 @@ impl CostValues for Costs2 { }) } - fn cost_set_var(n: u64) -> InterpreterResult { + fn cost_set_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 5, 691), write_length: linear(n, 1, 1), @@ -510,7 +510,7 @@ impl CostValues for Costs2 { }) } - fn cost_contract_storage(n: u64) -> InterpreterResult { + fn cost_contract_storage(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 13, 7982), write_length: linear(n, 1, 1), @@ -520,7 +520,7 @@ impl CostValues for Costs2 { }) } - fn cost_block_info(n: u64) -> InterpreterResult { + fn cost_block_info(n: u64) -> Result { Ok(ExecutionCost { runtime: 6321, write_length: 0, @@ -530,7 +530,7 @@ impl CostValues for Costs2 { }) } - fn cost_stx_balance(n: u64) -> InterpreterResult { + fn cost_stx_balance(n: u64) -> Result { Ok(ExecutionCost { runtime: 1385, write_length: 0, @@ -540,7 +540,7 @@ impl CostValues for Costs2 { }) } - fn cost_stx_transfer(n: u64) -> InterpreterResult { + fn cost_stx_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: 1430, write_length: 1, @@ -550,7 +550,7 @@ impl CostValues for Costs2 { }) } - fn cost_ft_mint(n: u64) -> InterpreterResult { + fn cost_ft_mint(n: u64) -> Result { Ok(ExecutionCost { runtime: 1645, write_length: 1, @@ -560,7 +560,7 @@ impl CostValues for Costs2 { }) } - fn cost_ft_transfer(n: u64) -> InterpreterResult { + fn cost_ft_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: 612, write_length: 1, @@ -570,7 +570,7 @@ impl CostValues for Costs2 { }) } - fn cost_ft_balance(n: u64) -> InterpreterResult { + fn cost_ft_balance(n: u64) -> Result { Ok(ExecutionCost { runtime: 547, write_length: 0, @@ -580,7 +580,7 @@ impl CostValues for Costs2 { }) } - fn cost_nft_mint(n: u64) -> InterpreterResult { + fn cost_nft_mint(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 1, @@ -590,7 +590,7 @@ impl CostValues for Costs2 { }) } - fn cost_nft_transfer(n: u64) -> InterpreterResult { + fn cost_nft_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 1, @@ -600,7 +600,7 @@ impl CostValues for Costs2 { }) } - fn cost_nft_owner(n: u64) -> InterpreterResult { + fn cost_nft_owner(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 0, @@ -610,7 +610,7 @@ impl CostValues for Costs2 { }) } - fn cost_ft_get_supply(n: u64) -> InterpreterResult { + fn cost_ft_get_supply(n: u64) -> Result { Ok(ExecutionCost { runtime: 483, write_length: 0, @@ -620,7 +620,7 @@ impl CostValues for Costs2 { }) } - fn cost_ft_burn(n: u64) -> InterpreterResult { + fn cost_ft_burn(n: u64) -> Result { Ok(ExecutionCost { runtime: 612, write_length: 1, @@ -630,7 +630,7 @@ impl CostValues for Costs2 { }) } - fn cost_nft_burn(n: u64) -> InterpreterResult { + fn cost_nft_burn(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 1, @@ -640,7 +640,7 @@ impl CostValues for Costs2 { }) } - fn poison_microblock(n: u64) -> InterpreterResult { + fn poison_microblock(n: u64) -> Result { Ok(ExecutionCost { runtime: 29568, write_length: 1, @@ -650,119 +650,119 @@ impl CostValues for Costs2 { }) } - fn cost_buff_to_int_le(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_int_le(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_uint_le(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_int_be(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_int_be(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_uint_be(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_is_standard(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_is_standard(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_principal_destruct(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_principal_destruct(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_principal_construct(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_principal_construct(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_string_to_int(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_string_to_int(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_string_to_uint(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_string_to_uint(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_int_to_ascii(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_int_to_ascii(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_int_to_utf8(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_int_to_utf8(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_burn_block_info(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_burn_block_info(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_stx_account(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_stx_account(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_slice(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_slice(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_to_consensus_buff(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_to_consensus_buff(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_from_consensus_buff(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_from_consensus_buff(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_stx_transfer_memo(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_replace_at(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_replace_at(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_as_contract(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_as_contract(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_and(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_and(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_or(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_or(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_not(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_not(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_left_shift(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_right_shift(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_contract_hash(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_contract_hash(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_to_ascii(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_to_ascii(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_restrict_assets(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_restrict_assets(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_as_contract_safe(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_as_contract_safe(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_secp256r1verify(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_secp256r1verify(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } } diff --git a/clarity/src/vm/costs/costs_2_testnet.rs b/clarity/src/vm/costs/costs_2_testnet.rs index 05baabd0b18..596b24fc716 100644 --- a/clarity/src/vm/costs/costs_2_testnet.rs +++ b/clarity/src/vm/costs/costs_2_testnet.rs @@ -16,92 +16,92 @@ /// This file implements the cost functions from costs-2-testnet.clar in Rust. use super::cost_functions::{linear, logn, nlogn, CostValues}; use super::ExecutionCost; -use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; +use crate::vm::errors::{RuntimeError, VmExecutionError}; pub struct Costs2Testnet; impl CostValues for Costs2Testnet { - fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + fn cost_analysis_type_annotate(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 9))) } - fn cost_analysis_type_check(n: u64) -> InterpreterResult { + fn cost_analysis_type_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 113, 1))) } - fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + fn cost_analysis_type_lookup(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 6))) } - fn cost_analysis_visit(n: u64) -> InterpreterResult { + fn cost_analysis_visit(n: u64) -> Result { Ok(ExecutionCost::runtime(1)) } - fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + fn cost_analysis_iterable_func(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 14))) } - fn cost_analysis_option_cons(n: u64) -> InterpreterResult { + fn cost_analysis_option_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(6)) } - fn cost_analysis_option_check(n: u64) -> InterpreterResult { + fn cost_analysis_option_check(n: u64) -> Result { Ok(ExecutionCost::runtime(3)) } - fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + fn cost_analysis_bind_name(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 176))) } - fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_list_items_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 4))) } - fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_get(n: u64) -> Result { Ok(ExecutionCost::runtime(logn(n, 1, 2)?)) } - fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_merge(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) } - fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 3, 5)?)) } - fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_tuple_items_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 59))) } - fn cost_analysis_check_let(n: u64) -> InterpreterResult { + fn cost_analysis_check_let(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 12))) } - fn cost_analysis_lookup_function(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function(n: u64) -> Result { Ok(ExecutionCost::runtime(20)) } - fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function_types(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 28))) } - fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_const(n: u64) -> Result { Ok(ExecutionCost::runtime(15)) } - fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_depth(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 1, 34)?)) } - fn cost_ast_parse(n: u64) -> InterpreterResult { + fn cost_ast_parse(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 172, 287441))) } - fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + fn cost_ast_cycle_detection(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 141, 72))) } - fn cost_analysis_storage(n: u64) -> InterpreterResult { + fn cost_analysis_storage(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 2, 100), write_length: linear(n, 1, 1), @@ -111,7 +111,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + fn cost_analysis_use_trait_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 723), write_length: linear(n, 1, 1), @@ -121,7 +121,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + fn cost_analysis_get_function_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 81, 1303), write_length: 0, @@ -131,7 +131,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + fn cost_analysis_fetch_contract_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1000, 1000), write_length: 0, @@ -141,275 +141,275 @@ impl CostValues for Costs2Testnet { }) } - fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_lookup_variable_depth(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 14))) } - fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + fn cost_lookup_variable_size(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 1))) } - fn cost_lookup_function(n: u64) -> InterpreterResult { + fn cost_lookup_function(n: u64) -> Result { Ok(ExecutionCost::runtime(16)) } - fn cost_bind_name(n: u64) -> InterpreterResult { + fn cost_bind_name(n: u64) -> Result { Ok(ExecutionCost::runtime(256)) } - fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + fn cost_inner_type_check_cost(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 9))) } - fn cost_user_function_application(n: u64) -> InterpreterResult { + fn cost_user_function_application(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 26, 140))) } - fn cost_let(n: u64) -> InterpreterResult { + fn cost_let(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 146, 862))) } - fn cost_if(n: u64) -> InterpreterResult { + fn cost_if(n: u64) -> Result { Ok(ExecutionCost::runtime(200)) } - fn cost_asserts(n: u64) -> InterpreterResult { + fn cost_asserts(n: u64) -> Result { Ok(ExecutionCost::runtime(158)) } - fn cost_map(n: u64) -> InterpreterResult { + fn cost_map(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1210, 3314))) } - fn cost_filter(n: u64) -> InterpreterResult { + fn cost_filter(n: u64) -> Result { Ok(ExecutionCost::runtime(460)) } - fn cost_len(n: u64) -> InterpreterResult { + fn cost_len(n: u64) -> Result { Ok(ExecutionCost::runtime(486)) } - fn cost_element_at(n: u64) -> InterpreterResult { + fn cost_element_at(n: u64) -> Result { Ok(ExecutionCost::runtime(619)) } - fn cost_index_of(n: u64) -> InterpreterResult { + fn cost_index_of(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 243))) } - fn cost_fold(n: u64) -> InterpreterResult { + fn cost_fold(n: u64) -> Result { Ok(ExecutionCost::runtime(483)) } - fn cost_list_cons(n: u64) -> InterpreterResult { + fn cost_list_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 198))) } - fn cost_type_parse_step(n: u64) -> InterpreterResult { + fn cost_type_parse_step(n: u64) -> Result { Ok(ExecutionCost::runtime(5)) } - fn cost_tuple_get(n: u64) -> InterpreterResult { + fn cost_tuple_get(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 4, 1780)?)) } - fn cost_tuple_merge(n: u64) -> InterpreterResult { + fn cost_tuple_merge(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 4, 646))) } - fn cost_tuple_cons(n: u64) -> InterpreterResult { + fn cost_tuple_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 11, 1101)?)) } - fn cost_add(n: u64) -> InterpreterResult { + fn cost_add(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 12, 156))) } - fn cost_sub(n: u64) -> InterpreterResult { + fn cost_sub(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 12, 156))) } - fn cost_mul(n: u64) -> InterpreterResult { + fn cost_mul(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 157))) } - fn cost_div(n: u64) -> InterpreterResult { + fn cost_div(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 157))) } - fn cost_geq(n: u64) -> InterpreterResult { + fn cost_geq(n: u64) -> Result { Ok(ExecutionCost::runtime(166)) } - fn cost_leq(n: u64) -> InterpreterResult { + fn cost_leq(n: u64) -> Result { Ok(ExecutionCost::runtime(166)) } - fn cost_le(n: u64) -> InterpreterResult { + fn cost_le(n: u64) -> Result { Ok(ExecutionCost::runtime(166)) } - fn cost_ge(n: u64) -> InterpreterResult { + fn cost_ge(n: u64) -> Result { Ok(ExecutionCost::runtime(166)) } - fn cost_int_cast(n: u64) -> InterpreterResult { + fn cost_int_cast(n: u64) -> Result { Ok(ExecutionCost::runtime(164)) } - fn cost_mod(n: u64) -> InterpreterResult { + fn cost_mod(n: u64) -> Result { Ok(ExecutionCost::runtime(168)) } - fn cost_pow(n: u64) -> InterpreterResult { + fn cost_pow(n: u64) -> Result { Ok(ExecutionCost::runtime(170)) } - fn cost_sqrti(n: u64) -> InterpreterResult { + fn cost_sqrti(n: u64) -> Result { Ok(ExecutionCost::runtime(167)) } - fn cost_log2(n: u64) -> InterpreterResult { + fn cost_log2(n: u64) -> Result { Ok(ExecutionCost::runtime(161)) } - fn cost_xor(n: u64) -> InterpreterResult { + fn cost_xor(n: u64) -> Result { Ok(ExecutionCost::runtime(167)) } - fn cost_not(n: u64) -> InterpreterResult { + fn cost_not(n: u64) -> Result { Ok(ExecutionCost::runtime(162)) } - fn cost_eq(n: u64) -> InterpreterResult { + fn cost_eq(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 7, 172))) } - fn cost_begin(n: u64) -> InterpreterResult { + fn cost_begin(n: u64) -> Result { Ok(ExecutionCost::runtime(202)) } - fn cost_hash160(n: u64) -> InterpreterResult { + fn cost_hash160(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 201))) } - fn cost_sha256(n: u64) -> InterpreterResult { + fn cost_sha256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 100))) } - fn cost_sha512(n: u64) -> InterpreterResult { + fn cost_sha512(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 176))) } - fn cost_sha512t256(n: u64) -> InterpreterResult { + fn cost_sha512t256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 188))) } - fn cost_keccak256(n: u64) -> InterpreterResult { + fn cost_keccak256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 221))) } - fn cost_secp256k1recover(n: u64) -> InterpreterResult { + fn cost_secp256k1recover(n: u64) -> Result { Ok(ExecutionCost::runtime(14344)) } - fn cost_secp256k1verify(n: u64) -> InterpreterResult { + fn cost_secp256k1verify(n: u64) -> Result { Ok(ExecutionCost::runtime(13540)) } - fn cost_print(n: u64) -> InterpreterResult { + fn cost_print(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 3, 1413))) } - fn cost_some_cons(n: u64) -> InterpreterResult { + fn cost_some_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(230)) } - fn cost_ok_cons(n: u64) -> InterpreterResult { + fn cost_ok_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(230)) } - fn cost_err_cons(n: u64) -> InterpreterResult { + fn cost_err_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(230)) } - fn cost_default_to(n: u64) -> InterpreterResult { + fn cost_default_to(n: u64) -> Result { Ok(ExecutionCost::runtime(249)) } - fn cost_unwrap_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(299)) } - fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_err_or_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(339)) } - fn cost_is_okay(n: u64) -> InterpreterResult { + fn cost_is_okay(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_is_none(n: u64) -> InterpreterResult { + fn cost_is_none(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_is_err(n: u64) -> InterpreterResult { + fn cost_is_err(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_is_some(n: u64) -> InterpreterResult { + fn cost_is_some(n: u64) -> Result { Ok(ExecutionCost::runtime(287)) } - fn cost_unwrap(n: u64) -> InterpreterResult { + fn cost_unwrap(n: u64) -> Result { Ok(ExecutionCost::runtime(284)) } - fn cost_unwrap_err(n: u64) -> InterpreterResult { + fn cost_unwrap_err(n: u64) -> Result { Ok(ExecutionCost::runtime(264)) } - fn cost_try_ret(n: u64) -> InterpreterResult { + fn cost_try_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(256)) } - fn cost_match(n: u64) -> InterpreterResult { + fn cost_match(n: u64) -> Result { Ok(ExecutionCost::runtime(286)) } - fn cost_or(n: u64) -> InterpreterResult { + fn cost_or(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 3, 149))) } - fn cost_and(n: u64) -> InterpreterResult { + fn cost_and(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 3, 149))) } - fn cost_append(n: u64) -> InterpreterResult { + fn cost_append(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 71, 176))) } - fn cost_concat(n: u64) -> InterpreterResult { + fn cost_concat(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 75, 244))) } - fn cost_as_max_len(n: u64) -> InterpreterResult { + fn cost_as_max_len(n: u64) -> Result { Ok(ExecutionCost::runtime(475)) } - fn cost_contract_call(n: u64) -> InterpreterResult { + fn cost_contract_call(n: u64) -> Result { Ok(ExecutionCost::runtime(153)) } - fn cost_contract_of(n: u64) -> InterpreterResult { + fn cost_contract_of(n: u64) -> Result { Ok(ExecutionCost::runtime(13400)) } - fn cost_principal_of(n: u64) -> InterpreterResult { + fn cost_principal_of(n: u64) -> Result { Ok(ExecutionCost::runtime(39)) } - fn cost_at_block(n: u64) -> InterpreterResult { + fn cost_at_block(n: u64) -> Result { Ok(ExecutionCost { runtime: 210, write_length: 0, @@ -419,7 +419,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_load_contract(n: u64) -> InterpreterResult { + fn cost_load_contract(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 157), write_length: 0, @@ -430,7 +430,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_create_map(n: u64) -> InterpreterResult { + fn cost_create_map(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1631), write_length: linear(n, 1, 1), @@ -440,7 +440,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_create_var(n: u64) -> InterpreterResult { + fn cost_create_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 7, 2152), write_length: linear(n, 1, 1), @@ -450,7 +450,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_create_nft(n: u64) -> InterpreterResult { + fn cost_create_nft(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1610), write_length: linear(n, 1, 1), @@ -460,7 +460,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_create_ft(n: u64) -> InterpreterResult { + fn cost_create_ft(n: u64) -> Result { Ok(ExecutionCost { runtime: 1972, write_length: 1, @@ -470,7 +470,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_fetch_entry(n: u64) -> InterpreterResult { + fn cost_fetch_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1539), write_length: 0, @@ -480,7 +480,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_set_entry(n: u64) -> InterpreterResult { + fn cost_set_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 4, 2204), write_length: linear(n, 1, 1), @@ -490,7 +490,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_fetch_var(n: u64) -> InterpreterResult { + fn cost_fetch_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 543), write_length: 0, @@ -500,7 +500,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_set_var(n: u64) -> InterpreterResult { + fn cost_set_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 5, 691), write_length: linear(n, 1, 1), @@ -510,7 +510,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_contract_storage(n: u64) -> InterpreterResult { + fn cost_contract_storage(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 13, 7982), write_length: linear(n, 1, 1), @@ -520,7 +520,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_block_info(n: u64) -> InterpreterResult { + fn cost_block_info(n: u64) -> Result { Ok(ExecutionCost { runtime: 6321, write_length: 0, @@ -530,7 +530,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_stx_balance(n: u64) -> InterpreterResult { + fn cost_stx_balance(n: u64) -> Result { Ok(ExecutionCost { runtime: 1385, write_length: 0, @@ -540,7 +540,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_stx_transfer(n: u64) -> InterpreterResult { + fn cost_stx_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: 1430, write_length: 1, @@ -550,7 +550,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_ft_mint(n: u64) -> InterpreterResult { + fn cost_ft_mint(n: u64) -> Result { Ok(ExecutionCost { runtime: 1645, write_length: 1, @@ -560,7 +560,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_ft_transfer(n: u64) -> InterpreterResult { + fn cost_ft_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: 612, write_length: 1, @@ -570,7 +570,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_ft_balance(n: u64) -> InterpreterResult { + fn cost_ft_balance(n: u64) -> Result { Ok(ExecutionCost { runtime: 547, write_length: 0, @@ -580,7 +580,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_nft_mint(n: u64) -> InterpreterResult { + fn cost_nft_mint(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 1, @@ -590,7 +590,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_nft_transfer(n: u64) -> InterpreterResult { + fn cost_nft_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 1, @@ -600,7 +600,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_nft_owner(n: u64) -> InterpreterResult { + fn cost_nft_owner(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 0, @@ -610,7 +610,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_ft_get_supply(n: u64) -> InterpreterResult { + fn cost_ft_get_supply(n: u64) -> Result { Ok(ExecutionCost { runtime: 483, write_length: 0, @@ -620,7 +620,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_ft_burn(n: u64) -> InterpreterResult { + fn cost_ft_burn(n: u64) -> Result { Ok(ExecutionCost { runtime: 612, write_length: 1, @@ -630,7 +630,7 @@ impl CostValues for Costs2Testnet { }) } - fn cost_nft_burn(n: u64) -> InterpreterResult { + fn cost_nft_burn(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 1, @@ -640,7 +640,7 @@ impl CostValues for Costs2Testnet { }) } - fn poison_microblock(n: u64) -> InterpreterResult { + fn poison_microblock(n: u64) -> Result { Ok(ExecutionCost { runtime: 29568, write_length: 1, @@ -650,119 +650,119 @@ impl CostValues for Costs2Testnet { }) } - fn cost_buff_to_int_le(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_int_le(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_uint_le(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_int_be(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_int_be(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_buff_to_uint_be(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_is_standard(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_is_standard(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_principal_destruct(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_principal_destruct(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_principal_construct(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_principal_construct(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_string_to_int(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_string_to_int(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_string_to_uint(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_string_to_uint(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_int_to_ascii(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_int_to_ascii(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_int_to_utf8(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_int_to_utf8(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_burn_block_info(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_burn_block_info(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_stx_account(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_stx_account(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_slice(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_slice(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_to_consensus_buff(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_to_consensus_buff(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_from_consensus_buff(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_from_consensus_buff(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_stx_transfer_memo(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_replace_at(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_replace_at(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_as_contract(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_as_contract(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_and(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_and(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_or(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_or(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_not(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_not(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_left_shift(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_bitwise_right_shift(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_contract_hash(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_contract_hash(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_to_ascii(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_to_ascii(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_restrict_assets(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_restrict_assets(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_as_contract_safe(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_as_contract_safe(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_secp256r1verify(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_secp256r1verify(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } } diff --git a/clarity/src/vm/costs/costs_3.rs b/clarity/src/vm/costs/costs_3.rs index 8e34ad6b1de..be2646fa6cf 100644 --- a/clarity/src/vm/costs/costs_3.rs +++ b/clarity/src/vm/costs/costs_3.rs @@ -16,92 +16,92 @@ /// This file implements the cost functions from costs-3.clar in Rust. use super::cost_functions::{linear, logn, nlogn, CostValues}; use super::ExecutionCost; -use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; +use crate::vm::errors::{RuntimeError, VmExecutionError}; pub struct Costs3; impl CostValues for Costs3 { - fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + fn cost_analysis_type_annotate(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 9))) } - fn cost_analysis_type_check(n: u64) -> InterpreterResult { + fn cost_analysis_type_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 113, 1))) } - fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + fn cost_analysis_type_lookup(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 4))) } - fn cost_analysis_visit(n: u64) -> InterpreterResult { + fn cost_analysis_visit(n: u64) -> Result { Ok(ExecutionCost::runtime(1)) } - fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + fn cost_analysis_iterable_func(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 14))) } - fn cost_analysis_option_cons(n: u64) -> InterpreterResult { + fn cost_analysis_option_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(5)) } - fn cost_analysis_option_check(n: u64) -> InterpreterResult { + fn cost_analysis_option_check(n: u64) -> Result { Ok(ExecutionCost::runtime(4)) } - fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + fn cost_analysis_bind_name(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 59))) } - fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_list_items_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 4))) } - fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_get(n: u64) -> Result { Ok(ExecutionCost::runtime(logn(n, 1, 2)?)) } - fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_merge(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 45, 49)?)) } - fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 3, 5)?)) } - fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_tuple_items_check(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 28))) } - fn cost_analysis_check_let(n: u64) -> InterpreterResult { + fn cost_analysis_check_let(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 10))) } - fn cost_analysis_lookup_function(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function(n: u64) -> Result { Ok(ExecutionCost::runtime(18)) } - fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function_types(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 26))) } - fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_const(n: u64) -> Result { Ok(ExecutionCost::runtime(15)) } - fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_depth(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 1, 12)?)) } - fn cost_ast_parse(n: u64) -> InterpreterResult { + fn cost_ast_parse(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 27, 81))) } - fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + fn cost_ast_cycle_detection(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 141, 72))) } - fn cost_analysis_storage(n: u64) -> InterpreterResult { + fn cost_analysis_storage(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 2, 94), write_length: linear(n, 1, 1), @@ -111,7 +111,7 @@ impl CostValues for Costs3 { }) } - fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + fn cost_analysis_use_trait_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 698), write_length: linear(n, 1, 1), @@ -121,7 +121,7 @@ impl CostValues for Costs3 { }) } - fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + fn cost_analysis_fetch_contract_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1516), write_length: 0, @@ -131,7 +131,7 @@ impl CostValues for Costs3 { }) } - fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + fn cost_analysis_get_function_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 78, 1307), write_length: 0, @@ -141,275 +141,275 @@ impl CostValues for Costs3 { }) } - fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_lookup_variable_depth(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 1))) } - fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + fn cost_lookup_variable_size(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 1))) } - fn cost_lookup_function(n: u64) -> InterpreterResult { + fn cost_lookup_function(n: u64) -> Result { Ok(ExecutionCost::runtime(16)) } - fn cost_bind_name(n: u64) -> InterpreterResult { + fn cost_bind_name(n: u64) -> Result { Ok(ExecutionCost::runtime(216)) } - fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + fn cost_inner_type_check_cost(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 2, 5))) } - fn cost_user_function_application(n: u64) -> InterpreterResult { + fn cost_user_function_application(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 26, 5))) } - fn cost_let(n: u64) -> InterpreterResult { + fn cost_let(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 117, 178))) } - fn cost_if(n: u64) -> InterpreterResult { + fn cost_if(n: u64) -> Result { Ok(ExecutionCost::runtime(168)) } - fn cost_asserts(n: u64) -> InterpreterResult { + fn cost_asserts(n: u64) -> Result { Ok(ExecutionCost::runtime(128)) } - fn cost_map(n: u64) -> InterpreterResult { + fn cost_map(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1198, 3067))) } - fn cost_filter(n: u64) -> InterpreterResult { + fn cost_filter(n: u64) -> Result { Ok(ExecutionCost::runtime(407)) } - fn cost_len(n: u64) -> InterpreterResult { + fn cost_len(n: u64) -> Result { Ok(ExecutionCost::runtime(429)) } - fn cost_element_at(n: u64) -> InterpreterResult { + fn cost_element_at(n: u64) -> Result { Ok(ExecutionCost::runtime(498)) } - fn cost_index_of(n: u64) -> InterpreterResult { + fn cost_index_of(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 211))) } - fn cost_fold(n: u64) -> InterpreterResult { + fn cost_fold(n: u64) -> Result { Ok(ExecutionCost::runtime(460)) } - fn cost_list_cons(n: u64) -> InterpreterResult { + fn cost_list_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 14, 164))) } - fn cost_type_parse_step(n: u64) -> InterpreterResult { + fn cost_type_parse_step(n: u64) -> Result { Ok(ExecutionCost::runtime(4)) } - fn cost_tuple_get(n: u64) -> InterpreterResult { + fn cost_tuple_get(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 4, 1736)?)) } - fn cost_tuple_merge(n: u64) -> InterpreterResult { + fn cost_tuple_merge(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 4, 408))) } - fn cost_tuple_cons(n: u64) -> InterpreterResult { + fn cost_tuple_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 10, 1876)?)) } - fn cost_add(n: u64) -> InterpreterResult { + fn cost_add(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 11, 125))) } - fn cost_sub(n: u64) -> InterpreterResult { + fn cost_sub(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 11, 125))) } - fn cost_mul(n: u64) -> InterpreterResult { + fn cost_mul(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 13, 125))) } - fn cost_div(n: u64) -> InterpreterResult { + fn cost_div(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 13, 125))) } - fn cost_geq(n: u64) -> InterpreterResult { + fn cost_geq(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 7, 128))) } - fn cost_leq(n: u64) -> InterpreterResult { + fn cost_leq(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 7, 128))) } - fn cost_le(n: u64) -> InterpreterResult { + fn cost_le(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 7, 128))) } - fn cost_ge(n: u64) -> InterpreterResult { + fn cost_ge(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 7, 128))) } - fn cost_int_cast(n: u64) -> InterpreterResult { + fn cost_int_cast(n: u64) -> Result { Ok(ExecutionCost::runtime(135)) } - fn cost_mod(n: u64) -> InterpreterResult { + fn cost_mod(n: u64) -> Result { Ok(ExecutionCost::runtime(141)) } - fn cost_pow(n: u64) -> InterpreterResult { + fn cost_pow(n: u64) -> Result { Ok(ExecutionCost::runtime(143)) } - fn cost_sqrti(n: u64) -> InterpreterResult { + fn cost_sqrti(n: u64) -> Result { Ok(ExecutionCost::runtime(142)) } - fn cost_log2(n: u64) -> InterpreterResult { + fn cost_log2(n: u64) -> Result { Ok(ExecutionCost::runtime(133)) } - fn cost_xor(n: u64) -> InterpreterResult { + fn cost_xor(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 15, 129))) } - fn cost_not(n: u64) -> InterpreterResult { + fn cost_not(n: u64) -> Result { Ok(ExecutionCost::runtime(138)) } - fn cost_eq(n: u64) -> InterpreterResult { + fn cost_eq(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 7, 151))) } - fn cost_begin(n: u64) -> InterpreterResult { + fn cost_begin(n: u64) -> Result { Ok(ExecutionCost::runtime(151)) } - fn cost_hash160(n: u64) -> InterpreterResult { + fn cost_hash160(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 188))) } - fn cost_sha256(n: u64) -> InterpreterResult { + fn cost_sha256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 100))) } - fn cost_sha512(n: u64) -> InterpreterResult { + fn cost_sha512(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 176))) } - fn cost_sha512t256(n: u64) -> InterpreterResult { + fn cost_sha512t256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 56))) } - fn cost_keccak256(n: u64) -> InterpreterResult { + fn cost_keccak256(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 127))) } - fn cost_secp256k1recover(n: u64) -> InterpreterResult { + fn cost_secp256k1recover(n: u64) -> Result { Ok(ExecutionCost::runtime(8655)) } - fn cost_secp256k1verify(n: u64) -> InterpreterResult { + fn cost_secp256k1verify(n: u64) -> Result { Ok(ExecutionCost::runtime(8349)) } - fn cost_print(n: u64) -> InterpreterResult { + fn cost_print(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 15, 1458))) } - fn cost_some_cons(n: u64) -> InterpreterResult { + fn cost_some_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(199)) } - fn cost_ok_cons(n: u64) -> InterpreterResult { + fn cost_ok_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(199)) } - fn cost_err_cons(n: u64) -> InterpreterResult { + fn cost_err_cons(n: u64) -> Result { Ok(ExecutionCost::runtime(199)) } - fn cost_default_to(n: u64) -> InterpreterResult { + fn cost_default_to(n: u64) -> Result { Ok(ExecutionCost::runtime(268)) } - fn cost_unwrap_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(274)) } - fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_err_or_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(302)) } - fn cost_is_okay(n: u64) -> InterpreterResult { + fn cost_is_okay(n: u64) -> Result { Ok(ExecutionCost::runtime(258)) } - fn cost_is_none(n: u64) -> InterpreterResult { + fn cost_is_none(n: u64) -> Result { Ok(ExecutionCost::runtime(214)) } - fn cost_is_err(n: u64) -> InterpreterResult { + fn cost_is_err(n: u64) -> Result { Ok(ExecutionCost::runtime(245)) } - fn cost_is_some(n: u64) -> InterpreterResult { + fn cost_is_some(n: u64) -> Result { Ok(ExecutionCost::runtime(195)) } - fn cost_unwrap(n: u64) -> InterpreterResult { + fn cost_unwrap(n: u64) -> Result { Ok(ExecutionCost::runtime(252)) } - fn cost_unwrap_err(n: u64) -> InterpreterResult { + fn cost_unwrap_err(n: u64) -> Result { Ok(ExecutionCost::runtime(248)) } - fn cost_try_ret(n: u64) -> InterpreterResult { + fn cost_try_ret(n: u64) -> Result { Ok(ExecutionCost::runtime(240)) } - fn cost_match(n: u64) -> InterpreterResult { + fn cost_match(n: u64) -> Result { Ok(ExecutionCost::runtime(264)) } - fn cost_or(n: u64) -> InterpreterResult { + fn cost_or(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 3, 120))) } - fn cost_and(n: u64) -> InterpreterResult { + fn cost_and(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 3, 120))) } - fn cost_append(n: u64) -> InterpreterResult { + fn cost_append(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 73, 285))) } - fn cost_concat(n: u64) -> InterpreterResult { + fn cost_concat(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 37, 220))) } - fn cost_as_max_len(n: u64) -> InterpreterResult { + fn cost_as_max_len(n: u64) -> Result { Ok(ExecutionCost::runtime(475)) } - fn cost_contract_call(n: u64) -> InterpreterResult { + fn cost_contract_call(n: u64) -> Result { Ok(ExecutionCost::runtime(134)) } - fn cost_contract_of(n: u64) -> InterpreterResult { + fn cost_contract_of(n: u64) -> Result { Ok(ExecutionCost::runtime(13400)) } - fn cost_principal_of(n: u64) -> InterpreterResult { + fn cost_principal_of(n: u64) -> Result { Ok(ExecutionCost::runtime(984)) } - fn cost_at_block(n: u64) -> InterpreterResult { + fn cost_at_block(n: u64) -> Result { Ok(ExecutionCost { runtime: 1327, write_length: 0, @@ -419,7 +419,7 @@ impl CostValues for Costs3 { }) } - fn cost_load_contract(n: u64) -> InterpreterResult { + fn cost_load_contract(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 80), write_length: 0, @@ -430,7 +430,7 @@ impl CostValues for Costs3 { }) } - fn cost_create_map(n: u64) -> InterpreterResult { + fn cost_create_map(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1564), write_length: linear(n, 1, 1), @@ -440,7 +440,7 @@ impl CostValues for Costs3 { }) } - fn cost_create_var(n: u64) -> InterpreterResult { + fn cost_create_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 7, 2025), write_length: linear(n, 1, 1), @@ -450,7 +450,7 @@ impl CostValues for Costs3 { }) } - fn cost_create_nft(n: u64) -> InterpreterResult { + fn cost_create_nft(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1570), write_length: linear(n, 1, 1), @@ -460,7 +460,7 @@ impl CostValues for Costs3 { }) } - fn cost_create_ft(n: u64) -> InterpreterResult { + fn cost_create_ft(n: u64) -> Result { Ok(ExecutionCost { runtime: 1831, write_length: 1, @@ -470,7 +470,7 @@ impl CostValues for Costs3 { }) } - fn cost_fetch_entry(n: u64) -> InterpreterResult { + fn cost_fetch_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 1025), write_length: 0, @@ -480,7 +480,7 @@ impl CostValues for Costs3 { }) } - fn cost_set_entry(n: u64) -> InterpreterResult { + fn cost_set_entry(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 4, 1899), write_length: linear(n, 1, 1), @@ -490,7 +490,7 @@ impl CostValues for Costs3 { }) } - fn cost_fetch_var(n: u64) -> InterpreterResult { + fn cost_fetch_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 1, 468), write_length: 0, @@ -500,7 +500,7 @@ impl CostValues for Costs3 { }) } - fn cost_set_var(n: u64) -> InterpreterResult { + fn cost_set_var(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 5, 655), write_length: linear(n, 1, 1), @@ -510,7 +510,7 @@ impl CostValues for Costs3 { }) } - fn cost_contract_storage(n: u64) -> InterpreterResult { + fn cost_contract_storage(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 11, 7165), write_length: linear(n, 1, 1), @@ -520,7 +520,7 @@ impl CostValues for Costs3 { }) } - fn cost_block_info(n: u64) -> InterpreterResult { + fn cost_block_info(n: u64) -> Result { Ok(ExecutionCost { runtime: 6321, write_length: 0, @@ -530,7 +530,7 @@ impl CostValues for Costs3 { }) } - fn cost_stx_balance(n: u64) -> InterpreterResult { + fn cost_stx_balance(n: u64) -> Result { Ok(ExecutionCost { runtime: 4294, write_length: 0, @@ -540,7 +540,7 @@ impl CostValues for Costs3 { }) } - fn cost_stx_transfer(n: u64) -> InterpreterResult { + fn cost_stx_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: 4640, write_length: 1, @@ -550,7 +550,7 @@ impl CostValues for Costs3 { }) } - fn cost_ft_mint(n: u64) -> InterpreterResult { + fn cost_ft_mint(n: u64) -> Result { Ok(ExecutionCost { runtime: 1479, write_length: 1, @@ -560,7 +560,7 @@ impl CostValues for Costs3 { }) } - fn cost_ft_transfer(n: u64) -> InterpreterResult { + fn cost_ft_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: 549, write_length: 1, @@ -570,7 +570,7 @@ impl CostValues for Costs3 { }) } - fn cost_ft_balance(n: u64) -> InterpreterResult { + fn cost_ft_balance(n: u64) -> Result { Ok(ExecutionCost { runtime: 479, write_length: 0, @@ -580,7 +580,7 @@ impl CostValues for Costs3 { }) } - fn cost_nft_mint(n: u64) -> InterpreterResult { + fn cost_nft_mint(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 575), write_length: 1, @@ -590,7 +590,7 @@ impl CostValues for Costs3 { }) } - fn cost_nft_transfer(n: u64) -> InterpreterResult { + fn cost_nft_transfer(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 572), write_length: 1, @@ -600,7 +600,7 @@ impl CostValues for Costs3 { }) } - fn cost_nft_owner(n: u64) -> InterpreterResult { + fn cost_nft_owner(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 795), write_length: 0, @@ -610,7 +610,7 @@ impl CostValues for Costs3 { }) } - fn cost_ft_get_supply(n: u64) -> InterpreterResult { + fn cost_ft_get_supply(n: u64) -> Result { Ok(ExecutionCost { runtime: 420, write_length: 0, @@ -620,7 +620,7 @@ impl CostValues for Costs3 { }) } - fn cost_ft_burn(n: u64) -> InterpreterResult { + fn cost_ft_burn(n: u64) -> Result { Ok(ExecutionCost { runtime: 549, write_length: 1, @@ -630,7 +630,7 @@ impl CostValues for Costs3 { }) } - fn cost_nft_burn(n: u64) -> InterpreterResult { + fn cost_nft_burn(n: u64) -> Result { Ok(ExecutionCost { runtime: linear(n, 9, 572), write_length: 1, @@ -640,7 +640,7 @@ impl CostValues for Costs3 { }) } - fn poison_microblock(n: u64) -> InterpreterResult { + fn poison_microblock(n: u64) -> Result { Ok(ExecutionCost { runtime: 17485, write_length: 1, @@ -650,51 +650,51 @@ impl CostValues for Costs3 { }) } - fn cost_buff_to_int_le(n: u64) -> InterpreterResult { + fn cost_buff_to_int_le(n: u64) -> Result { Ok(ExecutionCost::runtime(141)) } - fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { + fn cost_buff_to_uint_le(n: u64) -> Result { Ok(ExecutionCost::runtime(141)) } - fn cost_buff_to_int_be(n: u64) -> InterpreterResult { + fn cost_buff_to_int_be(n: u64) -> Result { Ok(ExecutionCost::runtime(141)) } - fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { + fn cost_buff_to_uint_be(n: u64) -> Result { Ok(ExecutionCost::runtime(141)) } - fn cost_is_standard(n: u64) -> InterpreterResult { + fn cost_is_standard(n: u64) -> Result { Ok(ExecutionCost::runtime(127)) } - fn cost_principal_destruct(n: u64) -> InterpreterResult { + fn cost_principal_destruct(n: u64) -> Result { Ok(ExecutionCost::runtime(314)) } - fn cost_principal_construct(n: u64) -> InterpreterResult { + fn cost_principal_construct(n: u64) -> Result { Ok(ExecutionCost::runtime(398)) } - fn cost_string_to_int(n: u64) -> InterpreterResult { + fn cost_string_to_int(n: u64) -> Result { Ok(ExecutionCost::runtime(168)) } - fn cost_string_to_uint(n: u64) -> InterpreterResult { + fn cost_string_to_uint(n: u64) -> Result { Ok(ExecutionCost::runtime(168)) } - fn cost_int_to_ascii(n: u64) -> InterpreterResult { + fn cost_int_to_ascii(n: u64) -> Result { Ok(ExecutionCost::runtime(147)) } - fn cost_int_to_utf8(n: u64) -> InterpreterResult { + fn cost_int_to_utf8(n: u64) -> Result { Ok(ExecutionCost::runtime(181)) } - fn cost_burn_block_info(n: u64) -> InterpreterResult { + fn cost_burn_block_info(n: u64) -> Result { Ok(ExecutionCost { runtime: 96479, write_length: 0, @@ -704,7 +704,7 @@ impl CostValues for Costs3 { }) } - fn cost_stx_account(n: u64) -> InterpreterResult { + fn cost_stx_account(n: u64) -> Result { Ok(ExecutionCost { runtime: 4654, write_length: 0, @@ -714,19 +714,19 @@ impl CostValues for Costs3 { }) } - fn cost_slice(n: u64) -> InterpreterResult { + fn cost_slice(n: u64) -> Result { Ok(ExecutionCost::runtime(448)) } - fn cost_to_consensus_buff(n: u64) -> InterpreterResult { + fn cost_to_consensus_buff(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 233))) } - fn cost_from_consensus_buff(n: u64) -> InterpreterResult { + fn cost_from_consensus_buff(n: u64) -> Result { Ok(ExecutionCost::runtime(nlogn(n, 3, 185)?)) } - fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { + fn cost_stx_transfer_memo(n: u64) -> Result { Ok(ExecutionCost { runtime: 4709, write_length: 1, @@ -736,51 +736,51 @@ impl CostValues for Costs3 { }) } - fn cost_replace_at(n: u64) -> InterpreterResult { + fn cost_replace_at(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 1, 561))) } - fn cost_as_contract(n: u64) -> InterpreterResult { + fn cost_as_contract(n: u64) -> Result { Ok(ExecutionCost::runtime(138)) } - fn cost_bitwise_and(n: u64) -> InterpreterResult { + fn cost_bitwise_and(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 15, 129))) } - fn cost_bitwise_or(n: u64) -> InterpreterResult { + fn cost_bitwise_or(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 15, 129))) } - fn cost_bitwise_not(n: u64) -> InterpreterResult { + fn cost_bitwise_not(n: u64) -> Result { Ok(ExecutionCost::runtime(147)) } - fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { + fn cost_bitwise_left_shift(n: u64) -> Result { Ok(ExecutionCost::runtime(167)) } - fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { + fn cost_bitwise_right_shift(n: u64) -> Result { Ok(ExecutionCost::runtime(167)) } - fn cost_contract_hash(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_contract_hash(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_to_ascii(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_to_ascii(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_restrict_assets(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_restrict_assets(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_as_contract_safe(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_as_contract_safe(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } - fn cost_secp256r1verify(n: u64) -> InterpreterResult { - Err(RuntimeErrorType::NotImplemented.into()) + fn cost_secp256r1verify(n: u64) -> Result { + Err(RuntimeError::NotImplemented.into()) } } diff --git a/clarity/src/vm/costs/costs_4.rs b/clarity/src/vm/costs/costs_4.rs index bdd1d5bd427..f7a85055683 100644 --- a/clarity/src/vm/costs/costs_4.rs +++ b/clarity/src/vm/costs/costs_4.rs @@ -22,433 +22,433 @@ use super::cost_functions::CostValues; use super::costs_3::Costs3; use super::ExecutionCost; use crate::vm::costs::cost_functions::linear; -use crate::vm::errors::InterpreterResult; +use crate::vm::errors::VmExecutionError; pub struct Costs4; impl CostValues for Costs4 { // Forward all costs to Costs3 to avoid duplication. - fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + fn cost_analysis_type_annotate(n: u64) -> Result { Costs3::cost_analysis_type_annotate(n) } - fn cost_analysis_type_check(n: u64) -> InterpreterResult { + fn cost_analysis_type_check(n: u64) -> Result { Costs3::cost_analysis_type_check(n) } - fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + fn cost_analysis_type_lookup(n: u64) -> Result { Costs3::cost_analysis_type_lookup(n) } - fn cost_analysis_visit(n: u64) -> InterpreterResult { + fn cost_analysis_visit(n: u64) -> Result { Costs3::cost_analysis_visit(n) } - fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + fn cost_analysis_iterable_func(n: u64) -> Result { Costs3::cost_analysis_iterable_func(n) } - fn cost_analysis_option_cons(n: u64) -> InterpreterResult { + fn cost_analysis_option_cons(n: u64) -> Result { Costs3::cost_analysis_option_cons(n) } - fn cost_analysis_option_check(n: u64) -> InterpreterResult { + fn cost_analysis_option_check(n: u64) -> Result { Costs3::cost_analysis_option_check(n) } - fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + fn cost_analysis_bind_name(n: u64) -> Result { Costs3::cost_analysis_bind_name(n) } - fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_list_items_check(n: u64) -> Result { Costs3::cost_analysis_list_items_check(n) } - fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_get(n: u64) -> Result { Costs3::cost_analysis_check_tuple_get(n) } - fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_merge(n: u64) -> Result { Costs3::cost_analysis_check_tuple_merge(n) } - fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + fn cost_analysis_check_tuple_cons(n: u64) -> Result { Costs3::cost_analysis_check_tuple_cons(n) } - fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + fn cost_analysis_tuple_items_check(n: u64) -> Result { Costs3::cost_analysis_tuple_items_check(n) } - fn cost_analysis_check_let(n: u64) -> InterpreterResult { + fn cost_analysis_check_let(n: u64) -> Result { Costs3::cost_analysis_check_let(n) } - fn cost_analysis_lookup_function(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function(n: u64) -> Result { Costs3::cost_analysis_lookup_function(n) } - fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_function_types(n: u64) -> Result { Costs3::cost_analysis_lookup_function_types(n) } - fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_const(n: u64) -> Result { Costs3::cost_analysis_lookup_variable_const(n) } - fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_analysis_lookup_variable_depth(n: u64) -> Result { Costs3::cost_analysis_lookup_variable_depth(n) } - fn cost_ast_parse(n: u64) -> InterpreterResult { + fn cost_ast_parse(n: u64) -> Result { Costs3::cost_ast_parse(n) } - fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + fn cost_ast_cycle_detection(n: u64) -> Result { Costs3::cost_ast_cycle_detection(n) } - fn cost_analysis_storage(n: u64) -> InterpreterResult { + fn cost_analysis_storage(n: u64) -> Result { Costs3::cost_analysis_storage(n) } - fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + fn cost_analysis_use_trait_entry(n: u64) -> Result { Costs3::cost_analysis_use_trait_entry(n) } - fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + fn cost_analysis_get_function_entry(n: u64) -> Result { Costs3::cost_analysis_get_function_entry(n) } - fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + fn cost_analysis_fetch_contract_entry(n: u64) -> Result { Costs3::cost_analysis_fetch_contract_entry(n) } - fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + fn cost_lookup_variable_depth(n: u64) -> Result { Costs3::cost_lookup_variable_depth(n) } - fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + fn cost_lookup_variable_size(n: u64) -> Result { Costs3::cost_lookup_variable_size(n) } - fn cost_lookup_function(n: u64) -> InterpreterResult { + fn cost_lookup_function(n: u64) -> Result { Costs3::cost_lookup_function(n) } - fn cost_bind_name(n: u64) -> InterpreterResult { + fn cost_bind_name(n: u64) -> Result { Costs3::cost_bind_name(n) } - fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + fn cost_inner_type_check_cost(n: u64) -> Result { Costs3::cost_inner_type_check_cost(n) } - fn cost_user_function_application(n: u64) -> InterpreterResult { + fn cost_user_function_application(n: u64) -> Result { Costs3::cost_user_function_application(n) } - fn cost_let(n: u64) -> InterpreterResult { + fn cost_let(n: u64) -> Result { Costs3::cost_let(n) } - fn cost_if(n: u64) -> InterpreterResult { + fn cost_if(n: u64) -> Result { Costs3::cost_if(n) } - fn cost_asserts(n: u64) -> InterpreterResult { + fn cost_asserts(n: u64) -> Result { Costs3::cost_asserts(n) } - fn cost_map(n: u64) -> InterpreterResult { + fn cost_map(n: u64) -> Result { Costs3::cost_map(n) } - fn cost_filter(n: u64) -> InterpreterResult { + fn cost_filter(n: u64) -> Result { Costs3::cost_filter(n) } - fn cost_len(n: u64) -> InterpreterResult { + fn cost_len(n: u64) -> Result { Costs3::cost_len(n) } - fn cost_element_at(n: u64) -> InterpreterResult { + fn cost_element_at(n: u64) -> Result { Costs3::cost_element_at(n) } - fn cost_index_of(n: u64) -> InterpreterResult { + fn cost_index_of(n: u64) -> Result { Costs3::cost_index_of(n) } - fn cost_fold(n: u64) -> InterpreterResult { + fn cost_fold(n: u64) -> Result { Costs3::cost_fold(n) } - fn cost_list_cons(n: u64) -> InterpreterResult { + fn cost_list_cons(n: u64) -> Result { Costs3::cost_list_cons(n) } - fn cost_type_parse_step(n: u64) -> InterpreterResult { + fn cost_type_parse_step(n: u64) -> Result { Costs3::cost_type_parse_step(n) } - fn cost_tuple_get(n: u64) -> InterpreterResult { + fn cost_tuple_get(n: u64) -> Result { Costs3::cost_tuple_get(n) } - fn cost_tuple_merge(n: u64) -> InterpreterResult { + fn cost_tuple_merge(n: u64) -> Result { Costs3::cost_tuple_merge(n) } - fn cost_tuple_cons(n: u64) -> InterpreterResult { + fn cost_tuple_cons(n: u64) -> Result { Costs3::cost_tuple_cons(n) } - fn cost_add(n: u64) -> InterpreterResult { + fn cost_add(n: u64) -> Result { Costs3::cost_add(n) } - fn cost_sub(n: u64) -> InterpreterResult { + fn cost_sub(n: u64) -> Result { Costs3::cost_sub(n) } - fn cost_mul(n: u64) -> InterpreterResult { + fn cost_mul(n: u64) -> Result { Costs3::cost_mul(n) } - fn cost_div(n: u64) -> InterpreterResult { + fn cost_div(n: u64) -> Result { Costs3::cost_div(n) } - fn cost_geq(n: u64) -> InterpreterResult { + fn cost_geq(n: u64) -> Result { Costs3::cost_geq(n) } - fn cost_leq(n: u64) -> InterpreterResult { + fn cost_leq(n: u64) -> Result { Costs3::cost_leq(n) } - fn cost_le(n: u64) -> InterpreterResult { + fn cost_le(n: u64) -> Result { Costs3::cost_le(n) } - fn cost_ge(n: u64) -> InterpreterResult { + fn cost_ge(n: u64) -> Result { Costs3::cost_ge(n) } - fn cost_int_cast(n: u64) -> InterpreterResult { + fn cost_int_cast(n: u64) -> Result { Costs3::cost_int_cast(n) } - fn cost_mod(n: u64) -> InterpreterResult { + fn cost_mod(n: u64) -> Result { Costs3::cost_mod(n) } - fn cost_pow(n: u64) -> InterpreterResult { + fn cost_pow(n: u64) -> Result { Costs3::cost_pow(n) } - fn cost_sqrti(n: u64) -> InterpreterResult { + fn cost_sqrti(n: u64) -> Result { Costs3::cost_sqrti(n) } - fn cost_log2(n: u64) -> InterpreterResult { + fn cost_log2(n: u64) -> Result { Costs3::cost_log2(n) } - fn cost_xor(n: u64) -> InterpreterResult { + fn cost_xor(n: u64) -> Result { Costs3::cost_xor(n) } - fn cost_not(n: u64) -> InterpreterResult { + fn cost_not(n: u64) -> Result { Costs3::cost_not(n) } - fn cost_eq(n: u64) -> InterpreterResult { + fn cost_eq(n: u64) -> Result { Costs3::cost_eq(n) } - fn cost_begin(n: u64) -> InterpreterResult { + fn cost_begin(n: u64) -> Result { Costs3::cost_begin(n) } - fn cost_hash160(n: u64) -> InterpreterResult { + fn cost_hash160(n: u64) -> Result { Costs3::cost_hash160(n) } - fn cost_sha256(n: u64) -> InterpreterResult { + fn cost_sha256(n: u64) -> Result { Costs3::cost_sha256(n) } - fn cost_sha512(n: u64) -> InterpreterResult { + fn cost_sha512(n: u64) -> Result { Costs3::cost_sha512(n) } - fn cost_sha512t256(n: u64) -> InterpreterResult { + fn cost_sha512t256(n: u64) -> Result { Costs3::cost_sha512t256(n) } - fn cost_keccak256(n: u64) -> InterpreterResult { + fn cost_keccak256(n: u64) -> Result { Costs3::cost_keccak256(n) } - fn cost_secp256k1recover(n: u64) -> InterpreterResult { + fn cost_secp256k1recover(n: u64) -> Result { Costs3::cost_secp256k1recover(n) } - fn cost_secp256k1verify(n: u64) -> InterpreterResult { + fn cost_secp256k1verify(n: u64) -> Result { Costs3::cost_secp256k1verify(n) } - fn cost_print(n: u64) -> InterpreterResult { + fn cost_print(n: u64) -> Result { Costs3::cost_print(n) } - fn cost_some_cons(n: u64) -> InterpreterResult { + fn cost_some_cons(n: u64) -> Result { Costs3::cost_some_cons(n) } - fn cost_ok_cons(n: u64) -> InterpreterResult { + fn cost_ok_cons(n: u64) -> Result { Costs3::cost_ok_cons(n) } - fn cost_err_cons(n: u64) -> InterpreterResult { + fn cost_err_cons(n: u64) -> Result { Costs3::cost_err_cons(n) } - fn cost_default_to(n: u64) -> InterpreterResult { + fn cost_default_to(n: u64) -> Result { Costs3::cost_default_to(n) } - fn cost_unwrap_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_ret(n: u64) -> Result { Costs3::cost_unwrap_ret(n) } - fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + fn cost_unwrap_err_or_ret(n: u64) -> Result { Costs3::cost_unwrap_err_or_ret(n) } - fn cost_is_okay(n: u64) -> InterpreterResult { + fn cost_is_okay(n: u64) -> Result { Costs3::cost_is_okay(n) } - fn cost_is_none(n: u64) -> InterpreterResult { + fn cost_is_none(n: u64) -> Result { Costs3::cost_is_none(n) } - fn cost_is_err(n: u64) -> InterpreterResult { + fn cost_is_err(n: u64) -> Result { Costs3::cost_is_err(n) } - fn cost_is_some(n: u64) -> InterpreterResult { + fn cost_is_some(n: u64) -> Result { Costs3::cost_is_some(n) } - fn cost_unwrap(n: u64) -> InterpreterResult { + fn cost_unwrap(n: u64) -> Result { Costs3::cost_unwrap(n) } - fn cost_unwrap_err(n: u64) -> InterpreterResult { + fn cost_unwrap_err(n: u64) -> Result { Costs3::cost_unwrap_err(n) } - fn cost_try_ret(n: u64) -> InterpreterResult { + fn cost_try_ret(n: u64) -> Result { Costs3::cost_try_ret(n) } - fn cost_match(n: u64) -> InterpreterResult { + fn cost_match(n: u64) -> Result { Costs3::cost_match(n) } - fn cost_or(n: u64) -> InterpreterResult { + fn cost_or(n: u64) -> Result { Costs3::cost_or(n) } - fn cost_and(n: u64) -> InterpreterResult { + fn cost_and(n: u64) -> Result { Costs3::cost_and(n) } - fn cost_append(n: u64) -> InterpreterResult { + fn cost_append(n: u64) -> Result { Costs3::cost_append(n) } - fn cost_concat(n: u64) -> InterpreterResult { + fn cost_concat(n: u64) -> Result { Costs3::cost_concat(n) } - fn cost_as_max_len(n: u64) -> InterpreterResult { + fn cost_as_max_len(n: u64) -> Result { Costs3::cost_as_max_len(n) } - fn cost_contract_call(n: u64) -> InterpreterResult { + fn cost_contract_call(n: u64) -> Result { Costs3::cost_contract_call(n) } - fn cost_contract_of(n: u64) -> InterpreterResult { + fn cost_contract_of(n: u64) -> Result { Costs3::cost_contract_of(n) } - fn cost_principal_of(n: u64) -> InterpreterResult { + fn cost_principal_of(n: u64) -> Result { Costs3::cost_principal_of(n) } - fn cost_at_block(n: u64) -> InterpreterResult { + fn cost_at_block(n: u64) -> Result { Costs3::cost_at_block(n) } - fn cost_load_contract(n: u64) -> InterpreterResult { + fn cost_load_contract(n: u64) -> Result { Costs3::cost_load_contract(n) } - fn cost_create_map(n: u64) -> InterpreterResult { + fn cost_create_map(n: u64) -> Result { Costs3::cost_create_map(n) } - fn cost_create_var(n: u64) -> InterpreterResult { + fn cost_create_var(n: u64) -> Result { Costs3::cost_create_var(n) } - fn cost_create_nft(n: u64) -> InterpreterResult { + fn cost_create_nft(n: u64) -> Result { Costs3::cost_create_nft(n) } - fn cost_create_ft(n: u64) -> InterpreterResult { + fn cost_create_ft(n: u64) -> Result { Costs3::cost_create_ft(n) } - fn cost_fetch_entry(n: u64) -> InterpreterResult { + fn cost_fetch_entry(n: u64) -> Result { Costs3::cost_fetch_entry(n) } - fn cost_set_entry(n: u64) -> InterpreterResult { + fn cost_set_entry(n: u64) -> Result { Costs3::cost_set_entry(n) } - fn cost_fetch_var(n: u64) -> InterpreterResult { + fn cost_fetch_var(n: u64) -> Result { Costs3::cost_fetch_var(n) } - fn cost_set_var(n: u64) -> InterpreterResult { + fn cost_set_var(n: u64) -> Result { Costs3::cost_set_var(n) } - fn cost_contract_storage(n: u64) -> InterpreterResult { + fn cost_contract_storage(n: u64) -> Result { Costs3::cost_contract_storage(n) } - fn cost_block_info(n: u64) -> InterpreterResult { + fn cost_block_info(n: u64) -> Result { Costs3::cost_block_info(n) } - fn cost_stx_balance(n: u64) -> InterpreterResult { + fn cost_stx_balance(n: u64) -> Result { Costs3::cost_stx_balance(n) } - fn cost_stx_transfer(n: u64) -> InterpreterResult { + fn cost_stx_transfer(n: u64) -> Result { Costs3::cost_stx_transfer(n) } - fn cost_ft_mint(n: u64) -> InterpreterResult { + fn cost_ft_mint(n: u64) -> Result { Costs3::cost_ft_mint(n) } - fn cost_ft_transfer(n: u64) -> InterpreterResult { + fn cost_ft_transfer(n: u64) -> Result { Costs3::cost_ft_transfer(n) } - fn cost_ft_balance(n: u64) -> InterpreterResult { + fn cost_ft_balance(n: u64) -> Result { Costs3::cost_ft_balance(n) } - fn cost_ft_get_supply(n: u64) -> InterpreterResult { + fn cost_ft_get_supply(n: u64) -> Result { Costs3::cost_ft_get_supply(n) } - fn cost_ft_burn(n: u64) -> InterpreterResult { + fn cost_ft_burn(n: u64) -> Result { Costs3::cost_ft_burn(n) } - fn cost_nft_mint(n: u64) -> InterpreterResult { + fn cost_nft_mint(n: u64) -> Result { Costs3::cost_nft_mint(n) } - fn cost_nft_transfer(n: u64) -> InterpreterResult { + fn cost_nft_transfer(n: u64) -> Result { Costs3::cost_nft_transfer(n) } - fn cost_nft_owner(n: u64) -> InterpreterResult { + fn cost_nft_owner(n: u64) -> Result { Costs3::cost_nft_owner(n) } - fn cost_nft_burn(n: u64) -> InterpreterResult { + fn cost_nft_burn(n: u64) -> Result { Costs3::cost_nft_burn(n) } - fn poison_microblock(n: u64) -> InterpreterResult { + fn poison_microblock(n: u64) -> Result { Costs3::poison_microblock(n) } - fn cost_buff_to_int_le(n: u64) -> InterpreterResult { + fn cost_buff_to_int_le(n: u64) -> Result { Costs3::cost_buff_to_int_le(n) } - fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { + fn cost_buff_to_uint_le(n: u64) -> Result { Costs3::cost_buff_to_uint_le(n) } - fn cost_buff_to_int_be(n: u64) -> InterpreterResult { + fn cost_buff_to_int_be(n: u64) -> Result { Costs3::cost_buff_to_int_be(n) } - fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { + fn cost_buff_to_uint_be(n: u64) -> Result { Costs3::cost_buff_to_uint_be(n) } - fn cost_is_standard(n: u64) -> InterpreterResult { + fn cost_is_standard(n: u64) -> Result { Costs3::cost_is_standard(n) } - fn cost_principal_destruct(n: u64) -> InterpreterResult { + fn cost_principal_destruct(n: u64) -> Result { Costs3::cost_principal_destruct(n) } - fn cost_principal_construct(n: u64) -> InterpreterResult { + fn cost_principal_construct(n: u64) -> Result { Costs3::cost_principal_construct(n) } - fn cost_string_to_int(n: u64) -> InterpreterResult { + fn cost_string_to_int(n: u64) -> Result { Costs3::cost_string_to_int(n) } - fn cost_string_to_uint(n: u64) -> InterpreterResult { + fn cost_string_to_uint(n: u64) -> Result { Costs3::cost_string_to_uint(n) } - fn cost_int_to_ascii(n: u64) -> InterpreterResult { + fn cost_int_to_ascii(n: u64) -> Result { Costs3::cost_int_to_ascii(n) } - fn cost_int_to_utf8(n: u64) -> InterpreterResult { + fn cost_int_to_utf8(n: u64) -> Result { Costs3::cost_int_to_utf8(n) } - fn cost_burn_block_info(n: u64) -> InterpreterResult { + fn cost_burn_block_info(n: u64) -> Result { Costs3::cost_burn_block_info(n) } - fn cost_stx_account(n: u64) -> InterpreterResult { + fn cost_stx_account(n: u64) -> Result { Costs3::cost_stx_account(n) } - fn cost_slice(n: u64) -> InterpreterResult { + fn cost_slice(n: u64) -> Result { Costs3::cost_slice(n) } - fn cost_to_consensus_buff(n: u64) -> InterpreterResult { + fn cost_to_consensus_buff(n: u64) -> Result { Costs3::cost_to_consensus_buff(n) } - fn cost_from_consensus_buff(n: u64) -> InterpreterResult { + fn cost_from_consensus_buff(n: u64) -> Result { Costs3::cost_from_consensus_buff(n) } - fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { + fn cost_stx_transfer_memo(n: u64) -> Result { Costs3::cost_stx_transfer_memo(n) } - fn cost_replace_at(n: u64) -> InterpreterResult { + fn cost_replace_at(n: u64) -> Result { Costs3::cost_replace_at(n) } - fn cost_as_contract(n: u64) -> InterpreterResult { + fn cost_as_contract(n: u64) -> Result { Costs3::cost_as_contract(n) } - fn cost_bitwise_and(n: u64) -> InterpreterResult { + fn cost_bitwise_and(n: u64) -> Result { Costs3::cost_bitwise_and(n) } - fn cost_bitwise_or(n: u64) -> InterpreterResult { + fn cost_bitwise_or(n: u64) -> Result { Costs3::cost_bitwise_or(n) } - fn cost_bitwise_not(n: u64) -> InterpreterResult { + fn cost_bitwise_not(n: u64) -> Result { Costs3::cost_bitwise_not(n) } - fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { + fn cost_bitwise_left_shift(n: u64) -> Result { Costs3::cost_bitwise_left_shift(n) } - fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { + fn cost_bitwise_right_shift(n: u64) -> Result { Costs3::cost_bitwise_right_shift(n) } // --- New in costs-4 --- - fn cost_contract_hash(_n: u64) -> InterpreterResult { + fn cost_contract_hash(_n: u64) -> Result { Ok(ExecutionCost { runtime: 188, write_length: 0, @@ -458,19 +458,19 @@ impl CostValues for Costs4 { }) } - fn cost_to_ascii(n: u64) -> InterpreterResult { + fn cost_to_ascii(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 16, 150))) } - fn cost_restrict_assets(n: u64) -> InterpreterResult { + fn cost_restrict_assets(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 125, 750))) } - fn cost_as_contract_safe(n: u64) -> InterpreterResult { + fn cost_as_contract_safe(n: u64) -> Result { Ok(ExecutionCost::runtime(linear(n, 125, 888))) } - fn cost_secp256r1verify(n: u64) -> InterpreterResult { + fn cost_secp256r1verify(n: u64) -> Result { Ok(ExecutionCost::runtime(51750)) } } diff --git a/clarity/src/vm/costs/mod.rs b/clarity/src/vm/costs/mod.rs index 669f6f483dc..4e006c890c1 100644 --- a/clarity/src/vm/costs/mod.rs +++ b/clarity/src/vm/costs/mod.rs @@ -19,6 +19,7 @@ use std::{cmp, fmt}; pub use clarity_types::errors::CostErrors; pub use clarity_types::execution_cost::{CostOverflowingMath, ExecutionCost}; +use clarity_types::VmExecutionError; use costs_1::Costs1; use costs_2::Costs2; use costs_2_testnet::Costs2Testnet; @@ -28,13 +29,12 @@ use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use stacks_common::types::StacksEpochId; -use super::errors::{CheckErrors, RuntimeErrorType}; +use super::errors::{CheckErrorKind, RuntimeError}; use crate::boot_util::boot_code_id; use crate::vm::contexts::{ContractContext, GlobalContext}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::database::clarity_store::NullBackingStore; use crate::vm::database::ClarityDatabase; -use crate::vm::errors::InterpreterResult; use crate::vm::types::signatures::FunctionType::Fixed; use crate::vm::types::signatures::TupleTypeSignature; use crate::vm::types::Value::UInt; @@ -215,8 +215,9 @@ impl DefaultVersion { }; r.map_err(|e| { let e = match e { - crate::vm::errors::Error::Runtime(RuntimeErrorType::NotImplemented, _) => { - CheckErrors::UndefinedFunction(cost_function_ref.function_name.clone()).into() + VmExecutionError::Runtime(RuntimeError::NotImplemented, _) => { + CheckErrorKind::UndefinedFunction(cost_function_ref.function_name.clone()) + .into() } other => other, }; @@ -852,6 +853,49 @@ impl LimitedCostTracker { }; Ok(result) } + + /// Create a [`LimitedCostTracker`] given an epoch id and an execution cost limit for testing purpose + /// + /// Autoconfigure itself loading all clarity const functions without the need of passing a clarity database + #[cfg(any(test, feature = "testing"))] + pub fn new_with_limit(epoch_id: StacksEpochId, limit: ExecutionCost) -> LimitedCostTracker { + use stacks_common::consts::CHAIN_ID_TESTNET; + + let contract_name = LimitedCostTracker::default_cost_contract_for_epoch(epoch_id) + .expect("Failed retrieving cost contract!"); + let boot_costs_id = boot_code_id(&contract_name, false); + + let version = DefaultVersion::try_from(false, &boot_costs_id) + .expect("Failed defining default version!"); + + let mut cost_functions = HashMap::new(); + for each in ClarityCostFunction::ALL { + let evaluator = ClarityCostFunctionEvaluator::Default( + ClarityCostFunctionReference { + contract_id: boot_costs_id.clone(), + function_name: each.get_name(), + }, + each.clone(), + version, + ); + cost_functions.insert(each, evaluator); + } + + let cost_tracker = TrackerData { + cost_function_references: cost_functions, + cost_contracts: HashMap::new(), + contract_call_circuits: HashMap::new(), + limit, + memory_limit: CLARITY_MEMORY_LIMIT, + total: ExecutionCost::ZERO, + memory: 0, + epoch: epoch_id, + mainnet: false, + chain_id: CHAIN_ID_TESTNET, + }; + + LimitedCostTracker::Limited(cost_tracker) + } } impl TrackerData { @@ -1004,7 +1048,7 @@ impl LimitedCostTracker { pub fn parse_cost( cost_function_name: &str, - eval_result: InterpreterResult>, + eval_result: Result, VmExecutionError>, ) -> Result { match eval_result { Ok(Some(Value::Tuple(data))) => { diff --git a/clarity/src/vm/coverage.rs b/clarity/src/vm/coverage.rs index 15f41b6693a..afbf45a87aa 100644 --- a/clarity/src/vm/coverage.rs +++ b/clarity/src/vm/coverage.rs @@ -241,7 +241,7 @@ impl EvalHook for CoverageReporter { _env: &mut crate::vm::Environment, _context: &crate::vm::LocalContext, _expr: &SymbolicExpression, - _res: &core::result::Result, + _res: &core::result::Result, ) { } diff --git a/clarity/src/vm/database/clarity_db.rs b/clarity/src/vm/database/clarity_db.rs index 5df22ba21ce..ba9af6ff763 100644 --- a/clarity/src/vm/database/clarity_db.rs +++ b/clarity/src/vm/database/clarity_db.rs @@ -36,9 +36,7 @@ use crate::vm::database::structures::{ FungibleTokenMetadata, NonFungibleTokenMetadata, STXBalance, STXBalanceSnapshot, }; use crate::vm::database::{ClarityBackingStore, RollbackWrapper}; -use crate::vm::errors::{ - CheckErrors, Error, InterpreterError, InterpreterResult as Result, RuntimeErrorType, -}; +use crate::vm::errors::{CheckErrorKind, RuntimeError, VmExecutionError, VmInternalError}; use crate::vm::representations::ClarityName; use crate::vm::types::serialization::NONE_SERIALIZATION_LEN; use crate::vm::types::{ @@ -478,12 +476,12 @@ impl<'a> ClarityDatabase<'a> { } /// Commit current key-value wrapper layer - pub fn commit(&mut self) -> Result<()> { + pub fn commit(&mut self) -> Result<(), VmExecutionError> { self.store.commit().map_err(|e| e.into()) } /// Drop current key-value wrapper layer - pub fn roll_back(&mut self) -> Result<()> { + pub fn roll_back(&mut self) -> Result<(), VmExecutionError> { self.store.rollback().map_err(|e| e.into()) } @@ -491,11 +489,15 @@ impl<'a> ClarityDatabase<'a> { &mut self, bhh: StacksBlockId, query_pending_data: bool, - ) -> Result { + ) -> Result { self.store.set_block_hash(bhh, query_pending_data) } - pub fn put_data(&mut self, key: &str, value: &T) -> Result<()> { + pub fn put_data( + &mut self, + key: &str, + value: &T, + ) -> Result<(), VmExecutionError> { self.store.put_data(key, &value.serialize()) } @@ -504,27 +506,32 @@ impl<'a> ClarityDatabase<'a> { &mut self, key: &str, value: &T, - ) -> Result { + ) -> Result { let serialized = value.serialize(); self.store.put_data(key, &serialized)?; Ok(byte_len_of_serialization(&serialized)) } - pub fn get_data(&mut self, key: &str) -> Result> + pub fn get_data(&mut self, key: &str) -> Result, VmExecutionError> where T: ClarityDeserializable, { self.store.get_data::(key) } - pub fn get_data_by_hash(&mut self, hash: &TrieHash) -> Result> + pub fn get_data_by_hash(&mut self, hash: &TrieHash) -> Result, VmExecutionError> where T: ClarityDeserializable, { self.store.get_data_by_hash::(hash) } - pub fn put_value(&mut self, key: &str, value: Value, epoch: &StacksEpochId) -> Result<()> { + pub fn put_value( + &mut self, + key: &str, + value: Value, + epoch: &StacksEpochId, + ) -> Result<(), VmExecutionError> { self.put_value_with_size(key, value, epoch)?; Ok(()) } @@ -534,19 +541,19 @@ impl<'a> ClarityDatabase<'a> { key: &str, value: Value, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { let sanitize = epoch.value_sanitizing(); let mut pre_sanitized_size = None; let serialized = if sanitize { let value_size = value .serialized_size() - .map_err(|e| InterpreterError::Expect(e.to_string()))? + .map_err(|e| VmInternalError::Expect(e.to_string()))? as u64; let (sanitized_value, did_sanitize) = Value::sanitize_value(epoch, &TypeSignature::type_of(&value)?, value) - .ok_or_else(|| CheckErrors::CouldNotDetermineType)?; + .ok_or_else(|| CheckErrorKind::CouldNotDetermineType)?; // if data needed to be sanitized *charge* for the unsanitized cost if did_sanitize { pre_sanitized_size = Some(value_size); @@ -568,13 +575,16 @@ impl<'a> ClarityDatabase<'a> { key: &str, expected: &TypeSignature, epoch: &StacksEpochId, - ) -> Result> { + ) -> Result, VmExecutionError> { self.store .get_value(key, expected, epoch) - .map_err(|e| InterpreterError::DBError(e.to_string()).into()) + .map_err(|e| VmInternalError::DBError(e.to_string()).into()) } - pub fn get_data_with_proof(&mut self, key: &str) -> Result)>> + pub fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError> where T: ClarityDeserializable, { @@ -584,7 +594,7 @@ impl<'a> ClarityDatabase<'a> { pub fn get_data_with_proof_by_hash( &mut self, hash: &TrieHash, - ) -> Result)>> + ) -> Result)>, VmExecutionError> where T: ClarityDeserializable, { @@ -623,7 +633,7 @@ impl<'a> ClarityDatabase<'a> { &mut self, contract_identifier: &QualifiedContractIdentifier, contract_content: &str, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let hash = Sha512Trunc256Sum::from_data(contract_content.as_bytes()); self.store .prepare_for_contract_metadata(contract_identifier, hash)?; @@ -661,7 +671,7 @@ impl<'a> ClarityDatabase<'a> { pub fn get_contract_hash( &mut self, contract_identifier: &QualifiedContractIdentifier, - ) -> Result> { + ) -> Result, VmExecutionError> { self.store.get_contract_hash(contract_identifier) } @@ -670,36 +680,20 @@ impl<'a> ClarityDatabase<'a> { contract_identifier: &QualifiedContractIdentifier, key: &str, data: &str, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { self.store .insert_metadata(contract_identifier, key, data) .map_err(|e| e.into()) } - /// Set a metadata entry if it hasn't already been set, yielding - /// a runtime error if it was. This should only be called by post-nakamoto - /// contexts. - pub fn try_set_metadata( - &mut self, - contract_identifier: &QualifiedContractIdentifier, - key: &str, - data: &str, - ) -> Result<()> { - if self.store.has_metadata_entry(contract_identifier, key) { - Err(Error::Runtime(RuntimeErrorType::MetadataAlreadySet, None)) - } else { - Ok(self.store.insert_metadata(contract_identifier, key, data)?) - } - } - fn insert_metadata( &mut self, contract_identifier: &QualifiedContractIdentifier, key: &str, data: &T, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { if self.store.has_metadata_entry(contract_identifier, key) { - Err(InterpreterError::Expect(format!( + Err(VmInternalError::Expect(format!( "Metadata entry '{key}' already exists for contract: {contract_identifier}" )) .into()) @@ -714,7 +708,7 @@ impl<'a> ClarityDatabase<'a> { &mut self, contract_identifier: &QualifiedContractIdentifier, key: &str, - ) -> Result> + ) -> Result, VmExecutionError> where T: ClarityDeserializable, { @@ -730,7 +724,7 @@ impl<'a> ClarityDatabase<'a> { at_height: u32, contract_identifier: &QualifiedContractIdentifier, key: &str, - ) -> Result> + ) -> Result, VmExecutionError> where T: ClarityDeserializable, { @@ -750,11 +744,11 @@ impl<'a> ClarityDatabase<'a> { pub fn load_contract_analysis( &mut self, contract_identifier: &QualifiedContractIdentifier, - ) -> Result> { + ) -> Result, VmExecutionError> { self.store .get_metadata(contract_identifier, AnalysisDatabase::storage_key()) // treat NoSuchContract error thrown by get_metadata as an Option::None -- - // the analysis will propagate that as a CheckError anyways. + // the analysis will propagate that as a StaticCheckError anyways. .ok() .flatten() .map(|x| ContractAnalysis::deserialize(&x)) @@ -764,7 +758,7 @@ impl<'a> ClarityDatabase<'a> { pub fn get_contract_size( &mut self, contract_identifier: &QualifiedContractIdentifier, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_metadata_key( StoreType::Contract, ContractDataVarName::ContractSize.as_str(), @@ -772,7 +766,7 @@ impl<'a> ClarityDatabase<'a> { let contract_size: u64 = self.fetch_metadata(contract_identifier, &key)? .ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "Failed to read non-consensus contract metadata, even though contract exists in MARF." .into()) })?; @@ -783,7 +777,7 @@ impl<'a> ClarityDatabase<'a> { let data_size: u64 = self .fetch_metadata(contract_identifier, &key)? .ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "Failed to read non-consensus contract metadata, even though contract exists in MARF." .into()) })?; @@ -797,7 +791,7 @@ impl<'a> ClarityDatabase<'a> { &mut self, contract_identifier: &QualifiedContractIdentifier, data_size: u64, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_metadata_key( StoreType::Contract, ContractDataVarName::ContractSize.as_str(), @@ -805,7 +799,7 @@ impl<'a> ClarityDatabase<'a> { let contract_size: u64 = self.fetch_metadata(contract_identifier, &key)? .ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "Failed to read non-consensus contract metadata, even though contract exists in MARF." .into()) })?; @@ -823,7 +817,7 @@ impl<'a> ClarityDatabase<'a> { &mut self, contract_identifier: &QualifiedContractIdentifier, contract: Contract, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_metadata_key( StoreType::Contract, ContractDataVarName::Contract.as_str(), @@ -843,13 +837,13 @@ impl<'a> ClarityDatabase<'a> { pub fn get_contract( &mut self, contract_identifier: &QualifiedContractIdentifier, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_metadata_key( StoreType::Contract, ContractDataVarName::Contract.as_str(), ); let mut data: Contract = self.fetch_metadata(contract_identifier, &key)? - .ok_or_else(|| InterpreterError::Expect( + .ok_or_else(|| VmInternalError::Expect( "Failed to read non-consensus contract metadata, even though contract exists in MARF." .into()))?; data.canonicalize_types(&self.get_clarity_epoch_version()?); @@ -864,10 +858,10 @@ impl<'a> ClarityDatabase<'a> { /// Since Clarity did not exist in stacks 1.0, the lowest valid epoch ID is stacks 2.0. /// The instantiation of subsequent epochs may bump up the epoch version in the clarity DB if /// Clarity is updated in that epoch. - pub fn get_clarity_epoch_version(&mut self) -> Result { + pub fn get_clarity_epoch_version(&mut self) -> Result { let out = match self.get_data(Self::clarity_state_epoch_key())? { Some(x) => u32::try_into(x).map_err(|_| { - InterpreterError::Expect("Bad Clarity epoch version in stored Clarity state".into()) + VmInternalError::Expect("Bad Clarity epoch version in stored Clarity state".into()) })?, None => StacksEpochId::Epoch20, }; @@ -875,17 +869,23 @@ impl<'a> ClarityDatabase<'a> { } /// Should be called _after_ all of the epoch's initialization has been invoked - pub fn set_clarity_epoch_version(&mut self, epoch: StacksEpochId) -> Result<()> { + pub fn set_clarity_epoch_version( + &mut self, + epoch: StacksEpochId, + ) -> Result<(), VmExecutionError> { self.put_data(Self::clarity_state_epoch_key(), &(epoch as u32)) } /// Setup block metadata at the beginning of a block /// This stores block-specific data that can be accessed during Clarity execution - pub fn setup_block_metadata(&mut self, block_time: Option) -> Result<()> { + pub fn setup_block_metadata( + &mut self, + block_time: Option, + ) -> Result<(), VmExecutionError> { let epoch = self.get_clarity_epoch_version()?; if epoch.uses_marfed_block_time() { let block_time = block_time.ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "FATAL: Marfed block time not provided to Clarity DB setup".into(), ) })?; @@ -894,15 +894,15 @@ impl<'a> ClarityDatabase<'a> { Ok(()) } - pub fn get_current_block_time(&mut self) -> Result { + pub fn get_current_block_time(&mut self) -> Result { match self.get_data(CLARITY_STORAGE_BLOCK_TIME_KEY)? { Some(value) => Ok(value), - None => Err(RuntimeErrorType::BlockTimeNotAvailable.into()), + None => Err(RuntimeError::BlockTimeNotAvailable.into()), } } /// Returns the _current_ total liquid ustx - pub fn get_total_liquid_ustx(&mut self) -> Result { + pub fn get_total_liquid_ustx(&mut self) -> Result { let epoch = self.get_clarity_epoch_version()?; Ok(self .get_value( @@ -911,7 +911,7 @@ impl<'a> ClarityDatabase<'a> { &epoch, ) .map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "FATAL: failed to load ustx_liquid_supply Clarity key".into(), ) })? @@ -920,7 +920,7 @@ impl<'a> ClarityDatabase<'a> { .unwrap_or(0)) } - fn set_ustx_liquid_supply(&mut self, set_to: u128) -> Result<()> { + fn set_ustx_liquid_supply(&mut self, set_to: u128) -> Result<(), VmExecutionError> { self.put_value( ClarityDatabase::ustx_liquid_supply_key(), Value::UInt(set_to), @@ -928,32 +928,32 @@ impl<'a> ClarityDatabase<'a> { &StacksEpochId::Epoch21, ) .map_err(|_| { - InterpreterError::Expect("FATAL: Failed to store STX liquid supply".into()).into() + VmInternalError::Expect("FATAL: Failed to store STX liquid supply".into()).into() }) } - pub fn increment_ustx_liquid_supply(&mut self, incr_by: u128) -> Result<()> { + pub fn increment_ustx_liquid_supply(&mut self, incr_by: u128) -> Result<(), VmExecutionError> { let current = self.get_total_liquid_ustx()?; let next = current.checked_add(incr_by).ok_or_else(|| { error!("Overflowed `ustx-liquid-supply`"); - RuntimeErrorType::ArithmeticOverflow + RuntimeError::ArithmeticOverflow })?; self.set_ustx_liquid_supply(next)?; Ok(()) } - pub fn decrement_ustx_liquid_supply(&mut self, decr_by: u128) -> Result<()> { + pub fn decrement_ustx_liquid_supply(&mut self, decr_by: u128) -> Result<(), VmExecutionError> { let current = self.get_total_liquid_ustx()?; let next = current.checked_sub(decr_by).ok_or_else(|| { error!("`stx-burn?` accepted that reduces `ustx-liquid-supply` below 0"); - RuntimeErrorType::ArithmeticUnderflow + RuntimeError::ArithmeticUnderflow })?; self.set_ustx_liquid_supply(next)?; Ok(()) } /// Returns the tenure height of the current block. - pub fn get_tenure_height(&mut self) -> Result { + pub fn get_tenure_height(&mut self) -> Result { if self.get_clarity_epoch_version()? < StacksEpochId::Epoch30 { // Before epoch 3.0, the tenure height was not stored in the // Clarity state. Instead, it was the same as the block height. @@ -962,11 +962,11 @@ impl<'a> ClarityDatabase<'a> { self.get_data(TENURE_HEIGHT_KEY)? .ok_or_else(|| { - InterpreterError::Expect("No tenure height in stored Clarity state".into()).into() + VmInternalError::Expect("No tenure height in stored Clarity state".into()).into() }) .and_then(|x| { u32::try_into(x).map_err(|_| { - InterpreterError::Expect("Bad tenure height in stored Clarity state".into()) + VmInternalError::Expect("Bad tenure height in stored Clarity state".into()) .into() }) }) @@ -975,9 +975,9 @@ impl<'a> ClarityDatabase<'a> { /// Set the tenure height of the current block. In the first block of a new /// tenure, this height must be incremented before evaluating any /// transactions in the block. - pub fn set_tenure_height(&mut self, height: u32) -> Result<()> { + pub fn set_tenure_height(&mut self, height: u32) -> Result<(), VmExecutionError> { if self.get_clarity_epoch_version()? < StacksEpochId::Epoch30 { - return Err(Error::Interpreter(InterpreterError::Expect( + return Err(VmExecutionError::Internal(VmInternalError::Expect( "Setting tenure height in Clarity state is not supported before epoch 3.0".into(), ))); } @@ -999,13 +999,16 @@ impl ClarityDatabase<'_> { /// Returns the ID of a *Stacks* block, by a *Stacks* block height. /// /// Fails if `block_height` >= the "currently" under construction Stacks block height. - pub fn get_index_block_header_hash(&mut self, block_height: u32) -> Result { + pub fn get_index_block_header_hash( + &mut self, + block_height: u32, + ) -> Result { self.store .get_block_header_hash(block_height) // the caller is responsible for ensuring that the block_height given // is < current_block_height, so this should _always_ return a value. .ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "Block header hash must return for provided block height".into(), ) .into() @@ -1035,7 +1038,7 @@ impl ClarityDatabase<'_> { /// Return the height for PoX v2 -> v3 auto unlocks /// from the burn state db - pub fn get_v2_unlock_height(&mut self) -> Result { + pub fn get_v2_unlock_height(&mut self) -> Result { if self.get_clarity_epoch_version()? >= StacksEpochId::Epoch22 { Ok(self.burn_state_db.get_v2_unlock_height()) } else { @@ -1045,7 +1048,7 @@ impl ClarityDatabase<'_> { /// Return the height for PoX v3 -> v4 auto unlocks /// from the burn state db - pub fn get_v3_unlock_height(&mut self) -> Result { + pub fn get_v3_unlock_height(&mut self) -> Result { if self.get_clarity_epoch_version()? >= StacksEpochId::Epoch25 { Ok(self.burn_state_db.get_v3_unlock_height()) } else { @@ -1064,7 +1067,7 @@ impl ClarityDatabase<'_> { pub fn get_block_height_for_tenure_height( &mut self, tenure_height: u32, - ) -> Result> { + ) -> Result, VmExecutionError> { let current_tenure_height = self.get_tenure_height()?; if current_tenure_height < tenure_height { return Ok(None); @@ -1091,7 +1094,7 @@ impl ClarityDatabase<'_> { /// This is the burnchain block height of the parent of the Stacks block at the current Stacks /// block height (i.e. that returned by `get_index_block_header_hash` for /// `get_current_block_height`). - pub fn get_current_burnchain_block_height(&mut self) -> Result { + pub fn get_current_burnchain_block_height(&mut self) -> Result { let cur_stacks_height = self.store.get_current_block_height(); // Before epoch 3.0, we can only access the burn block associated with the last block @@ -1108,7 +1111,7 @@ impl ClarityDatabase<'_> { self.get_burnchain_block_height(&last_mined_bhh) .ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "Block header hash '{last_mined_bhh}' must return for provided stacks block height {cur_stacks_height}" )) .into() @@ -1118,24 +1121,27 @@ impl ClarityDatabase<'_> { self.burn_state_db .get_tip_burn_block_height() .ok_or_else(|| { - InterpreterError::Expect("Failed to get burnchain tip height.".into()).into() + VmInternalError::Expect("Failed to get burnchain tip height.".into()).into() }) } } - pub fn get_block_header_hash(&mut self, block_height: u32) -> Result { + pub fn get_block_header_hash( + &mut self, + block_height: u32, + ) -> Result { let id_bhh = self.get_index_block_header_hash(block_height)?; let epoch = self.get_stacks_epoch_for_block(&id_bhh)?; self.headers_db .get_stacks_block_header_hash_for_block(&id_bhh, &epoch) - .ok_or_else(|| InterpreterError::Expect("Failed to get block data.".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to get block data.".into()).into()) } pub fn get_burn_block_time( &mut self, block_height: u32, id_bhh_opt: Option, - ) -> Result { + ) -> Result { let id_bhh = match id_bhh_opt { Some(x) => x, None => self.get_index_block_header_hash(block_height)?, @@ -1143,10 +1149,10 @@ impl ClarityDatabase<'_> { let epoch = self.get_stacks_epoch_for_block(&id_bhh)?; self.headers_db .get_burn_block_time_for_block(&id_bhh, Some(&epoch)) - .ok_or_else(|| InterpreterError::Expect("Failed to get block data.".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to get block data.".into()).into()) } - pub fn get_block_time(&mut self, block_height: u32) -> Result { + pub fn get_block_time(&mut self, block_height: u32) -> Result { let id_bhh = self.get_index_block_header_hash(block_height)?; let epoch = self.get_stacks_epoch_for_block(&id_bhh)?; if !epoch.uses_nakamoto_blocks() { @@ -1155,17 +1161,17 @@ impl ClarityDatabase<'_> { self.headers_db .get_stacks_block_time_for_block(&id_bhh) - .ok_or_else(|| InterpreterError::Expect("Failed to get block data.".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to get block data.".into()).into()) } pub fn get_burnchain_block_header_hash( &mut self, block_height: u32, - ) -> Result { + ) -> Result { let id_bhh = self.get_index_block_header_hash(block_height)?; self.headers_db .get_burn_header_hash_for_block(&id_bhh) - .ok_or_else(|| InterpreterError::Expect("Failed to get block data.".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to get block data.".into()).into()) } /// In Epoch 2.x: @@ -1176,7 +1182,7 @@ impl ClarityDatabase<'_> { /// 4. Resolve the consensus hash to the associated SortitionId /// In Epoch 3+: /// 1. Get the SortitionId of the current Stacks tip - fn get_sortition_id_for_stacks_tip(&mut self) -> Result> { + fn get_sortition_id_for_stacks_tip(&mut self) -> Result, VmExecutionError> { if !self .get_clarity_epoch_version()? .clarity_uses_tip_burn_block() @@ -1198,7 +1204,7 @@ impl ClarityDatabase<'_> { .headers_db .get_consensus_hash_for_block(&parent_id_bhh, &epoch) .ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "FATAL: no consensus hash found for StacksBlockId {parent_id_bhh}" )) })?; @@ -1208,7 +1214,7 @@ impl ClarityDatabase<'_> { .burn_state_db .get_sortition_id_from_consensus_hash(&consensus_hash) .ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "FATAL: no SortitionID found for consensus hash {consensus_hash}" )) })?; @@ -1229,7 +1235,7 @@ impl ClarityDatabase<'_> { pub fn get_burnchain_block_header_hash_for_burnchain_height( &mut self, burnchain_block_height: u32, - ) -> Result> { + ) -> Result, VmExecutionError> { let sortition_id = match self.get_sortition_id_for_stacks_tip()? { Some(x) => x, None => return Ok(None), @@ -1244,7 +1250,7 @@ impl ClarityDatabase<'_> { pub fn get_pox_payout_addrs_for_burnchain_height( &mut self, burnchain_block_height: u32, - ) -> Result, u128)>> { + ) -> Result, u128)>, VmExecutionError> { let sortition_id = match self.get_sortition_id_for_stacks_tip()? { Some(x) => x, None => return Ok(None), @@ -1258,25 +1264,28 @@ impl ClarityDatabase<'_> { self.headers_db.get_burn_block_height_for_block(id_bhh) } - pub fn get_block_vrf_seed(&mut self, block_height: u32) -> Result { + pub fn get_block_vrf_seed(&mut self, block_height: u32) -> Result { let id_bhh = self.get_index_block_header_hash(block_height)?; let epoch = self.get_stacks_epoch_for_block(&id_bhh)?; self.headers_db .get_vrf_seed_for_block(&id_bhh, &epoch) - .ok_or_else(|| InterpreterError::Expect("Failed to get block data.".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to get block data.".into()).into()) } - pub fn get_miner_address(&mut self, block_height: u32) -> Result { + pub fn get_miner_address( + &mut self, + block_height: u32, + ) -> Result { let id_bhh = self.get_index_block_header_hash(block_height)?; let epoch = self.get_stacks_epoch_for_block(&id_bhh)?; Ok(self .headers_db .get_miner_address(&id_bhh, &epoch) - .ok_or_else(|| InterpreterError::Expect("Failed to get block data.".into()))? + .ok_or_else(|| VmInternalError::Expect("Failed to get block data.".into()))? .into()) } - pub fn get_miner_spend_winner(&mut self, block_height: u32) -> Result { + pub fn get_miner_spend_winner(&mut self, block_height: u32) -> Result { if block_height == 0 { return Ok(0); } @@ -1287,13 +1296,13 @@ impl ClarityDatabase<'_> { .headers_db .get_burnchain_tokens_spent_for_winning_block(&id_bhh, &epoch) .ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "FATAL: no winning burnchain token spend record for block".into(), ) })?) } - pub fn get_miner_spend_total(&mut self, block_height: u32) -> Result { + pub fn get_miner_spend_total(&mut self, block_height: u32) -> Result { if block_height == 0 { return Ok(0); } @@ -1304,13 +1313,16 @@ impl ClarityDatabase<'_> { .headers_db .get_burnchain_tokens_spent_for_block(&id_bhh, &epoch) .ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "FATAL: no total burnchain token spend record for block".into(), ) })?) } - pub fn get_block_reward(&mut self, block_height: u32) -> Result> { + pub fn get_block_reward( + &mut self, + block_height: u32, + ) -> Result, VmExecutionError> { if block_height == 0 { return Ok(None); } @@ -1329,19 +1341,19 @@ impl ClarityDatabase<'_> { .headers_db .get_tokens_earned_for_block(&id_bhh, &epoch) .ok_or_else(|| { - InterpreterError::Expect("FATAL: matured block has no recorded reward".into()) + VmInternalError::Expect("FATAL: matured block has no recorded reward".into()) })?; Ok(Some(reward)) } - pub fn get_stx_btc_ops_processed(&mut self) -> Result { + pub fn get_stx_btc_ops_processed(&mut self) -> Result { Ok(self .get_data("vm_pox::stx_btc_ops::processed_blocks")? .unwrap_or(0)) } - pub fn set_stx_btc_ops_processed(&mut self, processed: u64) -> Result<()> { + pub fn set_stx_btc_ops_processed(&mut self, processed: u64) -> Result<(), VmExecutionError> { self.put_data("vm_pox::stx_btc_ops::processed_blocks", &processed) } } @@ -1361,7 +1373,7 @@ impl ClarityDatabase<'_> { &mut self, pubkey_hash: &Hash160, height: u32, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_microblock_pubkey_height_key(pubkey_hash); let value = format!("{height}"); self.put_data(&key, &value) @@ -1377,28 +1389,28 @@ impl ClarityDatabase<'_> { height: u32, reporter: &StandardPrincipalData, seq: u16, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_microblock_poison_key(height); let value = Value::Tuple( TupleData::from_data(vec![ ( ClarityName::try_from("reporter").map_err(|_| { - InterpreterError::Expect("BUG: valid string representation".into()) + VmInternalError::Expect("BUG: valid string representation".into()) })?, Value::Principal(PrincipalData::Standard(reporter.clone())), ), ( ClarityName::try_from("sequence").map_err(|_| { - InterpreterError::Expect("BUG: valid string representation".into()) + VmInternalError::Expect("BUG: valid string representation".into()) })?, Value::UInt(seq as u128), ), ]) - .map_err(|_| InterpreterError::Expect("BUG: valid tuple representation".into()))?, + .map_err(|_| VmInternalError::Expect("BUG: valid tuple representation".into()))?, ); let mut value_bytes = vec![]; value.serialize_write(&mut value_bytes).map_err(|_| { - InterpreterError::Expect("BUG: valid tuple representation did not serialize".into()) + VmInternalError::Expect("BUG: valid tuple representation did not serialize".into()) })?; let value_str = to_hex(&value_bytes); @@ -1408,12 +1420,12 @@ impl ClarityDatabase<'_> { pub fn get_microblock_pubkey_hash_height( &mut self, pubkey_hash: &Hash160, - ) -> Result> { + ) -> Result, VmExecutionError> { let key = ClarityDatabase::make_microblock_pubkey_height_key(pubkey_hash); self.get_data(&key)? .map(|height_str: String| { height_str.parse::().map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "BUG: inserted non-u32 as height of microblock pubkey hash".into(), ) .into() @@ -1426,13 +1438,13 @@ impl ClarityDatabase<'_> { pub fn get_microblock_poison_report( &mut self, height: u32, - ) -> Result> { + ) -> Result, VmExecutionError> { let key = ClarityDatabase::make_microblock_poison_key(height); self.get_data(&key)? .map(|reporter_hex_str: String| { let reporter_value = Value::try_deserialize_hex_untyped(&reporter_hex_str) .map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "BUG: failed to decode serialized poison-microblock reporter".into(), ) })?; @@ -1440,7 +1452,7 @@ impl ClarityDatabase<'_> { let reporter_value = tuple_data .get("reporter") .map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "BUG: poison-microblock report has no 'reporter'".into(), ) })? @@ -1448,7 +1460,7 @@ impl ClarityDatabase<'_> { let seq_value = tuple_data .get("sequence") .map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "BUG: poison-microblock report has no 'sequence'".into(), ) })? @@ -1459,11 +1471,11 @@ impl ClarityDatabase<'_> { let seq: u16 = seq_u128 .try_into() - .map_err(|_| InterpreterError::Expect("BUG: seq exceeds u16 max".into()))?; + .map_err(|_| VmInternalError::Expect("BUG: seq exceeds u16 max".into()))?; if let PrincipalData::Standard(principal_data) = reporter_principal { Ok((principal_data, seq)) } else { - Err(InterpreterError::Expect( + Err(VmInternalError::Expect( "BUG: poison-microblock report principal is not a standard principal" .into(), ) @@ -1476,9 +1488,11 @@ impl ClarityDatabase<'_> { // this is used so that things like load_map, load_var, load_nft, etc. // will throw NoSuchFoo errors instead of NoSuchContract errors. -fn map_no_contract_as_none(res: Result>) -> Result> { +fn map_no_contract_as_none( + res: Result, VmExecutionError>, +) -> Result, VmExecutionError> { res.or_else(|e| match e { - Error::Unchecked(CheckErrors::NoSuchContract(_)) => Ok(None), + VmExecutionError::Unchecked(CheckErrorKind::NoSuchContract(_)) => Ok(None), x => Err(x), }) } @@ -1490,7 +1504,7 @@ impl ClarityDatabase<'_> { contract_identifier: &QualifiedContractIdentifier, variable_name: &str, value_type: TypeSignature, - ) -> Result { + ) -> Result { let variable_data = DataVariableMetadata { value_type }; let key = ClarityDatabase::make_metadata_key(StoreType::VariableMeta, variable_name); @@ -1502,11 +1516,11 @@ impl ClarityDatabase<'_> { &mut self, contract_identifier: &QualifiedContractIdentifier, variable_name: &str, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_metadata_key(StoreType::VariableMeta, variable_name); map_no_contract_as_none(self.fetch_metadata(contract_identifier, &key))? - .ok_or(CheckErrors::NoSuchDataVariable(variable_name.to_string()).into()) + .ok_or(CheckErrorKind::NoSuchDataVariable(variable_name.to_string()).into()) } #[cfg(any(test, feature = "testing"))] @@ -1515,7 +1529,7 @@ impl ClarityDatabase<'_> { contract_identifier: &QualifiedContractIdentifier, variable_name: &str, value: Value, - ) -> Result { + ) -> Result { let epoch = self.get_clarity_epoch_version()?; let descriptor = self.load_variable(contract_identifier, variable_name)?; self.set_variable( @@ -1535,12 +1549,12 @@ impl ClarityDatabase<'_> { value: Value, variable_descriptor: &DataVariableMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { if !variable_descriptor .value_type .admits(&self.get_clarity_epoch_version()?, &value)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(variable_descriptor.value_type.clone()), Box::new(value), ) @@ -1566,7 +1580,7 @@ impl ClarityDatabase<'_> { contract_identifier: &QualifiedContractIdentifier, variable_name: &str, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { let descriptor = self.load_variable(contract_identifier, variable_name)?; self.lookup_variable(contract_identifier, variable_name, &descriptor, epoch) } @@ -1577,7 +1591,7 @@ impl ClarityDatabase<'_> { variable_name: &str, variable_descriptor: &DataVariableMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_key_for_trip( contract_identifier, StoreType::Variable, @@ -1600,7 +1614,7 @@ impl ClarityDatabase<'_> { variable_name: &str, variable_descriptor: &DataVariableMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_key_for_trip( contract_identifier, StoreType::Variable, @@ -1627,7 +1641,7 @@ impl ClarityDatabase<'_> { map_name: &str, key_type: TypeSignature, value_type: TypeSignature, - ) -> Result { + ) -> Result { let data = DataMapMetadata { key_type, value_type, @@ -1643,18 +1657,18 @@ impl ClarityDatabase<'_> { &mut self, contract_identifier: &QualifiedContractIdentifier, map_name: &str, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_metadata_key(StoreType::DataMapMeta, map_name); map_no_contract_as_none(self.fetch_metadata(contract_identifier, &key))? - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()).into()) + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()).into()) } pub fn make_key_for_data_map_entry( contract_identifier: &QualifiedContractIdentifier, map_name: &str, key_value: &Value, - ) -> Result { + ) -> Result { Ok(ClarityDatabase::make_key_for_data_map_entry_serialized( contract_identifier, map_name, @@ -1681,7 +1695,7 @@ impl ClarityDatabase<'_> { map_name: &str, key_value: &Value, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { let descriptor = self.load_map(contract_identifier, map_name)?; self.fetch_entry(contract_identifier, map_name, key_value, &descriptor, epoch) } @@ -1694,12 +1708,12 @@ impl ClarityDatabase<'_> { key_value: &Value, map_descriptor: &DataMapMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { if !map_descriptor .key_type .admits(&self.get_clarity_epoch_version()?, key_value)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(map_descriptor.key_type.clone()), Box::new(key_value.clone()), ) @@ -1725,12 +1739,12 @@ impl ClarityDatabase<'_> { key_value: &Value, map_descriptor: &DataMapMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { if !map_descriptor .key_type .admits(&self.get_clarity_epoch_version()?, key_value)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(map_descriptor.key_type.clone()), Box::new(key_value.clone()), ) @@ -1760,7 +1774,7 @@ impl ClarityDatabase<'_> { serialized_byte_len: serialized_byte_len .checked_add(byte_len_of_serialization(&key_serialized)) .ok_or_else(|| { - InterpreterError::Expect("Overflowed Clarity key/value size".into()) + VmInternalError::Expect("Overflowed Clarity key/value size".into()) })?, }), } @@ -1774,7 +1788,7 @@ impl ClarityDatabase<'_> { value: Value, map_descriptor: &DataMapMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { self.inner_set_entry( contract_identifier, map_name, @@ -1793,7 +1807,7 @@ impl ClarityDatabase<'_> { key: Value, value: Value, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { let descriptor = self.load_map(contract_identifier, map_name)?; self.set_entry( contract_identifier, @@ -1813,7 +1827,7 @@ impl ClarityDatabase<'_> { key: Value, value: Value, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { let descriptor = self.load_map(contract_identifier, map_name)?; self.insert_entry( contract_identifier, @@ -1834,7 +1848,7 @@ impl ClarityDatabase<'_> { value: Value, map_descriptor: &DataMapMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { self.inner_set_entry( contract_identifier, map_name, @@ -1851,7 +1865,7 @@ impl ClarityDatabase<'_> { key: &str, expected_value: &TypeSignature, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { match self.get_value(key, expected_value, epoch)? { None => Ok(false), Some(value) => Ok(value.value != Value::none()), @@ -1868,12 +1882,12 @@ impl ClarityDatabase<'_> { return_if_exists: bool, map_descriptor: &DataMapMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { if !map_descriptor .key_type .admits(&self.get_clarity_epoch_version()?, &key_value)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(map_descriptor.key_type.clone()), Box::new(key_value), ) @@ -1883,7 +1897,7 @@ impl ClarityDatabase<'_> { .value_type .admits(&self.get_clarity_epoch_version()?, &value)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(map_descriptor.value_type.clone()), Box::new(value), ) @@ -1915,7 +1929,7 @@ impl ClarityDatabase<'_> { serialized_byte_len: key_serialized_byte_len .checked_add(placed_size) .ok_or_else(|| { - InterpreterError::Expect("Overflowed Clarity key/value size".into()) + VmInternalError::Expect("Overflowed Clarity key/value size".into()) })?, }) } @@ -1927,12 +1941,12 @@ impl ClarityDatabase<'_> { key_value: &Value, map_descriptor: &DataMapMetadata, epoch: &StacksEpochId, - ) -> Result { + ) -> Result { if !map_descriptor .key_type .admits(&self.get_clarity_epoch_version()?, key_value)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(map_descriptor.key_type.clone()), Box::new(key_value.clone()), ) @@ -1962,7 +1976,7 @@ impl ClarityDatabase<'_> { serialized_byte_len: key_serialized_byte_len .checked_add(*NONE_SERIALIZATION_LEN) .ok_or_else(|| { - InterpreterError::Expect("Overflowed Clarity key/value size".into()) + VmInternalError::Expect("Overflowed Clarity key/value size".into()) })?, }) } @@ -1976,7 +1990,7 @@ impl ClarityDatabase<'_> { contract_identifier: &QualifiedContractIdentifier, token_name: &str, total_supply: &Option, - ) -> Result { + ) -> Result { let data = FungibleTokenMetadata { total_supply: *total_supply, }; @@ -1999,11 +2013,11 @@ impl ClarityDatabase<'_> { &mut self, contract_identifier: &QualifiedContractIdentifier, token_name: &str, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_metadata_key(StoreType::FungibleTokenMeta, token_name); map_no_contract_as_none(self.fetch_metadata(contract_identifier, &key))? - .ok_or(CheckErrors::NoSuchFT(token_name.to_string()).into()) + .ok_or(CheckErrorKind::NoSuchFT(token_name.to_string()).into()) } pub fn create_non_fungible_token( @@ -2011,7 +2025,7 @@ impl ClarityDatabase<'_> { contract_identifier: &QualifiedContractIdentifier, token_name: &str, key_type: &TypeSignature, - ) -> Result { + ) -> Result { let data = NonFungibleTokenMetadata { key_type: key_type.clone(), }; @@ -2025,11 +2039,11 @@ impl ClarityDatabase<'_> { &mut self, contract_identifier: &QualifiedContractIdentifier, token_name: &str, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_metadata_key(StoreType::NonFungibleTokenMeta, token_name); map_no_contract_as_none(self.fetch_metadata(contract_identifier, &key))? - .ok_or(CheckErrors::NoSuchNFT(token_name.to_string()).into()) + .ok_or(CheckErrorKind::NoSuchNFT(token_name.to_string()).into()) } pub fn checked_increase_token_supply( @@ -2038,23 +2052,23 @@ impl ClarityDatabase<'_> { token_name: &str, amount: u128, descriptor: &FungibleTokenMetadata, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_key_for_trip( contract_identifier, StoreType::CirculatingSupply, token_name, ); let current_supply: u128 = self.get_data(&key)?.ok_or_else(|| { - InterpreterError::Expect("ERROR: Clarity VM failed to track token supply.".into()) + VmInternalError::Expect("ERROR: Clarity VM failed to track token supply.".into()) })?; let new_supply = current_supply .checked_add(amount) - .ok_or(RuntimeErrorType::ArithmeticOverflow)?; + .ok_or(RuntimeError::ArithmeticOverflow)?; if let Some(total_supply) = descriptor.total_supply { if new_supply > total_supply { - return Err(RuntimeErrorType::SupplyOverflow(new_supply, total_supply).into()); + return Err(RuntimeError::SupplyOverflow(new_supply, total_supply).into()); } } @@ -2066,18 +2080,18 @@ impl ClarityDatabase<'_> { contract_identifier: &QualifiedContractIdentifier, token_name: &str, amount: u128, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_key_for_trip( contract_identifier, StoreType::CirculatingSupply, token_name, ); let current_supply: u128 = self.get_data(&key)?.ok_or_else(|| { - InterpreterError::Expect("ERROR: Clarity VM failed to track token supply.".into()) + VmInternalError::Expect("ERROR: Clarity VM failed to track token supply.".into()) })?; if amount > current_supply { - return Err(RuntimeErrorType::SupplyUnderflow(current_supply, amount).into()); + return Err(RuntimeError::SupplyUnderflow(current_supply, amount).into()); } let new_supply = current_supply - amount; @@ -2091,7 +2105,7 @@ impl ClarityDatabase<'_> { token_name: &str, principal: &PrincipalData, descriptor: Option<&FungibleTokenMetadata>, - ) -> Result { + ) -> Result { if descriptor.is_none() { self.load_ft(contract_identifier, token_name)?; } @@ -2116,7 +2130,7 @@ impl ClarityDatabase<'_> { token_name: &str, principal: &PrincipalData, balance: u128, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_key_for_quad( contract_identifier, StoreType::FungibleToken, @@ -2130,14 +2144,14 @@ impl ClarityDatabase<'_> { &mut self, contract_identifier: &QualifiedContractIdentifier, token_name: &str, - ) -> Result { + ) -> Result { let key = ClarityDatabase::make_key_for_trip( contract_identifier, StoreType::CirculatingSupply, token_name, ); let supply = self.get_data(&key)?.ok_or_else(|| { - InterpreterError::Expect("ERROR: Clarity VM failed to track token supply.".into()) + VmInternalError::Expect("ERROR: Clarity VM failed to track token supply.".into()) })?; Ok(supply) } @@ -2148,9 +2162,9 @@ impl ClarityDatabase<'_> { asset_name: &str, asset: &Value, key_type: &TypeSignature, - ) -> Result { + ) -> Result { if !key_type.admits(&self.get_clarity_epoch_version()?, asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(key_type.clone()), Box::new(asset.clone()), ) @@ -2168,17 +2182,17 @@ impl ClarityDatabase<'_> { let value: Option = self.get_value( &key, &TypeSignature::new_option(TypeSignature::PrincipalType) - .map_err(|_| InterpreterError::Expect("Unexpected type failure".into()))?, + .map_err(|_| VmInternalError::Expect("Unexpected type failure".into()))?, &epoch, )?; let owner = match value { Some(owner) => owner.value.expect_optional()?, - None => return Err(RuntimeErrorType::NoSuchToken.into()), + None => return Err(RuntimeError::NoSuchToken.into()), }; let principal = match owner { Some(value) => value.expect_principal()?, - None => return Err(RuntimeErrorType::NoSuchToken.into()), + None => return Err(RuntimeError::NoSuchToken.into()), }; Ok(principal) @@ -2188,7 +2202,7 @@ impl ClarityDatabase<'_> { &mut self, contract_identifier: &QualifiedContractIdentifier, asset_name: &str, - ) -> Result { + ) -> Result { let descriptor = self.load_nft(contract_identifier, asset_name)?; Ok(descriptor.key_type) } @@ -2201,9 +2215,9 @@ impl ClarityDatabase<'_> { principal: &PrincipalData, key_type: &TypeSignature, epoch: &StacksEpochId, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { if !key_type.admits(&self.get_clarity_epoch_version()?, asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(key_type.clone()), Box::new(asset.clone()), ) @@ -2230,9 +2244,9 @@ impl ClarityDatabase<'_> { asset: &Value, key_type: &TypeSignature, epoch: &StacksEpochId, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { if !key_type.admits(&self.get_clarity_epoch_version()?, asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(key_type.clone()), Box::new(asset.clone()), ) @@ -2276,7 +2290,7 @@ impl<'a> ClarityDatabase<'a> { pub fn get_stx_balance_snapshot<'conn>( &'conn mut self, principal: &PrincipalData, - ) -> Result> { + ) -> Result, VmExecutionError> { let stx_balance = self.get_account_stx_balance(principal)?; let cur_burn_height = u64::from(self.get_current_burnchain_block_height()?); @@ -2310,7 +2324,7 @@ impl<'a> ClarityDatabase<'a> { pub fn get_stx_balance_snapshot_genesis<'conn>( &'conn mut self, principal: &PrincipalData, - ) -> Result> { + ) -> Result, VmExecutionError> { let stx_balance = self.get_account_stx_balance(principal)?; let cur_burn_height = 0; @@ -2341,20 +2355,30 @@ impl<'a> ClarityDatabase<'a> { )) } - pub fn get_account_stx_balance(&mut self, principal: &PrincipalData) -> Result { + pub fn get_account_stx_balance( + &mut self, + principal: &PrincipalData, + ) -> Result { let key = ClarityDatabase::make_key_for_account_balance(principal); debug!("Fetching account balance"; "principal" => %principal.to_string()); let result = self.get_data(&key)?; Ok(result.unwrap_or_default()) } - pub fn get_account_nonce(&mut self, principal: &PrincipalData) -> Result { + pub fn get_account_nonce( + &mut self, + principal: &PrincipalData, + ) -> Result { let key = ClarityDatabase::make_key_for_account_nonce(principal); let result = self.get_data(&key)?; Ok(result.unwrap_or_default()) } - pub fn set_account_nonce(&mut self, principal: &PrincipalData, nonce: u64) -> Result<()> { + pub fn set_account_nonce( + &mut self, + principal: &PrincipalData, + nonce: u64, + ) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_key_for_account_nonce(principal); self.put_data(&key, &nonce) } @@ -2372,15 +2396,18 @@ impl ClarityDatabase<'_> { self.burn_state_db.get_stacks_epoch(height) } - pub fn get_stacks_epoch_for_block(&self, id_bhh: &StacksBlockId) -> Result { + pub fn get_stacks_epoch_for_block( + &self, + id_bhh: &StacksBlockId, + ) -> Result { let burn_block = self.get_burnchain_block_height(id_bhh).ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "FATAL: no burnchain block height found for Stacks block {id_bhh}" )) })?; let epoch = self .get_stacks_epoch(burn_block) - .ok_or_else(|| InterpreterError::Expect("Failed to get block data.".into()))?; + .ok_or_else(|| VmInternalError::Expect("Failed to get block data.".into()))?; Ok(epoch.epoch_id) } } diff --git a/clarity/src/vm/database/clarity_store.rs b/clarity/src/vm/database/clarity_store.rs index e1d6dacaeee..b354b568410 100644 --- a/clarity/src/vm/database/clarity_store.rs +++ b/clarity/src/vm/database/clarity_store.rs @@ -24,7 +24,7 @@ use crate::vm::contexts::GlobalContext; use crate::vm::database::{ ClarityDatabase, ClarityDeserializable, ClaritySerializable, NULL_BURN_STATE_DB, NULL_HEADER_DB, }; -use crate::vm::errors::{InterpreterError, InterpreterResult as Result}; +use crate::vm::errors::{VmExecutionError, VmInternalError}; use crate::vm::types::{PrincipalData, QualifiedContractIdentifier}; use crate::vm::Value; @@ -45,33 +45,36 @@ pub type SpecialCaseHandler = &'static dyn Fn( &[Value], // the result of the function call &Value, -) -> Result<()>; +) -> Result<(), VmExecutionError>; // These functions generally _do not_ return errors, rather, any errors in the underlying storage // will _panic_. The rationale for this is that under no condition should the interpreter // attempt to continue processing in the event of an unexpected storage error. pub trait ClarityBackingStore { /// put K-V data into the committed datastore - fn put_all_data(&mut self, items: Vec<(String, String)>) -> Result<()>; + fn put_all_data(&mut self, items: Vec<(String, String)>) -> Result<(), VmExecutionError>; /// fetch K-V out of the committed datastore - fn get_data(&mut self, key: &str) -> Result>; + fn get_data(&mut self, key: &str) -> Result, VmExecutionError>; /// fetch Hash(K)-V out of the commmitted datastore - fn get_data_from_path(&mut self, hash: &TrieHash) -> Result>; + fn get_data_from_path(&mut self, hash: &TrieHash) -> Result, VmExecutionError>; /// fetch K-V out of the committed datastore, along with the byte representation /// of the Merkle proof for that key-value pair - fn get_data_with_proof(&mut self, key: &str) -> Result)>>; + fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError>; fn get_data_with_proof_from_path( &mut self, hash: &TrieHash, - ) -> Result)>>; - fn has_entry(&mut self, key: &str) -> Result { + ) -> Result)>, VmExecutionError>; + fn has_entry(&mut self, key: &str) -> Result { Ok(self.get_data(key)?.is_some()) } /// change the current MARF context to service reads from a different chain_tip /// used to implement time-shifted evaluation. /// returns the previous block header hash on success - fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result; + fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result; /// Is None if `block_height` >= the "currently" under construction Stacks block height. fn get_block_at_height(&mut self, height: u32) -> Option; @@ -108,32 +111,32 @@ pub trait ClarityBackingStore { fn get_contract_hash( &mut self, contract: &QualifiedContractIdentifier, - ) -> Result<(StacksBlockId, Sha512Trunc256Sum)>; + ) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError>; fn insert_metadata( &mut self, contract: &QualifiedContractIdentifier, key: &str, value: &str, - ) -> Result<()>; + ) -> Result<(), VmExecutionError>; fn get_metadata( &mut self, contract: &QualifiedContractIdentifier, key: &str, - ) -> Result>; + ) -> Result, VmExecutionError>; fn get_metadata_manual( &mut self, at_height: u32, contract: &QualifiedContractIdentifier, key: &str, - ) -> Result>; + ) -> Result, VmExecutionError>; fn put_all_metadata( &mut self, items: Vec<((QualifiedContractIdentifier, String), String)>, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { for ((contract, key), value) in items.into_iter() { self.insert_metadata(&contract, &key, &value)?; } @@ -158,19 +161,19 @@ impl ClaritySerializable for ContractCommitment { } impl ClarityDeserializable for ContractCommitment { - fn deserialize(input: &str) -> Result { + fn deserialize(input: &str) -> Result { if input.len() != 72 { - return Err(InterpreterError::Expect("Unexpected input length".into()).into()); + return Err(VmInternalError::Expect("Unexpected input length".into()).into()); } let hash = Sha512Trunc256Sum::from_hex(&input[0..64]) - .map_err(|_| InterpreterError::Expect("Hex decode fail.".into()))?; + .map_err(|_| VmInternalError::Expect("Hex decode fail.".into()))?; let height_bytes = hex_bytes(&input[64..72]) - .map_err(|_| InterpreterError::Expect("Hex decode fail.".into()))?; + .map_err(|_| VmInternalError::Expect("Hex decode fail.".into()))?; let block_height = u32::from_be_bytes( height_bytes .as_slice() .try_into() - .map_err(|_| InterpreterError::Expect("Block height decode fail.".into()))?, + .map_err(|_| VmInternalError::Expect("Block height decode fail.".into()))?, ); Ok(ContractCommitment { hash, block_height }) } @@ -198,26 +201,29 @@ impl NullBackingStore { #[allow(clippy::panic)] impl ClarityBackingStore for NullBackingStore { - fn set_block_hash(&mut self, _bhh: StacksBlockId) -> Result { + fn set_block_hash(&mut self, _bhh: StacksBlockId) -> Result { panic!("NullBackingStore can't set block hash") } - fn get_data(&mut self, _key: &str) -> Result> { + fn get_data(&mut self, _key: &str) -> Result, VmExecutionError> { panic!("NullBackingStore can't retrieve data") } - fn get_data_from_path(&mut self, _hash: &TrieHash) -> Result> { + fn get_data_from_path(&mut self, _hash: &TrieHash) -> Result, VmExecutionError> { panic!("NullBackingStore can't retrieve data") } - fn get_data_with_proof(&mut self, _key: &str) -> Result)>> { + fn get_data_with_proof( + &mut self, + _key: &str, + ) -> Result)>, VmExecutionError> { panic!("NullBackingStore can't retrieve data") } fn get_data_with_proof_from_path( &mut self, _hash: &TrieHash, - ) -> Result)>> { + ) -> Result)>, VmExecutionError> { panic!("NullBackingStore can't retrieve data") } @@ -242,14 +248,14 @@ impl ClarityBackingStore for NullBackingStore { panic!("NullBackingStore can't get current block height") } - fn put_all_data(&mut self, mut _items: Vec<(String, String)>) -> Result<()> { + fn put_all_data(&mut self, mut _items: Vec<(String, String)>) -> Result<(), VmExecutionError> { panic!("NullBackingStore cannot put") } fn get_contract_hash( &mut self, _contract: &QualifiedContractIdentifier, - ) -> Result<(StacksBlockId, Sha512Trunc256Sum)> { + ) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError> { panic!("NullBackingStore cannot get_contract_hash") } @@ -258,7 +264,7 @@ impl ClarityBackingStore for NullBackingStore { _contract: &QualifiedContractIdentifier, _key: &str, _value: &str, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { panic!("NullBackingStore cannot insert_metadata") } @@ -266,7 +272,7 @@ impl ClarityBackingStore for NullBackingStore { &mut self, _contract: &QualifiedContractIdentifier, _key: &str, - ) -> Result> { + ) -> Result, VmExecutionError> { panic!("NullBackingStore cannot get_metadata") } @@ -275,7 +281,7 @@ impl ClarityBackingStore for NullBackingStore { _at_height: u32, _contract: &QualifiedContractIdentifier, _key: &str, - ) -> Result> { + ) -> Result, VmExecutionError> { panic!("NullBackingStore cannot get_metadata_manual") } } diff --git a/clarity/src/vm/database/key_value_wrapper.rs b/clarity/src/vm/database/key_value_wrapper.rs index 5578ac549d7..56b082c96fd 100644 --- a/clarity/src/vm/database/key_value_wrapper.rs +++ b/clarity/src/vm/database/key_value_wrapper.rs @@ -24,7 +24,7 @@ use stacks_common::util::hash::Sha512Trunc256Sum; use super::clarity_store::SpecialCaseHandler; use super::{ClarityBackingStore, ClarityDeserializable}; use crate::vm::database::clarity_store::{make_contract_hash_key, ContractCommitment}; -use crate::vm::errors::{InterpreterError, InterpreterResult}; +use crate::vm::errors::{VmExecutionError, VmInternalError}; use crate::vm::types::serialization::SerializationError; use crate::vm::types::{QualifiedContractIdentifier, TypeSignature}; use crate::vm::Value; @@ -49,7 +49,7 @@ fn rollback_edits_push(edits: &mut Vec<(T, RollbackValueCheck)>, key: T, _val fn rollback_check_pre_bottom_commit( edits: Vec<(T, RollbackValueCheck)>, lookup_map: &mut HashMap>, -) -> Result, InterpreterError> +) -> Result, VmInternalError> where T: Eq + Hash + Clone, { @@ -86,7 +86,7 @@ where fn rollback_check_pre_bottom_commit( edits: Vec<(T, RollbackValueCheck)>, lookup_map: &mut HashMap>, -) -> Result, InterpreterError> +) -> Result, VmInternalError> where T: Eq + Hash + Clone, { @@ -179,19 +179,19 @@ fn rollback_lookup_map( key: &T, value: &RollbackValueCheck, lookup_map: &mut HashMap>, -) -> Result +) -> Result where T: Eq + Hash + Clone, { let popped_value; let remove_edit_deque = { let key_edit_history = lookup_map.get_mut(key).ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "ERROR: Clarity VM had edit log entry, but not lookup_map entry".into(), ) })?; popped_value = key_edit_history.pop().ok_or_else(|| { - InterpreterError::Expect("ERROR: expected value in edit history".into()) + VmInternalError::Expect("ERROR: expected value in edit history".into()) })?; rollback_value_check(&popped_value, value); key_edit_history.is_empty() @@ -240,9 +240,9 @@ impl<'a> RollbackWrapper<'a> { // Rollback the child's edits. // this clears all edits from the child's edit queue, // and removes any of those edits from the lookup map. - pub fn rollback(&mut self) -> Result<(), InterpreterError> { + pub fn rollback(&mut self) -> Result<(), VmInternalError> { let mut last_item = self.stack.pop().ok_or_else(|| { - InterpreterError::Expect("ERROR: Clarity VM attempted to commit past the stack.".into()) + VmInternalError::Expect("ERROR: Clarity VM attempted to commit past the stack.".into()) })?; last_item.edits.reverse(); @@ -263,9 +263,9 @@ impl<'a> RollbackWrapper<'a> { self.stack.len() } - pub fn commit(&mut self) -> Result<(), InterpreterError> { + pub fn commit(&mut self) -> Result<(), VmInternalError> { let mut last_item = self.stack.pop().ok_or_else(|| { - InterpreterError::Expect("ERROR: Clarity VM attempted to commit past the stack.".into()) + VmInternalError::Expect("ERROR: Clarity VM attempted to commit past the stack.".into()) })?; if let Some(next_up) = self.stack.last_mut() { @@ -283,7 +283,7 @@ impl<'a> RollbackWrapper<'a> { rollback_check_pre_bottom_commit(last_item.edits, &mut self.lookup_map)?; if !all_edits.is_empty() { self.store.put_all_data(all_edits).map_err(|e| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: Failed to commit data to sql store: {e:?}" )) })?; @@ -295,7 +295,7 @@ impl<'a> RollbackWrapper<'a> { )?; if !metadata_edits.is_empty() { self.store.put_all_metadata(metadata_edits).map_err(|e| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: Failed to commit data to sql store: {e:?}" )) })?; @@ -320,11 +320,9 @@ fn inner_put_data( } impl RollbackWrapper<'_> { - pub fn put_data(&mut self, key: &str, value: &str) -> InterpreterResult<()> { + pub fn put_data(&mut self, key: &str, value: &str) -> Result<(), VmExecutionError> { let current = self.stack.last_mut().ok_or_else(|| { - InterpreterError::Expect( - "ERROR: Clarity VM attempted PUT on non-nested context.".into(), - ) + VmInternalError::Expect("ERROR: Clarity VM attempted PUT on non-nested context.".into()) })?; inner_put_data( @@ -345,7 +343,7 @@ impl RollbackWrapper<'_> { &mut self, bhh: StacksBlockId, query_pending_data: bool, - ) -> InterpreterResult { + ) -> Result { self.store.set_block_hash(bhh).inspect(|_| { // use and_then so that query_pending_data is only set once set_block_hash succeeds // this doesn't matter in practice, because a set_block_hash failure always aborts @@ -357,7 +355,10 @@ impl RollbackWrapper<'_> { /// this function will only return commitment proofs for values _already_ materialized /// in the underlying store. otherwise it returns None. - pub fn get_data_with_proof(&mut self, key: &str) -> InterpreterResult)>> + pub fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError> where T: ClarityDeserializable, { @@ -372,7 +373,7 @@ impl RollbackWrapper<'_> { pub fn get_data_with_proof_by_hash( &mut self, hash: &TrieHash, - ) -> InterpreterResult)>> + ) -> Result)>, VmExecutionError> where T: ClarityDeserializable, { @@ -382,14 +383,12 @@ impl RollbackWrapper<'_> { .transpose() } - pub fn get_data(&mut self, key: &str) -> InterpreterResult> + pub fn get_data(&mut self, key: &str) -> Result, VmExecutionError> where T: ClarityDeserializable, { self.stack.last().ok_or_else(|| { - InterpreterError::Expect( - "ERROR: Clarity VM attempted GET on non-nested context.".into(), - ) + VmInternalError::Expect("ERROR: Clarity VM attempted GET on non-nested context.".into()) })?; if self.query_pending_data { @@ -412,7 +411,7 @@ impl RollbackWrapper<'_> { /// /// This should never be called from within the Clarity VM, or via block-processing. It's only /// meant to be used by the RPC system. - pub fn get_data_by_hash(&mut self, hash: &TrieHash) -> InterpreterResult> + pub fn get_data_by_hash(&mut self, hash: &TrieHash) -> Result, VmExecutionError> where T: ClarityDeserializable, { @@ -478,7 +477,7 @@ impl RollbackWrapper<'_> { pub fn get_contract_hash( &mut self, contract: &QualifiedContractIdentifier, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { let key = make_contract_hash_key(contract); let s = match self.get_data::(&key)? { Some(s) => s, @@ -492,7 +491,7 @@ impl RollbackWrapper<'_> { &mut self, contract: &QualifiedContractIdentifier, content_hash: Sha512Trunc256Sum, - ) -> InterpreterResult<()> { + ) -> Result<(), VmExecutionError> { let key = make_contract_hash_key(contract); let value = self.store.make_contract_commitment(content_hash); self.put_data(&key, &value) @@ -503,11 +502,9 @@ impl RollbackWrapper<'_> { contract: &QualifiedContractIdentifier, key: &str, value: &str, - ) -> Result<(), InterpreterError> { + ) -> Result<(), VmInternalError> { let current = self.stack.last_mut().ok_or_else(|| { - InterpreterError::Expect( - "ERROR: Clarity VM attempted PUT on non-nested context.".into(), - ) + VmInternalError::Expect("ERROR: Clarity VM attempted PUT on non-nested context.".into()) })?; let metadata_key = (contract.clone(), key.to_string()); @@ -527,11 +524,9 @@ impl RollbackWrapper<'_> { &mut self, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { self.stack.last().ok_or_else(|| { - InterpreterError::Expect( - "ERROR: Clarity VM attempted GET on non-nested context.".into(), - ) + VmInternalError::Expect("ERROR: Clarity VM attempted GET on non-nested context.".into()) })?; // This is THEORETICALLY a spurious clone, but it's hard to turn something like @@ -558,11 +553,9 @@ impl RollbackWrapper<'_> { at_height: u32, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { self.stack.last().ok_or_else(|| { - InterpreterError::Expect( - "ERROR: Clarity VM attempted GET on non-nested context.".into(), - ) + VmInternalError::Expect("ERROR: Clarity VM attempted GET on non-nested context.".into()) })?; // This is THEORETICALLY a spurious clone, but it's hard to turn something like @@ -582,11 +575,9 @@ impl RollbackWrapper<'_> { } } - pub fn has_entry(&mut self, key: &str) -> InterpreterResult { + pub fn has_entry(&mut self, key: &str) -> Result { self.stack.last().ok_or_else(|| { - InterpreterError::Expect( - "ERROR: Clarity VM attempted GET on non-nested context.".into(), - ) + VmInternalError::Expect("ERROR: Clarity VM attempted GET on non-nested context.".into()) })?; if self.query_pending_data && self.lookup_map.contains_key(key) { Ok(true) diff --git a/clarity/src/vm/database/sqlite.rs b/clarity/src/vm/database/sqlite.rs index c1af5530416..da9b25808c7 100644 --- a/clarity/src/vm/database/sqlite.rs +++ b/clarity/src/vm/database/sqlite.rs @@ -25,10 +25,8 @@ use super::{ ClarityBackingStore, ClarityDatabase, ClarityDeserializable, SpecialCaseHandler, NULL_BURN_STATE_DB, NULL_HEADER_DB, }; -use crate::vm::analysis::{AnalysisDatabase, CheckErrors}; -use crate::vm::errors::{ - IncomparableError, InterpreterError, InterpreterResult as Result, RuntimeErrorType, -}; +use crate::vm::analysis::{AnalysisDatabase, CheckErrorKind}; +use crate::vm::errors::{IncomparableError, RuntimeError, VmExecutionError, VmInternalError}; use crate::vm::types::QualifiedContractIdentifier; const SQL_FAIL_MESSAGE: &str = "PANIC: SQL Failure in Smart Contract VM."; @@ -37,18 +35,18 @@ pub struct SqliteConnection { conn: Connection, } -fn sqlite_put(conn: &Connection, key: &str, value: &str) -> Result<()> { +fn sqlite_put(conn: &Connection, key: &str, value: &str) -> Result<(), VmExecutionError> { let params = params![key, value]; match conn.execute("REPLACE INTO data_table (key, value) VALUES (?, ?)", params) { Ok(_) => Ok(()), Err(e) => { error!("Failed to insert/replace ({key},{value}): {e:?}"); - Err(InterpreterError::DBError(SQL_FAIL_MESSAGE.into()).into()) + Err(VmInternalError::DBError(SQL_FAIL_MESSAGE.into()).into()) } } } -fn sqlite_get(conn: &Connection, key: &str) -> Result> { +fn sqlite_get(conn: &Connection, key: &str) -> Result, VmExecutionError> { trace!("sqlite_get {key}"); let params = params![key]; let res = match conn @@ -62,7 +60,7 @@ fn sqlite_get(conn: &Connection, key: &str) -> Result> { Ok(x) => Ok(x), Err(e) => { error!("Failed to query '{key}': {e:?}"); - Err(InterpreterError::DBError(SQL_FAIL_MESSAGE.into()).into()) + Err(VmInternalError::DBError(SQL_FAIL_MESSAGE.into()).into()) } }; @@ -70,25 +68,25 @@ fn sqlite_get(conn: &Connection, key: &str) -> Result> { res } -fn sqlite_has_entry(conn: &Connection, key: &str) -> Result { +fn sqlite_has_entry(conn: &Connection, key: &str) -> Result { Ok(sqlite_get(conn, key)?.is_some()) } pub fn sqlite_get_contract_hash( store: &mut dyn ClarityBackingStore, contract: &QualifiedContractIdentifier, -) -> Result<(StacksBlockId, Sha512Trunc256Sum)> { +) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError> { let key = make_contract_hash_key(contract); let contract_commitment = store .get_data(&key)? .map(|x| ContractCommitment::deserialize(&x)) - .ok_or_else(|| CheckErrors::NoSuchContract(contract.to_string()))?; + .ok_or_else(|| CheckErrorKind::NoSuchContract(contract.to_string()))?; let ContractCommitment { block_height, hash: contract_hash, } = contract_commitment?; let bhh = store.get_block_at_height(block_height) - .ok_or_else(|| InterpreterError::Expect("Should always be able to map from height to block hash when looking up contract information.".into()))?; + .ok_or_else(|| VmInternalError::Expect("Should always be able to map from height to block hash when looking up contract information.".into()))?; Ok((bhh, contract_hash)) } @@ -97,7 +95,7 @@ pub fn sqlite_insert_metadata( contract: &QualifiedContractIdentifier, key: &str, value: &str, -) -> Result<()> { +) -> Result<(), VmExecutionError> { let bhh = store.get_open_chain_tip(); SqliteConnection::insert_metadata( store.get_side_store(), @@ -112,7 +110,7 @@ pub fn sqlite_get_metadata( store: &mut dyn ClarityBackingStore, contract: &QualifiedContractIdentifier, key: &str, -) -> Result> { +) -> Result, VmExecutionError> { let (bhh, _) = store.get_contract_hash(contract)?; SqliteConnection::get_metadata(store.get_side_store(), &bhh, &contract.to_string(), key) } @@ -122,20 +120,20 @@ pub fn sqlite_get_metadata_manual( at_height: u32, contract: &QualifiedContractIdentifier, key: &str, -) -> Result> { +) -> Result, VmExecutionError> { let bhh = store.get_block_at_height(at_height).ok_or_else(|| { warn!("Unknown block height when manually querying metadata"; "block_height" => at_height); - RuntimeErrorType::BadBlockHeight(at_height.to_string()) + RuntimeError::BadBlockHeight(at_height.to_string()) })?; SqliteConnection::get_metadata(store.get_side_store(), &bhh, &contract.to_string(), key) } impl SqliteConnection { - pub fn put(conn: &Connection, key: &str, value: &str) -> Result<()> { + pub fn put(conn: &Connection, key: &str, value: &str) -> Result<(), VmExecutionError> { sqlite_put(conn, key, value) } - pub fn get(conn: &Connection, key: &str) -> Result> { + pub fn get(conn: &Connection, key: &str) -> Result, VmExecutionError> { sqlite_get(conn, key) } @@ -145,7 +143,7 @@ impl SqliteConnection { contract_hash: &str, key: &str, value: &str, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let key = format!("clr-meta::{contract_hash}::{key}"); let params = params![bhh, key, value]; @@ -154,7 +152,7 @@ impl SqliteConnection { params, ) { error!("Failed to insert ({bhh},{key},{value}): {e:?}"); - return Err(InterpreterError::DBError(SQL_FAIL_MESSAGE.into()).into()); + return Err(VmInternalError::DBError(SQL_FAIL_MESSAGE.into()).into()); } Ok(()) } @@ -163,25 +161,25 @@ impl SqliteConnection { conn: &Connection, from: &StacksBlockId, to: &StacksBlockId, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { let params = params![to, from]; if let Err(e) = conn.execute( "UPDATE metadata_table SET blockhash = ? WHERE blockhash = ?", params, ) { error!("Failed to update {from} to {to}: {e:?}"); - return Err(InterpreterError::DBError(SQL_FAIL_MESSAGE.into()).into()); + return Err(VmInternalError::DBError(SQL_FAIL_MESSAGE.into()).into()); } Ok(()) } - pub fn drop_metadata(conn: &Connection, from: &StacksBlockId) -> Result<()> { + pub fn drop_metadata(conn: &Connection, from: &StacksBlockId) -> Result<(), VmExecutionError> { if let Err(e) = conn.execute( "DELETE FROM metadata_table WHERE blockhash = ?", params![from], ) { error!("Failed to drop metadata from {from}: {e:?}"); - return Err(InterpreterError::DBError(SQL_FAIL_MESSAGE.into()).into()); + return Err(VmInternalError::DBError(SQL_FAIL_MESSAGE.into()).into()); } Ok(()) } @@ -191,7 +189,7 @@ impl SqliteConnection { bhh: &StacksBlockId, contract_hash: &str, key: &str, - ) -> Result> { + ) -> Result, VmExecutionError> { let key = format!("clr-meta::{contract_hash}::{key}"); let params = params![bhh, key]; @@ -206,27 +204,27 @@ impl SqliteConnection { Ok(x) => Ok(x), Err(e) => { error!("Failed to query ({bhh},{key}): {e:?}"); - Err(InterpreterError::DBError(SQL_FAIL_MESSAGE.into()).into()) + Err(VmInternalError::DBError(SQL_FAIL_MESSAGE.into()).into()) } } } - pub fn has_entry(conn: &Connection, key: &str) -> Result { + pub fn has_entry(conn: &Connection, key: &str) -> Result { sqlite_has_entry(conn, key) } } impl SqliteConnection { - pub fn initialize_conn(conn: &Connection) -> Result<()> { + pub fn initialize_conn(conn: &Connection) -> Result<(), VmExecutionError> { conn.query_row("PRAGMA journal_mode = WAL;", NO_PARAMS, |_row| Ok(())) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; conn.execute( "CREATE TABLE IF NOT EXISTS data_table (key TEXT PRIMARY KEY, value TEXT)", NO_PARAMS, ) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; conn.execute( "CREATE TABLE IF NOT EXISTS metadata_table @@ -234,45 +232,45 @@ impl SqliteConnection { UNIQUE (key, blockhash))", NO_PARAMS, ) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; conn.execute( "CREATE INDEX IF NOT EXISTS md_blockhashes ON metadata_table(blockhash)", NO_PARAMS, ) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; Self::check_schema(conn)?; Ok(()) } - pub fn memory() -> Result { + pub fn memory() -> Result { let contract_db = SqliteConnection::inner_open(":memory:")?; SqliteConnection::initialize_conn(&contract_db)?; Ok(contract_db) } - pub fn check_schema(conn: &Connection) -> Result<()> { + pub fn check_schema(conn: &Connection) -> Result<(), VmExecutionError> { let sql = "SELECT sql FROM sqlite_master WHERE name=?"; let _: String = conn .query_row(sql, params!["data_table"], |row| row.get(0)) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; let _: String = conn .query_row(sql, params!["metadata_table"], |row| row.get(0)) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; let _: String = conn .query_row(sql, params!["md_blockhashes"], |row| row.get(0)) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; Ok(()) } - fn inner_open(filename: &str) -> Result { + fn inner_open(filename: &str) -> Result { let conn = Connection::open(filename) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; conn.busy_handler(Some(tx_busy_handler)) - .map_err(|x| InterpreterError::SqliteError(IncomparableError { err: x }))?; + .map_err(|x| VmInternalError::SqliteError(IncomparableError { err: x }))?; Ok(conn) } @@ -310,26 +308,29 @@ impl MemoryBackingStore { } impl ClarityBackingStore for MemoryBackingStore { - fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result { - Err(RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)).into()) + fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result { + Err(RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)).into()) } - fn get_data(&mut self, key: &str) -> Result> { + fn get_data(&mut self, key: &str) -> Result, VmExecutionError> { SqliteConnection::get(self.get_side_store(), key) } - fn get_data_from_path(&mut self, hash: &TrieHash) -> Result> { + fn get_data_from_path(&mut self, hash: &TrieHash) -> Result, VmExecutionError> { SqliteConnection::get(self.get_side_store(), hash.to_string().as_str()) } - fn get_data_with_proof(&mut self, key: &str) -> Result)>> { + fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError> { Ok(SqliteConnection::get(self.get_side_store(), key)?.map(|x| (x, vec![]))) } fn get_data_with_proof_from_path( &mut self, hash: &TrieHash, - ) -> Result)>> { + ) -> Result)>, VmExecutionError> { self.get_data_with_proof(&hash.to_string()) } @@ -361,7 +362,7 @@ impl ClarityBackingStore for MemoryBackingStore { None } - fn put_all_data(&mut self, items: Vec<(String, String)>) -> Result<()> { + fn put_all_data(&mut self, items: Vec<(String, String)>) -> Result<(), VmExecutionError> { for (key, value) in items.into_iter() { SqliteConnection::put(self.get_side_store(), &key, &value)?; } @@ -371,7 +372,7 @@ impl ClarityBackingStore for MemoryBackingStore { fn get_contract_hash( &mut self, contract: &QualifiedContractIdentifier, - ) -> Result<(StacksBlockId, Sha512Trunc256Sum)> { + ) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError> { sqlite_get_contract_hash(self, contract) } @@ -380,7 +381,7 @@ impl ClarityBackingStore for MemoryBackingStore { contract: &QualifiedContractIdentifier, key: &str, value: &str, - ) -> Result<()> { + ) -> Result<(), VmExecutionError> { sqlite_insert_metadata(self, contract, key, value) } @@ -388,7 +389,7 @@ impl ClarityBackingStore for MemoryBackingStore { &mut self, contract: &QualifiedContractIdentifier, key: &str, - ) -> Result> { + ) -> Result, VmExecutionError> { sqlite_get_metadata(self, contract, key) } @@ -397,7 +398,7 @@ impl ClarityBackingStore for MemoryBackingStore { at_height: u32, contract: &QualifiedContractIdentifier, key: &str, - ) -> Result> { + ) -> Result, VmExecutionError> { sqlite_get_metadata_manual(self, at_height, contract, key) } } diff --git a/clarity/src/vm/database/structures.rs b/clarity/src/vm/database/structures.rs index c4fec9f382e..9741f3fb4ff 100644 --- a/clarity/src/vm/database/structures.rs +++ b/clarity/src/vm/database/structures.rs @@ -22,7 +22,7 @@ use stacks_common::util::hash::{hex_bytes, to_hex}; use crate::vm::analysis::ContractAnalysis; use crate::vm::contracts::Contract; use crate::vm::database::ClarityDatabase; -use crate::vm::errors::{Error, InterpreterError, RuntimeErrorType}; +use crate::vm::errors::{RuntimeError, VmExecutionError, VmInternalError}; use crate::vm::types::{PrincipalData, TypeSignature}; pub trait ClaritySerializable { @@ -30,7 +30,7 @@ pub trait ClaritySerializable { } pub trait ClarityDeserializable { - fn deserialize(json: &str) -> Result; + fn deserialize(json: &str) -> Result; } impl ClaritySerializable for String { @@ -40,7 +40,7 @@ impl ClaritySerializable for String { } impl ClarityDeserializable for String { - fn deserialize(serialized: &str) -> Result { + fn deserialize(serialized: &str) -> Result { Ok(serialized.into()) } } @@ -54,7 +54,7 @@ macro_rules! clarity_serializable { } impl ClarityDeserializable<$Name> for $Name { #[cfg(not(target_family = "wasm"))] - fn deserialize(json: &str) -> Result { + fn deserialize(json: &str) -> Result { let mut deserializer = serde_json::Deserializer::from_str(&json); // serde's default 128 depth limit can be exhausted // by a 64-stack-depth AST, so disable the recursion limit @@ -63,13 +63,13 @@ macro_rules! clarity_serializable { // this will instead spill to the heap let deserializer = serde_stacker::Deserializer::new(&mut deserializer); Deserialize::deserialize(deserializer).map_err(|_| { - InterpreterError::Expect("Failed to deserialize vm.Value".into()).into() + VmInternalError::Expect("Failed to deserialize vm.Value".into()).into() }) } #[cfg(target_family = "wasm")] - fn deserialize(json: &str) -> Result { + fn deserialize(json: &str) -> Result { serde_json::from_str(json).map_err(|_| { - InterpreterError::Expect("Failed to deserialize vm.Value".into()).into() + VmInternalError::Expect("Failed to deserialize vm.Value".into()).into() }) } } @@ -257,23 +257,23 @@ impl ClaritySerializable for STXBalance { } impl ClarityDeserializable for STXBalance { - fn deserialize(input: &str) -> Result { + fn deserialize(input: &str) -> Result { let bytes = hex_bytes(input).map_err(|_| { - InterpreterError::Expect("STXBalance deserialization: failed decoding bytes.".into()) + VmInternalError::Expect("STXBalance deserialization: failed decoding bytes.".into()) })?; let result = if bytes.len() == STXBalance::unlocked_and_v1_size { let amount_unlocked = u128::from_be_bytes(bytes[0..16].try_into().map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "STXBalance deserialization: failed reading amount_unlocked.".into(), ) })?); let amount_locked = u128::from_be_bytes(bytes[16..32].try_into().map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "STXBalance deserialization: failed reading amount_locked.".into(), ) })?); let unlock_height = u64::from_be_bytes(bytes[32..40].try_into().map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "STXBalance deserialization: failed reading unlock_height.".into(), ) })?); @@ -295,23 +295,23 @@ impl ClarityDeserializable for STXBalance { && version != &STXBalance::pox_3_version && version != &STXBalance::pox_4_version { - return Err(InterpreterError::Expect(format!( + return Err(VmInternalError::Expect(format!( "Bad version byte in STX Balance serialization = {version}" )) .into()); } let amount_unlocked = u128::from_be_bytes(bytes[1..17].try_into().map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "STXBalance deserialization: failed reading amount_unlocked.".into(), ) })?); let amount_locked = u128::from_be_bytes(bytes[17..33].try_into().map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "STXBalance deserialization: failed reading amount_locked.".into(), ) })?); let unlock_height = u64::from_be_bytes(bytes[33..41].try_into().map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "STXBalance deserialization: failed reading unlock_height.".into(), ) })?); @@ -339,13 +339,13 @@ impl ClarityDeserializable for STXBalance { unlock_height, } } else { - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "Version is checked for pox_3 or pox_2 version compliance above".into(), ) .into()); } } else { - return Err(InterpreterError::Expect(format!( + return Err(VmInternalError::Expect(format!( "Bad STX Balance serialization size = {}", bytes.len() )) @@ -374,14 +374,18 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &self.balance } - pub fn save(self) -> Result<(), Error> { + pub fn save(self) -> Result<(), VmExecutionError> { let key = ClarityDatabase::make_key_for_account_balance(&self.principal); self.db_ref.put_data(&key, &self.balance) } - pub fn transfer_to(mut self, recipient: &PrincipalData, amount: u128) -> Result<(), Error> { + pub fn transfer_to( + mut self, + recipient: &PrincipalData, + amount: u128, + ) -> Result<(), VmExecutionError> { if !self.can_transfer(amount)? { - return Err(InterpreterError::InsufficientBalance.into()); + return Err(VmInternalError::InsufficientBalance.into()); } let recipient_key = ClarityDatabase::make_key_for_account_balance(recipient); @@ -392,7 +396,10 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { recipient_balance .checked_add_unlocked_amount(amount) - .ok_or(Error::Runtime(RuntimeErrorType::ArithmeticOverflow, None))?; + .ok_or(VmExecutionError::Runtime( + RuntimeError::ArithmeticOverflow, + None, + ))?; self.debit(amount)?; self.db_ref.put_data(&recipient_key, &recipient_balance)?; @@ -400,7 +407,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { Ok(()) } - pub fn get_available_balance(&mut self) -> Result { + pub fn get_available_balance(&mut self) -> Result { let v1_unlock_height = self.db_ref.get_v1_unlock_height(); let v2_unlock_height = self.db_ref.get_v2_unlock_height()?; let v3_unlock_height = self.db_ref.get_v3_unlock_height()?; @@ -412,7 +419,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { ) } - pub fn canonical_balance_repr(&mut self) -> Result { + pub fn canonical_balance_repr(&mut self) -> Result { let v1_unlock_height = self.db_ref.get_v1_unlock_height(); let v2_unlock_height = self.db_ref.get_v2_unlock_height()?; let v3_unlock_height = self.db_ref.get_v3_unlock_height()?; @@ -427,7 +434,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { .0) } - pub fn has_locked_tokens(&mut self) -> Result { + pub fn has_locked_tokens(&mut self) -> Result { let v1_unlock_height = self.db_ref.get_v1_unlock_height(); let v2_unlock_height = self.db_ref.get_v2_unlock_height()?; let v3_unlock_height = self.db_ref.get_v3_unlock_height()?; @@ -439,7 +446,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { )) } - pub fn has_unlockable_tokens(&mut self) -> Result { + pub fn has_unlockable_tokens(&mut self) -> Result { let v1_unlock_height = self.db_ref.get_v1_unlock_height(); let v2_unlock_height = self.db_ref.get_v2_unlock_height()?; let v3_unlock_height = self.db_ref.get_v3_unlock_height()?; @@ -451,11 +458,11 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { )) } - pub fn can_transfer(&mut self, amount: u128) -> Result { + pub fn can_transfer(&mut self, amount: u128) -> Result { Ok(self.get_available_balance()? >= amount) } - pub fn debit(&mut self, amount: u128) -> Result<(), Error> { + pub fn debit(&mut self, amount: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-debit"); @@ -464,7 +471,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { self.balance.debit_unlocked_amount(amount) } - pub fn credit(&mut self, amount: u128) -> Result<(), Error> { + pub fn credit(&mut self, amount: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-credit"); @@ -472,7 +479,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { self.balance .checked_add_unlocked_amount(amount) - .ok_or_else(|| InterpreterError::Expect("STX balance overflow".into()))?; + .ok_or_else(|| VmInternalError::Expect("STX balance overflow".into()))?; Ok(()) } @@ -484,7 +491,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &mut self, amount_to_lock: u128, unlock_burn_height: u64, - ) -> Result<(), Error> { + ) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -495,7 +502,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if unlock_burn_height <= self.burn_block_height { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: cannot set a lock with expired unlock burn height".into(), ) .into()); @@ -503,10 +510,9 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if self.has_locked_tokens()? { // caller needs to have checked this - return Err(InterpreterError::Expect( - "FATAL: account already has locked tokens".into(), - ) - .into()); + return Err( + VmInternalError::Expect("FATAL: account already has locked tokens".into()).into(), + ); } // from `unlock_available_tokens_if_any` call above, `self.balance` should @@ -516,7 +522,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { .balance .get_total_balance()? .checked_sub(amount_to_lock) - .ok_or_else(|| InterpreterError::Expect("STX underflow".into()))?; + .ok_or_else(|| VmInternalError::Expect("STX underflow".into()))?; self.balance = STXBalance::LockedPoxOne { amount_unlocked: new_amount_unlocked, @@ -530,7 +536,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Return true iff `self` represents a snapshot that has a lock /// created by PoX v2. - pub fn is_v2_locked(&mut self) -> Result { + pub fn is_v2_locked(&mut self) -> Result { match self.canonical_balance_repr()? { STXBalance::LockedPoxTwo { .. } => Ok(true), _ => Ok(false), @@ -539,7 +545,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Increase the account's current lock to `new_total_locked`. /// Panics if `self` was not locked by V2 PoX. - pub fn increase_lock_v2(&mut self, new_total_locked: u128) -> Result<(), Error> { + pub fn increase_lock_v2(&mut self, new_total_locked: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -547,7 +553,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if !self.has_locked_tokens()? { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: account does not have locked tokens".into(), ) .into()); @@ -556,12 +562,12 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if !self.is_v2_locked()? { // caller needs to have checked this return Err( - InterpreterError::Expect("FATAL: account must be locked by pox-2".into()).into(), + VmInternalError::Expect("FATAL: account must be locked by pox-2".into()).into(), ); } if self.balance.amount_locked() > new_total_locked { - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: account must lock more after `increase_lock_v2`".into(), ) .into()); @@ -571,9 +577,9 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { .balance .amount_unlocked() .checked_add(self.balance.amount_locked()) - .ok_or_else(|| InterpreterError::Expect("STX balance overflowed u128".into()))?; + .ok_or_else(|| VmInternalError::Expect("STX balance overflowed u128".into()))?; let amount_unlocked = total_amount.checked_sub(new_total_locked).ok_or_else(|| { - InterpreterError::Expect("STX underflow: more is locked than total balance".into()) + VmInternalError::Expect("STX underflow: more is locked than total balance".into()) })?; self.balance = STXBalance::LockedPoxTwo { @@ -588,7 +594,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Extend this account's current lock to `unlock_burn_height`. /// After calling, this method will set the balance to a "LockedPoxTwo" balance, /// because this method is only invoked as a result of PoX2 interactions - pub fn extend_lock_v2(&mut self, unlock_burn_height: u64) -> Result<(), Error> { + pub fn extend_lock_v2(&mut self, unlock_burn_height: u64) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -596,7 +602,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if !self.has_locked_tokens()? { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: account does not have locked tokens".into(), ) .into()); @@ -604,7 +610,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if unlock_burn_height <= self.burn_block_height { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: cannot set a lock with expired unlock burn height".into(), ) .into()); @@ -625,7 +631,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &mut self, amount_to_lock: u128, unlock_burn_height: u64, - ) -> Result<(), Error> { + ) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -633,12 +639,12 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { // caller needs to have checked this if amount_to_lock == 0 { - return Err(InterpreterError::Expect("BUG: cannot lock 0 tokens".into()).into()); + return Err(VmInternalError::Expect("BUG: cannot lock 0 tokens".into()).into()); } if unlock_burn_height <= self.burn_block_height { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: cannot set a lock with expired unlock burn height".into(), ) .into()); @@ -646,10 +652,9 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if self.has_locked_tokens()? { // caller needs to have checked this - return Err(InterpreterError::Expect( - "FATAL: account already has locked tokens".into(), - ) - .into()); + return Err( + VmInternalError::Expect("FATAL: account already has locked tokens".into()).into(), + ); } // from `unlock_available_tokens_if_any` call above, `self.balance` should @@ -659,7 +664,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { .balance .get_total_balance()? .checked_sub(amount_to_lock) - .ok_or_else(|| InterpreterError::Expect("STX underflow".into()))?; + .ok_or_else(|| VmInternalError::Expect("STX underflow".into()))?; self.balance = STXBalance::LockedPoxTwo { amount_unlocked: new_amount_unlocked, @@ -678,7 +683,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &mut self, amount_to_lock: u128, unlock_burn_height: u64, - ) -> Result<(), Error> { + ) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -689,7 +694,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if unlock_burn_height <= self.burn_block_height { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: cannot set a lock with expired unlock burn height".into(), ) .into()); @@ -697,10 +702,9 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if self.has_locked_tokens()? { // caller needs to have checked this - return Err(InterpreterError::Expect( - "FATAL: account already has locked tokens".into(), - ) - .into()); + return Err( + VmInternalError::Expect("FATAL: account already has locked tokens".into()).into(), + ); } // from `unlock_available_tokens_if_any` call above, `self.balance` should @@ -711,7 +715,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { .get_total_balance()? .checked_sub(amount_to_lock) .ok_or_else(|| { - InterpreterError::Expect( + VmInternalError::Expect( "FATAL: account locks more STX than balance possessed".into(), ) })?; @@ -728,7 +732,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Extend this account's current lock to `unlock_burn_height`. /// After calling, this method will set the balance to a "LockedPoxThree" balance, /// because this method is only invoked as a result of PoX3 interactions - pub fn extend_lock_v3(&mut self, unlock_burn_height: u64) -> Result<(), Error> { + pub fn extend_lock_v3(&mut self, unlock_burn_height: u64) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -736,7 +740,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if !self.has_locked_tokens()? { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: account does not have locked tokens".into(), ) .into()); @@ -744,7 +748,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if unlock_burn_height <= self.burn_block_height { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: cannot set a lock with expired unlock burn height".into(), ) .into()); @@ -760,7 +764,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Increase the account's current lock to `new_total_locked`. /// Panics if `self` was not locked by V3 PoX. - pub fn increase_lock_v3(&mut self, new_total_locked: u128) -> Result<(), Error> { + pub fn increase_lock_v3(&mut self, new_total_locked: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -768,7 +772,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if !self.has_locked_tokens()? { // caller needs to have checked this - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "FATAL: account does not have locked tokens".into(), ) .into()); @@ -777,7 +781,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { if !self.is_v3_locked()? { // caller needs to have checked this return Err( - InterpreterError::Expect("FATAL: account must be locked by pox-3".into()).into(), + VmInternalError::Expect("FATAL: account must be locked by pox-3".into()).into(), ); } @@ -790,9 +794,9 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { .balance .amount_unlocked() .checked_add(self.balance.amount_locked()) - .ok_or_else(|| InterpreterError::Expect("STX balance overflowed u128".into()))?; + .ok_or_else(|| VmInternalError::Expect("STX balance overflowed u128".into()))?; let amount_unlocked = total_amount.checked_sub(new_total_locked).ok_or_else(|| { - InterpreterError::Expect("STX underflow: more is locked than total balance".into()) + VmInternalError::Expect("STX underflow: more is locked than total balance".into()) })?; self.balance = STXBalance::LockedPoxThree { @@ -805,7 +809,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Return true iff `self` represents a snapshot that has a lock /// created by PoX v3. - pub fn is_v3_locked(&mut self) -> Result { + pub fn is_v3_locked(&mut self) -> Result { match self.canonical_balance_repr()? { STXBalance::LockedPoxThree { .. } => Ok(true), _ => Ok(false), @@ -821,7 +825,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { &mut self, amount_to_lock: u128, unlock_burn_height: u64, - ) -> Result<(), Error> { + ) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -860,7 +864,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Extend this account's current lock to `unlock_burn_height`. /// After calling, this method will set the balance to a "LockedPoxFour" balance, /// because this method is only invoked as a result of PoX3 interactions - pub fn extend_lock_v4(&mut self, unlock_burn_height: u64) -> Result<(), Error> { + pub fn extend_lock_v4(&mut self, unlock_burn_height: u64) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -886,7 +890,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Increase the account's current lock to `new_total_locked`. /// Panics if `self` was not locked by V3 PoX. - pub fn increase_lock_v4(&mut self, new_total_locked: u128) -> Result<(), Error> { + pub fn increase_lock_v4(&mut self, new_total_locked: u128) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after extend-token-lock"); @@ -926,7 +930,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Return true iff `self` represents a snapshot that has a lock /// created by PoX v3. - pub fn is_v4_locked(&mut self) -> Result { + pub fn is_v4_locked(&mut self) -> Result { match self.canonical_balance_repr()? { STXBalance::LockedPoxFour { .. } => Ok(true), _ => Ok(false), @@ -937,7 +941,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// If this snapshot is locked, then alter the lock height to be /// the next burn block (i.e., `self.burn_block_height + 1`) - pub fn accelerate_unlock(&mut self) -> Result<(), Error> { + pub fn accelerate_unlock(&mut self) -> Result<(), VmExecutionError> { let unlocked = self.unlock_available_tokens_if_any()?; if unlocked > 0 { debug!("Consolidated after account-token-lock"); @@ -947,10 +951,10 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { self.balance = match self.balance { STXBalance::Unlocked { amount } => STXBalance::Unlocked { amount }, STXBalance::LockedPoxOne { .. } => { - return Err(InterpreterError::Expect( + return Err(VmInternalError::Expect( "Attempted to accelerate the unlock of a lockup created by PoX-1".into(), ) - .into()) + .into()); } STXBalance::LockedPoxTwo { amount_unlocked, @@ -985,7 +989,7 @@ impl<'db, 'conn> STXBalanceSnapshot<'db, 'conn> { /// Unlock any tokens that are unlockable at the current /// burn block height, and return the amount newly unlocked - fn unlock_available_tokens_if_any(&mut self) -> Result { + fn unlock_available_tokens_if_any(&mut self) -> Result { let (new_balance, unlocked) = self.balance.canonical_repr_at_block( self.burn_block_height, self.db_ref.get_v1_unlock_height(), @@ -1102,7 +1106,7 @@ impl STXBalance { } } - fn debit_unlocked_amount(&mut self, delta: u128) -> Result<(), Error> { + fn debit_unlocked_amount(&mut self, delta: u128) -> Result<(), VmExecutionError> { match self { STXBalance::Unlocked { amount: amount_unlocked, @@ -1121,7 +1125,7 @@ impl STXBalance { } => { *amount_unlocked = amount_unlocked .checked_sub(delta) - .ok_or_else(|| InterpreterError::Expect("STX underflow".into()))?; + .ok_or_else(|| VmInternalError::Expect("STX underflow".into()))?; Ok(()) } } @@ -1164,7 +1168,7 @@ impl STXBalance { v1_unlock_height: u32, v2_unlock_height: u32, v3_unlock_height: u32, - ) -> Result<(STXBalance, u128), Error> { + ) -> Result<(STXBalance, u128), VmExecutionError> { if self.has_unlockable_tokens_at_burn_block( burn_block_height, v1_unlock_height, @@ -1188,7 +1192,7 @@ impl STXBalance { v1_unlock_height: u32, v2_unlock_height: u32, v3_unlock_height: u32, - ) -> Result { + ) -> Result { if self.has_unlockable_tokens_at_burn_block( burn_block_height, v1_unlock_height, @@ -1257,7 +1261,7 @@ impl STXBalance { } } - pub fn get_total_balance(&self) -> Result { + pub fn get_total_balance(&self) -> Result { let (unlocked, locked) = match self { STXBalance::Unlocked { amount } => (*amount, 0), STXBalance::LockedPoxOne { @@ -1283,7 +1287,7 @@ impl STXBalance { }; unlocked .checked_add(locked) - .ok_or_else(|| InterpreterError::Expect("STX overflow".into()).into()) + .ok_or_else(|| VmInternalError::Expect("STX overflow".into()).into()) } pub fn was_locked_by_v1(&self) -> bool { @@ -1462,7 +1466,7 @@ impl STXBalance { v1_unlock_height: u32, v2_unlock_height: u32, v3_unlock_height: u32, - ) -> Result { + ) -> Result { Ok(self.get_available_balance_at_burn_block( burn_block_height, v1_unlock_height, diff --git a/clarity/src/vm/docs/contracts.rs b/clarity/src/vm/docs/contracts.rs index 4860ab3934e..a8f71d214bb 100644 --- a/clarity/src/vm/docs/contracts.rs +++ b/clarity/src/vm/docs/contracts.rs @@ -67,7 +67,7 @@ fn get_constant_value(var_name: &str, contract_content: &str) -> Value { .expect("BUG: failed to return constant value") } -fn doc_execute(program: &str) -> Result, vm::Error> { +fn doc_execute(program: &str) -> Result, vm::VmExecutionError> { let contract_id = QualifiedContractIdentifier::transient(); let mut contract_context = ContractContext::new(contract_id.clone(), ClarityVersion::Clarity2); let mut marf = MemoryBackingStore::new(); diff --git a/clarity/src/vm/errors.rs b/clarity/src/vm/errors.rs index 764ac466e5c..e5d78e24f3b 100644 --- a/clarity/src/vm/errors.rs +++ b/clarity/src/vm/errors.rs @@ -15,12 +15,11 @@ // along with this program. If not, see . pub use clarity_types::errors::{ - Error, IncomparableError, InterpreterError, InterpreterResult, RuntimeErrorType, - ShortReturnType, + EarlyReturnError, IncomparableError, RuntimeError, VmExecutionError, VmInternalError, }; pub use crate::vm::analysis::errors::{ - check_argument_count, check_arguments_at_least, check_arguments_at_most, CheckErrors, + check_argument_count, check_arguments_at_least, check_arguments_at_most, CheckErrorKind, SyntaxBindingError, SyntaxBindingErrorType, }; diff --git a/clarity/src/vm/events.rs b/clarity/src/vm/events.rs index c29517219f2..75169f4f4fd 100644 --- a/clarity/src/vm/events.rs +++ b/clarity/src/vm/events.rs @@ -15,6 +15,7 @@ // along with this program. If not, see . use serde_json::json; +use stacks_common::util::hash::to_hex_prefixed; use super::types::serialization::SerializationError; use crate::vm::types::{ @@ -219,18 +220,15 @@ pub struct NFTTransferEventData { impl NFTTransferEventData { pub fn json_serialize(&self) -> Result { - let raw_value = { - let mut bytes = vec![]; - self.value.serialize_write(&mut bytes)?; - let formatted_bytes: Vec = bytes.iter().map(|b| format!("{b:02x}")).collect(); - formatted_bytes - }; + let mut byte_serialization = Vec::new(); + self.value.serialize_write(&mut byte_serialization)?; + let raw_value = to_hex_prefixed(byte_serialization.as_slice(), true); Ok(json!({ "asset_identifier": format!("{}", self.asset_identifier), "sender": format!("{}",self.sender), "recipient": format!("{}",self.recipient), "value": self.value, - "raw_value": format!("0x{}", raw_value.join("")), + "raw_value": raw_value, })) } } @@ -244,17 +242,14 @@ pub struct NFTMintEventData { impl NFTMintEventData { pub fn json_serialize(&self) -> Result { - let raw_value = { - let mut bytes = vec![]; - self.value.serialize_write(&mut bytes)?; - let formatted_bytes: Vec = bytes.iter().map(|b| format!("{b:02x}")).collect(); - formatted_bytes - }; + let mut byte_serialization = Vec::new(); + self.value.serialize_write(&mut byte_serialization)?; + let raw_value = to_hex_prefixed(byte_serialization.as_slice(), true); Ok(json!({ "asset_identifier": format!("{}", self.asset_identifier), "recipient": format!("{}",self.recipient), "value": self.value, - "raw_value": format!("0x{}", raw_value.join("")), + "raw_value": raw_value, })) } } @@ -268,17 +263,14 @@ pub struct NFTBurnEventData { impl NFTBurnEventData { pub fn json_serialize(&self) -> Result { - let raw_value = { - let mut bytes = vec![]; - self.value.serialize_write(&mut bytes)?; - let formatted_bytes: Vec = bytes.iter().map(|b| format!("{b:02x}")).collect(); - formatted_bytes - }; + let mut byte_serialization = Vec::new(); + self.value.serialize_write(&mut byte_serialization)?; + let raw_value = to_hex_prefixed(byte_serialization.as_slice(), true); Ok(json!({ "asset_identifier": format!("{}", self.asset_identifier), "sender": format!("{}",self.sender), "value": self.value, - "raw_value": format!("0x{}", raw_value.join("")), + "raw_value": raw_value, })) } } @@ -344,17 +336,14 @@ pub struct SmartContractEventData { impl SmartContractEventData { pub fn json_serialize(&self) -> Result { - let raw_value = { - let mut bytes = vec![]; - self.value.serialize_write(&mut bytes)?; - let formatted_bytes: Vec = bytes.iter().map(|b| format!("{b:02x}")).collect(); - formatted_bytes - }; + let mut byte_serialization = Vec::new(); + self.value.serialize_write(&mut byte_serialization)?; + let raw_value = to_hex_prefixed(byte_serialization.as_slice(), true); Ok(json!({ "contract_identifier": self.key.0.to_string(), "topic": self.key.1, "value": self.value, - "raw_value": format!("0x{}", raw_value.join("")), + "raw_value": raw_value, })) } } diff --git a/clarity/src/vm/functions/arithmetic.rs b/clarity/src/vm/functions/arithmetic.rs index fcbbc5ab489..cf629a85d8a 100644 --- a/clarity/src/vm/functions/arithmetic.rs +++ b/clarity/src/vm/functions/arithmetic.rs @@ -21,7 +21,7 @@ use integer_sqrt::IntegerSquareRoot; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; use crate::vm::errors::{ - check_argument_count, CheckErrors, InterpreterError, InterpreterResult, RuntimeErrorType, + check_argument_count, CheckErrorKind, RuntimeError, VmExecutionError, VmInternalError, }; use crate::vm::representations::SymbolicExpression; use crate::vm::types::{ @@ -37,25 +37,25 @@ struct UTF8Ops(); struct BuffOps(); impl U128Ops { - fn make_value(x: u128) -> InterpreterResult { + fn make_value(x: u128) -> Result { Ok(Value::UInt(x)) } } impl I128Ops { - fn make_value(x: i128) -> InterpreterResult { + fn make_value(x: i128) -> Result { Ok(Value::Int(x)) } } impl ASCIIOps { - fn make_value(x: Vec) -> InterpreterResult { + fn make_value(x: Vec) -> Result { Ok(Value::Sequence(SequenceData::String(CharType::ASCII( ASCIIData { data: x }, )))) } } impl UTF8Ops { - fn make_value(x: Vec>) -> InterpreterResult { + fn make_value(x: Vec>) -> Result { Ok(Value::Sequence(SequenceData::String(CharType::UTF8( UTF8Data { data: x }, )))) @@ -63,7 +63,7 @@ impl UTF8Ops { } impl BuffOps { - fn make_value(x: Vec) -> InterpreterResult { + fn make_value(x: Vec) -> Result { Ok(Value::Sequence(SequenceData::Buffer(BuffData { data: x }))) } } @@ -76,7 +76,7 @@ macro_rules! type_force_binary_arithmetic { match ($x, $y) { (Value::Int(x), Value::Int(y)) => I128Ops::$function(x, y), (Value::UInt(x), Value::UInt(y)) => U128Ops::$function(x, y), - (x, _) => Err(CheckErrors::UnionTypeValueError( + (x, _) => Err(CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(x), ) @@ -91,7 +91,7 @@ macro_rules! type_force_binary_comparison_v1 { match ($x, $y) { (Value::Int(x), Value::Int(y)) => I128Ops::$function(x, y), (Value::UInt(x), Value::UInt(y)) => U128Ops::$function(x, y), - (x, _) => Err(CheckErrors::UnionTypeValueError( + (x, _) => Err(CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(x), ) @@ -119,7 +119,7 @@ macro_rules! type_force_binary_comparison_v2 { Value::Sequence(SequenceData::Buffer(BuffData { data: x })), Value::Sequence(SequenceData::Buffer(BuffData { data: y })), ) => BuffOps::$function(x, y), - (x, _) => Err(CheckErrors::UnionTypeValueError( + (x, _) => Err(CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -139,7 +139,7 @@ macro_rules! type_force_unary_arithmetic { match $x { Value::Int(x) => I128Ops::$function(x), Value::UInt(x) => U128Ops::$function(x), - x => Err(CheckErrors::UnionTypeValueError( + x => Err(CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(x), ) @@ -155,14 +155,14 @@ macro_rules! type_force_variadic_arithmetic { ($function: ident, $args: expr) => {{ let first = $args .get(0) - .ok_or(CheckErrors::IncorrectArgumentCount(1, $args.len()))?; + .ok_or(CheckErrorKind::IncorrectArgumentCount(1, $args.len()))?; match first { Value::Int(_) => { let typed_args: Result, _> = $args .drain(..) .map(|x| match x { Value::Int(value) => Ok(value), - _ => Err(CheckErrors::TypeValueError( + _ => Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::IntType), Box::new(x.clone()), )), @@ -176,7 +176,7 @@ macro_rules! type_force_variadic_arithmetic { .drain(..) .map(|x| match x { Value::UInt(value) => Ok(value), - _ => Err(CheckErrors::TypeValueError( + _ => Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(x.clone()), )), @@ -185,7 +185,7 @@ macro_rules! type_force_variadic_arithmetic { let checked_args = typed_args?; U128Ops::$function(&checked_args) } - _ => Err(CheckErrors::UnionTypeValueError( + _ => Err(CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(first.clone()), ) @@ -199,16 +199,16 @@ macro_rules! type_force_variadic_arithmetic { macro_rules! make_comparison_ops { ($struct_name: ident, $type:ty) => { impl $struct_name { - fn greater(x: $type, y: $type) -> InterpreterResult { + fn greater(x: $type, y: $type) -> Result { Ok(Value::Bool(x > y)) } - fn less(x: $type, y: $type) -> InterpreterResult { + fn less(x: $type, y: $type) -> Result { Ok(Value::Bool(x < y)) } - fn leq(x: $type, y: $type) -> InterpreterResult { + fn leq(x: $type, y: $type) -> Result { Ok(Value::Bool(x <= y)) } - fn geq(x: $type, y: $type) -> InterpreterResult { + fn geq(x: $type, y: $type) -> Result { Ok(Value::Bool(x >= y)) } } @@ -222,14 +222,14 @@ macro_rules! make_comparison_ops { macro_rules! make_arithmetic_ops { ($struct_name: ident, $type:ty) => { impl $struct_name { - fn xor(x: $type, y: $type) -> InterpreterResult { + fn xor(x: $type, y: $type) -> Result { Self::make_value(x ^ y) } - fn bitwise_xor2(args: &[$type]) -> InterpreterResult { + fn bitwise_xor2(args: &[$type]) -> Result { let result = args.iter().fold(0, |acc: $type, x: &$type| (acc ^ x)); Self::make_value(result) } - fn bitwise_and(args: &[$type]) -> InterpreterResult { + fn bitwise_and(args: &[$type]) -> Result { let first: $type = args[0]; let result = args .iter() @@ -237,64 +237,64 @@ macro_rules! make_arithmetic_ops { .fold(first, |acc: $type, x: &$type| (acc & x)); Self::make_value(result) } - fn bitwise_or(args: &[$type]) -> InterpreterResult { + fn bitwise_or(args: &[$type]) -> Result { let result = args.iter().fold(0, |acc: $type, x: &$type| (acc | x)); Self::make_value(result) } - fn bitwise_not(x: $type) -> InterpreterResult { + fn bitwise_not(x: $type) -> Result { Self::make_value(!x) } - fn add(args: &[$type]) -> InterpreterResult { + fn add(args: &[$type]) -> Result { let result = args .iter() .try_fold(0, |acc: $type, x: &$type| acc.checked_add(*x)) - .ok_or(RuntimeErrorType::ArithmeticOverflow)?; + .ok_or(RuntimeError::ArithmeticOverflow)?; Self::make_value(result) } - fn sub(args: &[$type]) -> InterpreterResult { + fn sub(args: &[$type]) -> Result { let (first, rest) = args .split_first() - .ok_or(CheckErrors::IncorrectArgumentCount(1, 0))?; + .ok_or(CheckErrorKind::IncorrectArgumentCount(1, 0))?; if rest.len() == 0 { // return negation return Self::make_value( first .checked_neg() - .ok_or(RuntimeErrorType::ArithmeticUnderflow)?, + .ok_or(RuntimeError::ArithmeticUnderflow)?, ); } let result = rest .iter() .try_fold(*first, |acc: $type, x: &$type| acc.checked_sub(*x)) - .ok_or(RuntimeErrorType::ArithmeticUnderflow)?; + .ok_or(RuntimeError::ArithmeticUnderflow)?; Self::make_value(result) } - fn mul(args: &[$type]) -> InterpreterResult { + fn mul(args: &[$type]) -> Result { let result = args .iter() .try_fold(1, |acc: $type, x: &$type| acc.checked_mul(*x)) - .ok_or(RuntimeErrorType::ArithmeticOverflow)?; + .ok_or(RuntimeError::ArithmeticOverflow)?; Self::make_value(result) } - fn div(args: &[$type]) -> InterpreterResult { + fn div(args: &[$type]) -> Result { let (first, rest) = args .split_first() - .ok_or(CheckErrors::IncorrectArgumentCount(1, 0))?; + .ok_or(CheckErrorKind::IncorrectArgumentCount(1, 0))?; let result = rest .iter() .try_fold(*first, |acc: $type, x: &$type| acc.checked_div(*x)) - .ok_or(RuntimeErrorType::DivisionByZero)?; + .ok_or(RuntimeError::DivisionByZero)?; Self::make_value(result) } - fn modulo(numerator: $type, denominator: $type) -> InterpreterResult { + fn modulo(numerator: $type, denominator: $type) -> Result { let result = numerator .checked_rem(denominator) - .ok_or(RuntimeErrorType::DivisionByZero)?; + .ok_or(RuntimeError::DivisionByZero)?; Self::make_value(result) } #[allow(unused_comparisons)] - fn pow(base: $type, power: $type) -> InterpreterResult { + fn pow(base: $type, power: $type) -> Result { if base == 0 && power == 0 { // Note that 0⁰ (pow(0, 0)) returns 1. Mathematically this is undefined (https://docs.rs/num-traits/0.2.10/num_traits/pow/fn.pow.html) return Self::make_value(1); @@ -312,7 +312,7 @@ macro_rules! make_arithmetic_ops { } if power < 0 || power > (u32::MAX as $type) { - return Err(RuntimeErrorType::Arithmetic( + return Err(RuntimeError::Arithmetic( "Power argument to (pow ...) must be a u32 integer".to_string(), ) .into()); @@ -322,23 +322,23 @@ macro_rules! make_arithmetic_ops { let result = base .checked_pow(power_u32) - .ok_or(RuntimeErrorType::ArithmeticOverflow)?; + .ok_or(RuntimeError::ArithmeticOverflow)?; Self::make_value(result) } - fn sqrti(n: $type) -> InterpreterResult { + fn sqrti(n: $type) -> Result { match n.integer_sqrt_checked() { Some(result) => Self::make_value(result), None => { - return Err(RuntimeErrorType::Arithmetic( + return Err(RuntimeError::Arithmetic( "sqrti must be passed a positive integer".to_string(), ) .into()) } } } - fn log2(n: $type) -> InterpreterResult { + fn log2(n: $type) -> Result { if n < 1 { - return Err(RuntimeErrorType::Arithmetic( + return Err(RuntimeError::Arithmetic( "log2 must be passed a positive integer".to_string(), ) .into()); @@ -360,24 +360,24 @@ make_comparison_ops!(UTF8Ops, Vec>); make_comparison_ops!(BuffOps, Vec); // Used for the `xor` function. -pub fn native_xor(a: Value, b: Value) -> InterpreterResult { +pub fn native_xor(a: Value, b: Value) -> Result { type_force_binary_arithmetic!(xor, a, b) } // Used for the `^` xor function. -pub fn native_bitwise_xor(mut args: Vec) -> InterpreterResult { +pub fn native_bitwise_xor(mut args: Vec) -> Result { type_force_variadic_arithmetic!(bitwise_xor2, args) } -pub fn native_bitwise_and(mut args: Vec) -> InterpreterResult { +pub fn native_bitwise_and(mut args: Vec) -> Result { type_force_variadic_arithmetic!(bitwise_and, args) } -pub fn native_bitwise_or(mut args: Vec) -> InterpreterResult { +pub fn native_bitwise_or(mut args: Vec) -> Result { type_force_variadic_arithmetic!(bitwise_or, args) } -pub fn native_bitwise_not(a: Value) -> InterpreterResult { +pub fn native_bitwise_not(a: Value) -> Result { type_force_unary_arithmetic!(bitwise_not, a) } @@ -387,7 +387,7 @@ fn special_geq_v1( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { check_argument_count(2, args)?; let a = eval(&args[0], env, context)?; let b = eval(&args[1], env, context)?; @@ -401,7 +401,7 @@ fn special_geq_v2( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { check_argument_count(2, args)?; let a = eval(&args[0], env, context)?; let b = eval(&args[1], env, context)?; @@ -419,7 +419,7 @@ pub fn special_geq( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { if *env.contract_context.get_clarity_version() >= ClarityVersion::Clarity2 { special_geq_v2(args, env, context) } else { @@ -434,7 +434,7 @@ fn special_leq_v1( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { check_argument_count(2, args)?; let a = eval(&args[0], env, context)?; let b = eval(&args[1], env, context)?; @@ -448,7 +448,7 @@ fn special_leq_v2( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { check_argument_count(2, args)?; let a = eval(&args[0], env, context)?; let b = eval(&args[1], env, context)?; @@ -466,7 +466,7 @@ pub fn special_leq( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { if *env.contract_context.get_clarity_version() >= ClarityVersion::Clarity2 { special_leq_v2(args, env, context) } else { @@ -480,7 +480,7 @@ fn special_greater_v1( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { check_argument_count(2, args)?; let a = eval(&args[0], env, context)?; let b = eval(&args[1], env, context)?; @@ -494,7 +494,7 @@ fn special_greater_v2( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { check_argument_count(2, args)?; let a = eval(&args[0], env, context)?; let b = eval(&args[1], env, context)?; @@ -508,7 +508,7 @@ pub fn special_greater( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { if *env.contract_context.get_clarity_version() >= ClarityVersion::Clarity2 { special_greater_v2(args, env, context) } else { @@ -522,7 +522,7 @@ fn special_less_v1( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { check_argument_count(2, args)?; let a = eval(&args[0], env, context)?; let b = eval(&args[1], env, context)?; @@ -536,7 +536,7 @@ fn special_less_v2( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { check_argument_count(2, args)?; let a = eval(&args[0], env, context)?; let b = eval(&args[1], env, context)?; @@ -550,7 +550,7 @@ pub fn special_less( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { if *env.contract_context.get_clarity_version() >= ClarityVersion::Clarity2 { special_less_v2(args, env, context) } else { @@ -558,35 +558,35 @@ pub fn special_less( } } -pub fn native_add(mut args: Vec) -> InterpreterResult { +pub fn native_add(mut args: Vec) -> Result { type_force_variadic_arithmetic!(add, args) } -pub fn native_sub(mut args: Vec) -> InterpreterResult { +pub fn native_sub(mut args: Vec) -> Result { type_force_variadic_arithmetic!(sub, args) } -pub fn native_mul(mut args: Vec) -> InterpreterResult { +pub fn native_mul(mut args: Vec) -> Result { type_force_variadic_arithmetic!(mul, args) } -pub fn native_div(mut args: Vec) -> InterpreterResult { +pub fn native_div(mut args: Vec) -> Result { type_force_variadic_arithmetic!(div, args) } -pub fn native_pow(a: Value, b: Value) -> InterpreterResult { +pub fn native_pow(a: Value, b: Value) -> Result { type_force_binary_arithmetic!(pow, a, b) } -pub fn native_sqrti(n: Value) -> InterpreterResult { +pub fn native_sqrti(n: Value) -> Result { type_force_unary_arithmetic!(sqrti, n) } -pub fn native_log2(n: Value) -> InterpreterResult { +pub fn native_log2(n: Value) -> Result { type_force_unary_arithmetic!(log2, n) } -pub fn native_mod(a: Value, b: Value) -> InterpreterResult { +pub fn native_mod(a: Value, b: Value) -> Result { type_force_binary_arithmetic!(modulo, a, b) } -pub fn native_bitwise_left_shift(input: Value, pos: Value) -> InterpreterResult { +pub fn native_bitwise_left_shift(input: Value, pos: Value) -> Result { if let Value::UInt(u128_val) = pos { let shamt = u32::try_from(u128_val & 0x7f).map_err(|_| { - InterpreterError::Expect("FATAL: lower 32 bits did not convert to u32".into()) + VmInternalError::Expect("FATAL: lower 32 bits did not convert to u32".into()) })?; match input { @@ -598,21 +598,21 @@ pub fn native_bitwise_left_shift(input: Value, pos: Value) -> InterpreterResult< let result = input.wrapping_shl(shamt); Ok(Value::UInt(result)) } - _ => Err(CheckErrors::UnionTypeError( + _ => Err(CheckErrorKind::UnionTypeError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(TypeSignature::type_of(&input)?), ) .into()), } } else { - Err(CheckErrors::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(pos)).into()) + Err(CheckErrorKind::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(pos)).into()) } } -pub fn native_bitwise_right_shift(input: Value, pos: Value) -> InterpreterResult { +pub fn native_bitwise_right_shift(input: Value, pos: Value) -> Result { if let Value::UInt(u128_val) = pos { let shamt = u32::try_from(u128_val & 0x7f).map_err(|_| { - InterpreterError::Expect("FATAL: lower 32 bits did not convert to u32".into()) + VmInternalError::Expect("FATAL: lower 32 bits did not convert to u32".into()) })?; match input { @@ -624,32 +624,37 @@ pub fn native_bitwise_right_shift(input: Value, pos: Value) -> InterpreterResult let result = input.wrapping_shr(shamt); Ok(Value::UInt(result)) } - _ => Err(CheckErrors::UnionTypeError( + _ => Err(CheckErrorKind::UnionTypeError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(TypeSignature::type_of(&input)?), ) .into()), } } else { - Err(CheckErrors::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(pos)).into()) + Err(CheckErrorKind::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(pos)).into()) } } -pub fn native_to_uint(input: Value) -> InterpreterResult { +pub fn native_to_uint(input: Value) -> Result { if let Value::Int(int_val) = input { - let uint_val = - u128::try_from(int_val).map_err(|_| RuntimeErrorType::ArithmeticUnderflow)?; + let uint_val = u128::try_from(int_val).map_err(|_| RuntimeError::ArithmeticUnderflow)?; Ok(Value::UInt(uint_val)) } else { - Err(CheckErrors::TypeValueError(Box::new(TypeSignature::IntType), Box::new(input)).into()) + Err( + CheckErrorKind::TypeValueError(Box::new(TypeSignature::IntType), Box::new(input)) + .into(), + ) } } -pub fn native_to_int(input: Value) -> InterpreterResult { +pub fn native_to_int(input: Value) -> Result { if let Value::UInt(uint_val) = input { - let int_val = i128::try_from(uint_val).map_err(|_| RuntimeErrorType::ArithmeticOverflow)?; + let int_val = i128::try_from(uint_val).map_err(|_| RuntimeError::ArithmeticOverflow)?; Ok(Value::Int(int_val)) } else { - Err(CheckErrors::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(input)).into()) + Err( + CheckErrorKind::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(input)) + .into(), + ) } } diff --git a/clarity/src/vm/functions/assets.rs b/clarity/src/vm/functions/assets.rs index 62763fa3fc0..debbee8ec5b 100644 --- a/clarity/src/vm/functions/assets.rs +++ b/clarity/src/vm/functions/assets.rs @@ -20,8 +20,7 @@ use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{runtime_cost, CostTracker}; use crate::vm::database::STXBalance; use crate::vm::errors::{ - check_argument_count, CheckErrors, Error, InterpreterError, InterpreterResult as Result, - RuntimeErrorType, + check_argument_count, CheckErrorKind, RuntimeError, VmExecutionError, VmInternalError, }; use crate::vm::representations::SymbolicExpression; use crate::vm::types::{ @@ -91,7 +90,7 @@ pub fn special_stx_balance( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::StxBalance, env, 0)?; @@ -109,7 +108,7 @@ pub fn special_stx_balance( Ok(Value::UInt(balance)) } else { Err( - CheckErrors::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(owner)) + CheckErrorKind::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(owner)) .into(), ) } @@ -124,7 +123,7 @@ pub fn stx_transfer_consolidated( to: &PrincipalData, amount: u128, memo: &BuffData, -) -> Result { +) -> Result { if amount == 0 { return clarity_ecode!(StxErrorCodes::NON_POSITIVE_AMOUNT); } @@ -162,7 +161,7 @@ pub fn special_stx_transfer( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::StxTransfer, env, 0)?; @@ -181,7 +180,7 @@ pub fn special_stx_transfer( { stx_transfer_consolidated(env, from, to, amount, memo) } else { - Err(CheckErrors::BadTransferSTXArguments.into()) + Err(CheckErrorKind::BadTransferSTXArguments.into()) } } @@ -189,7 +188,7 @@ pub fn special_stx_transfer_memo( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; runtime_cost(ClarityCostFunction::StxTransferMemo, env, 0)?; @@ -207,7 +206,7 @@ pub fn special_stx_transfer_memo( { stx_transfer_consolidated(env, from, to, amount, memo) } else { - Err(CheckErrors::BadTransferSTXArguments.into()) + Err(CheckErrorKind::BadTransferSTXArguments.into()) } } @@ -216,7 +215,7 @@ pub fn special_stx_account( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::StxGetAccount, env, 0)?; @@ -225,7 +224,7 @@ pub fn special_stx_account( let principal = if let Value::Principal(p) = owner { p } else { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::PrincipalType), Box::new(owner), ) @@ -245,19 +244,19 @@ pub fn special_stx_account( ( "unlocked" .try_into() - .map_err(|_| InterpreterError::Expect("Bad special tuple name".into()))?, + .map_err(|_| VmInternalError::Expect("Bad special tuple name".into()))?, Value::UInt(stx_balance.amount_unlocked()), ), ( "locked" .try_into() - .map_err(|_| InterpreterError::Expect("Bad special tuple name".into()))?, + .map_err(|_| VmInternalError::Expect("Bad special tuple name".into()))?, Value::UInt(stx_balance.amount_locked()), ), ( "unlock-height" .try_into() - .map_err(|_| InterpreterError::Expect("Bad special tuple name".into()))?, + .map_err(|_| VmInternalError::Expect("Bad special tuple name".into()))?, Value::UInt(u128::from(stx_balance.effective_unlock_height( v1_unlock_ht, v2_unlock_ht, @@ -272,7 +271,7 @@ pub fn special_stx_burn( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::StxTransfer, env, 0)?; @@ -309,7 +308,7 @@ pub fn special_stx_burn( Ok(Value::okay_true()) } else { - Err(CheckErrors::BadTransferSTXArguments.into()) + Err(CheckErrorKind::BadTransferSTXArguments.into()) } } @@ -317,12 +316,12 @@ pub fn special_mint_token( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::FtMint, env, 0)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let amount = eval(&args[1], env, context)?; let to = eval(&args[2], env, context)?; @@ -336,7 +335,7 @@ pub fn special_mint_token( .contract_context .meta_ft .get(token_name) - .ok_or(CheckErrors::NoSuchFT(token_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchFT(token_name.to_string()))?; env.global_context.database.checked_increase_token_supply( &env.contract_context.contract_identifier, @@ -354,7 +353,7 @@ pub fn special_mint_token( let final_to_bal = to_bal .checked_add(amount) - .ok_or_else(|| InterpreterError::Expect("STX overflow".into()))?; + .ok_or_else(|| VmInternalError::Expect("STX overflow".into()))?; env.add_memory(TypeSignature::PrincipalType.size()? as u64)?; env.add_memory(TypeSignature::UIntType.size()? as u64)?; @@ -374,7 +373,7 @@ pub fn special_mint_token( Ok(Value::okay_true()) } else { - Err(CheckErrors::BadMintFTArguments.into()) + Err(CheckErrorKind::BadMintFTArguments.into()) } } @@ -382,10 +381,10 @@ pub fn special_mint_asset_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let asset = eval(&args[1], env, context)?; let to = eval(&args[2], env, context)?; @@ -394,7 +393,7 @@ pub fn special_mint_asset_v200( .contract_context .meta_nft .get(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; let expected_asset_type = &nft_metadata.key_type; runtime_cost( @@ -404,7 +403,7 @@ pub fn special_mint_asset_v200( )?; if !expected_asset_type.admits(env.epoch(), &asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_asset_type.clone()), Box::new(asset), ) @@ -418,7 +417,7 @@ pub fn special_mint_asset_v200( &asset, expected_asset_type, ) { - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(()), + Err(VmExecutionError::Runtime(RuntimeError::NoSuchToken, _)) => Ok(()), Ok(_owner) => return clarity_ecode!(MintAssetErrorCodes::ALREADY_EXIST), Err(e) => Err(e), }?; @@ -445,7 +444,7 @@ pub fn special_mint_asset_v200( Ok(Value::okay_true()) } else { Err( - CheckErrors::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(to)) + CheckErrorKind::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(to)) .into(), ) } @@ -457,10 +456,10 @@ pub fn special_mint_asset_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let asset = eval(&args[1], env, context)?; let to = eval(&args[2], env, context)?; @@ -469,16 +468,16 @@ pub fn special_mint_asset_v205( .contract_context .meta_nft .get(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; let expected_asset_type = &nft_metadata.key_type; let asset_size = asset .serialized_size() - .map_err(|e| InterpreterError::Expect(e.to_string()))? as u64; + .map_err(|e| VmInternalError::Expect(e.to_string()))? as u64; runtime_cost(ClarityCostFunction::NftMint, env, asset_size)?; if !expected_asset_type.admits(env.epoch(), &asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_asset_type.clone()), Box::new(asset), ) @@ -492,7 +491,7 @@ pub fn special_mint_asset_v205( &asset, expected_asset_type, ) { - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(()), + Err(VmExecutionError::Runtime(RuntimeError::NoSuchToken, _)) => Ok(()), Ok(_owner) => return clarity_ecode!(MintAssetErrorCodes::ALREADY_EXIST), Err(e) => Err(e), }?; @@ -519,7 +518,7 @@ pub fn special_mint_asset_v205( Ok(Value::okay_true()) } else { Err( - CheckErrors::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(to)) + CheckErrorKind::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(to)) .into(), ) } @@ -529,10 +528,10 @@ pub fn special_transfer_asset_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let asset = eval(&args[1], env, context)?; let from = eval(&args[2], env, context)?; @@ -542,7 +541,7 @@ pub fn special_transfer_asset_v200( .contract_context .meta_nft .get(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; let expected_asset_type = &nft_metadata.key_type; runtime_cost( @@ -552,7 +551,7 @@ pub fn special_transfer_asset_v200( )?; if !expected_asset_type.admits(env.epoch(), &asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_asset_type.clone()), Box::new(asset), ) @@ -571,7 +570,7 @@ pub fn special_transfer_asset_v200( expected_asset_type, ) { Ok(owner) => Ok(owner), - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => { + Err(VmExecutionError::Runtime(RuntimeError::NoSuchToken, _)) => { return clarity_ecode!(TransferAssetErrorCodes::DOES_NOT_EXIST) } Err(e) => Err(e), @@ -614,7 +613,7 @@ pub fn special_transfer_asset_v200( Ok(Value::okay_true()) } else { - Err(CheckErrors::BadTransferNFTArguments.into()) + Err(CheckErrorKind::BadTransferNFTArguments.into()) } } @@ -624,10 +623,10 @@ pub fn special_transfer_asset_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let asset = eval(&args[1], env, context)?; let from = eval(&args[2], env, context)?; @@ -637,16 +636,16 @@ pub fn special_transfer_asset_v205( .contract_context .meta_nft .get(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; let expected_asset_type = &nft_metadata.key_type; let asset_size = asset .serialized_size() - .map_err(|e| InterpreterError::Expect(e.to_string()))? as u64; + .map_err(|e| VmInternalError::Expect(e.to_string()))? as u64; runtime_cost(ClarityCostFunction::NftTransfer, env, asset_size)?; if !expected_asset_type.admits(env.epoch(), &asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_asset_type.clone()), Box::new(asset), ) @@ -665,7 +664,7 @@ pub fn special_transfer_asset_v205( expected_asset_type, ) { Ok(owner) => Ok(owner), - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => { + Err(VmExecutionError::Runtime(RuntimeError::NoSuchToken, _)) => { return clarity_ecode!(TransferAssetErrorCodes::DOES_NOT_EXIST) } Err(e) => Err(e), @@ -708,7 +707,7 @@ pub fn special_transfer_asset_v205( Ok(Value::okay_true()) } else { - Err(CheckErrors::BadTransferNFTArguments.into()) + Err(CheckErrorKind::BadTransferNFTArguments.into()) } } @@ -716,12 +715,12 @@ pub fn special_transfer_token( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(4, args)?; runtime_cost(ClarityCostFunction::FtTransfer, env, 0)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let amount = eval(&args[1], env, context)?; let from = eval(&args[2], env, context)?; @@ -745,7 +744,7 @@ pub fn special_transfer_token( .contract_context .meta_ft .get(token_name) - .ok_or(CheckErrors::NoSuchFT(token_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchFT(token_name.to_string()))?; let from_bal = env.global_context.database.get_ft_balance( &env.contract_context.contract_identifier, @@ -769,7 +768,7 @@ pub fn special_transfer_token( let final_to_bal = to_bal .checked_add(amount) - .ok_or(RuntimeErrorType::ArithmeticOverflow)?; + .ok_or(RuntimeError::ArithmeticOverflow)?; env.add_memory(TypeSignature::PrincipalType.size()? as u64)?; env.add_memory(TypeSignature::PrincipalType.size()? as u64)?; @@ -809,7 +808,7 @@ pub fn special_transfer_token( Ok(Value::okay_true()) } else { - Err(CheckErrors::BadTransferFTArguments.into()) + Err(CheckErrorKind::BadTransferFTArguments.into()) } } @@ -817,12 +816,12 @@ pub fn special_get_balance( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::FtBalance, env, 0)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let owner = eval(&args[1], env, context)?; @@ -831,7 +830,7 @@ pub fn special_get_balance( .contract_context .meta_ft .get(token_name) - .ok_or(CheckErrors::NoSuchFT(token_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchFT(token_name.to_string()))?; let balance = env.global_context.database.get_ft_balance( &env.contract_context.contract_identifier, @@ -842,7 +841,7 @@ pub fn special_get_balance( Ok(Value::UInt(balance)) } else { Err( - CheckErrors::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(owner)) + CheckErrorKind::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(owner)) .into(), ) } @@ -852,10 +851,10 @@ pub fn special_get_owner_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let asset = eval(&args[1], env, context)?; @@ -863,7 +862,7 @@ pub fn special_get_owner_v200( .contract_context .meta_nft .get(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; let expected_asset_type = &nft_metadata.key_type; runtime_cost( @@ -873,7 +872,7 @@ pub fn special_get_owner_v200( )?; if !expected_asset_type.admits(env.epoch(), &asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_asset_type.clone()), Box::new(asset), ) @@ -887,9 +886,9 @@ pub fn special_get_owner_v200( expected_asset_type, ) { Ok(owner) => Ok(Value::some(Value::Principal(owner)).map_err(|_| { - InterpreterError::Expect("Principal should always fit in optional.".into()) + VmInternalError::Expect("Principal should always fit in optional.".into()) })?), - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(Value::none()), + Err(VmExecutionError::Runtime(RuntimeError::NoSuchToken, _)) => Ok(Value::none()), Err(e) => Err(e), } } @@ -900,10 +899,10 @@ pub fn special_get_owner_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let asset = eval(&args[1], env, context)?; @@ -911,16 +910,16 @@ pub fn special_get_owner_v205( .contract_context .meta_nft .get(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; let expected_asset_type = &nft_metadata.key_type; let asset_size = asset .serialized_size() - .map_err(|e| InterpreterError::Expect(e.to_string()))? as u64; + .map_err(|e| VmInternalError::Expect(e.to_string()))? as u64; runtime_cost(ClarityCostFunction::NftOwner, env, asset_size)?; if !expected_asset_type.admits(env.epoch(), &asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_asset_type.clone()), Box::new(asset), ) @@ -934,9 +933,9 @@ pub fn special_get_owner_v205( expected_asset_type, ) { Ok(owner) => Ok(Value::some(Value::Principal(owner)).map_err(|_| { - InterpreterError::Expect("Principal should always fit in optional.".into()) + VmInternalError::Expect("Principal should always fit in optional.".into()) })?), - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => Ok(Value::none()), + Err(VmExecutionError::Runtime(RuntimeError::NoSuchToken, _)) => Ok(Value::none()), Err(e) => Err(e), } } @@ -945,12 +944,12 @@ pub fn special_get_token_supply( args: &[SymbolicExpression], env: &mut Environment, _context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::FtSupply, env, 0)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let supply = env .global_context @@ -963,12 +962,12 @@ pub fn special_burn_token( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::FtBurn, env, 0)?; - let token_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let token_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let amount = eval(&args[1], env, context)?; let from = eval(&args[2], env, context)?; @@ -1022,7 +1021,7 @@ pub fn special_burn_token( Ok(Value::okay_true()) } else { - Err(CheckErrors::BadBurnFTArguments.into()) + Err(CheckErrorKind::BadBurnFTArguments.into()) } } @@ -1030,12 +1029,12 @@ pub fn special_burn_asset_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::NftBurn, env, 0)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let asset = eval(&args[1], env, context)?; let sender = eval(&args[2], env, context)?; @@ -1044,7 +1043,7 @@ pub fn special_burn_asset_v200( .contract_context .meta_nft .get(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; let expected_asset_type = &nft_metadata.key_type; runtime_cost( @@ -1054,7 +1053,7 @@ pub fn special_burn_asset_v200( )?; if !expected_asset_type.admits(env.epoch(), &asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_asset_type.clone()), Box::new(asset), ) @@ -1068,7 +1067,7 @@ pub fn special_burn_asset_v200( &asset, expected_asset_type, ) { - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => { + Err(VmExecutionError::Runtime(RuntimeError::NoSuchToken, _)) => { return clarity_ecode!(BurnAssetErrorCodes::DOES_NOT_EXIST) } Ok(owner) => Ok(owner), @@ -1106,10 +1105,11 @@ pub fn special_burn_asset_v200( Ok(Value::okay_true()) } else { - Err( - CheckErrors::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(sender)) - .into(), + Err(CheckErrorKind::TypeValueError( + Box::new(TypeSignature::PrincipalType), + Box::new(sender), ) + .into()) } } @@ -1119,12 +1119,12 @@ pub fn special_burn_asset_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::NftBurn, env, 0)?; - let asset_name = args[0].match_atom().ok_or(CheckErrors::BadTokenName)?; + let asset_name = args[0].match_atom().ok_or(CheckErrorKind::BadTokenName)?; let asset = eval(&args[1], env, context)?; let sender = eval(&args[2], env, context)?; @@ -1133,16 +1133,16 @@ pub fn special_burn_asset_v205( .contract_context .meta_nft .get(asset_name) - .ok_or(CheckErrors::NoSuchNFT(asset_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchNFT(asset_name.to_string()))?; let expected_asset_type = &nft_metadata.key_type; let asset_size = asset .serialized_size() - .map_err(|e| InterpreterError::Expect(e.to_string()))? as u64; + .map_err(|e| VmInternalError::Expect(e.to_string()))? as u64; runtime_cost(ClarityCostFunction::NftBurn, env, asset_size)?; if !expected_asset_type.admits(env.epoch(), &asset)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_asset_type.clone()), Box::new(asset), ) @@ -1156,7 +1156,7 @@ pub fn special_burn_asset_v205( &asset, expected_asset_type, ) { - Err(Error::Runtime(RuntimeErrorType::NoSuchToken, _)) => { + Err(VmExecutionError::Runtime(RuntimeError::NoSuchToken, _)) => { return clarity_ecode!(BurnAssetErrorCodes::DOES_NOT_EXIST) } Ok(owner) => Ok(owner), @@ -1194,9 +1194,10 @@ pub fn special_burn_asset_v205( Ok(Value::okay_true()) } else { - Err( - CheckErrors::TypeValueError(Box::new(TypeSignature::PrincipalType), Box::new(sender)) - .into(), + Err(CheckErrorKind::TypeValueError( + Box::new(TypeSignature::PrincipalType), + Box::new(sender), ) + .into()) } } diff --git a/clarity/src/vm/functions/boolean.rs b/clarity/src/vm/functions/boolean.rs index e692b4ad71c..afcd1b88cd4 100644 --- a/clarity/src/vm/functions/boolean.rs +++ b/clarity/src/vm/functions/boolean.rs @@ -17,15 +17,15 @@ use crate::vm::contexts::{Environment, LocalContext}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; -use crate::vm::errors::{check_arguments_at_least, CheckErrors, InterpreterResult as Result}; +use crate::vm::errors::{check_arguments_at_least, CheckErrorKind, VmExecutionError}; use crate::vm::eval; use crate::vm::representations::SymbolicExpression; use crate::vm::types::{TypeSignature, Value}; -fn type_force_bool(value: &Value) -> Result { +fn type_force_bool(value: &Value) -> Result { match *value { Value::Bool(boolean) => Ok(boolean), - _ => Err(CheckErrors::TypeValueError( + _ => Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BoolType), Box::new(value.clone()), ) @@ -37,7 +37,7 @@ pub fn special_or( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; runtime_cost(ClarityCostFunction::Or, env, args.len())?; @@ -57,7 +57,7 @@ pub fn special_and( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; runtime_cost(ClarityCostFunction::And, env, args.len())?; @@ -73,7 +73,7 @@ pub fn special_and( Ok(Value::Bool(true)) } -pub fn native_not(input: Value) -> Result { +pub fn native_not(input: Value) -> Result { let value = type_force_bool(&input)?; Ok(Value::Bool(!value)) } diff --git a/clarity/src/vm/functions/conversions.rs b/clarity/src/vm/functions/conversions.rs index 12ceca6aecc..4b5438717e8 100644 --- a/clarity/src/vm/functions/conversions.rs +++ b/clarity/src/vm/functions/conversions.rs @@ -18,9 +18,7 @@ use clarity_types::types::serialization::SerializationError; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; -use crate::vm::errors::{ - check_argument_count, CheckErrors, InterpreterError, InterpreterResult as Result, -}; +use crate::vm::errors::{check_argument_count, CheckErrorKind, VmExecutionError, VmInternalError}; use crate::vm::representations::SymbolicExpression; use crate::vm::types::SequenceSubtype::BufferType; use crate::vm::types::TypeSignature::SequenceType; @@ -49,17 +47,17 @@ pub fn buff_to_int_generic( value: Value, direction: EndianDirection, conversion_fn: fn([u8; 16]) -> Value, -) -> Result { +) -> Result { match value { Value::Sequence(SequenceData::Buffer(ref sequence_data)) => { if sequence_data.len()? > BufferLength::try_from(16_u32) - .map_err(|_| InterpreterError::Expect("Failed to construct".into()))? + .map_err(|_| VmInternalError::Expect("Failed to construct".into()))? { - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32) - .map_err(|_| InterpreterError::Expect("Failed to construct".into()))?, + .map_err(|_| VmInternalError::Expect("Failed to construct".into()))?, ))), Box::new(value), ) @@ -82,10 +80,10 @@ pub fn buff_to_int_generic( Ok(value) } } - _ => Err(CheckErrors::TypeValueError( + _ => Err(CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32) - .map_err(|_| InterpreterError::Expect("Failed to construct".into()))?, + .map_err(|_| VmInternalError::Expect("Failed to construct".into()))?, ))), Box::new(value), ) @@ -93,7 +91,7 @@ pub fn buff_to_int_generic( } } -pub fn native_buff_to_int_le(value: Value) -> Result { +pub fn native_buff_to_int_le(value: Value) -> Result { fn convert_to_int_le(buffer: [u8; 16]) -> Value { let value = i128::from_le_bytes(buffer); Value::Int(value) @@ -101,7 +99,7 @@ pub fn native_buff_to_int_le(value: Value) -> Result { buff_to_int_generic(value, EndianDirection::LittleEndian, convert_to_int_le) } -pub fn native_buff_to_uint_le(value: Value) -> Result { +pub fn native_buff_to_uint_le(value: Value) -> Result { fn convert_to_uint_le(buffer: [u8; 16]) -> Value { let value = u128::from_le_bytes(buffer); Value::UInt(value) @@ -110,7 +108,7 @@ pub fn native_buff_to_uint_le(value: Value) -> Result { buff_to_int_generic(value, EndianDirection::LittleEndian, convert_to_uint_le) } -pub fn native_buff_to_int_be(value: Value) -> Result { +pub fn native_buff_to_int_be(value: Value) -> Result { fn convert_to_int_be(buffer: [u8; 16]) -> Value { let value = i128::from_be_bytes(buffer); Value::Int(value) @@ -118,7 +116,7 @@ pub fn native_buff_to_int_be(value: Value) -> Result { buff_to_int_generic(value, EndianDirection::BigEndian, convert_to_int_be) } -pub fn native_buff_to_uint_be(value: Value) -> Result { +pub fn native_buff_to_uint_be(value: Value) -> Result { fn convert_to_uint_be(buffer: [u8; 16]) -> Value { let value = u128::from_be_bytes(buffer); Value::UInt(value) @@ -132,8 +130,8 @@ pub fn native_buff_to_uint_be(value: Value) -> Result { // either a Int or UInt, depending on the desired result. pub fn native_string_to_int_generic( value: Value, - string_to_value_fn: fn(String) -> Result, -) -> Result { + string_to_value_fn: fn(String) -> Result, +) -> Result { match value { Value::Sequence(SequenceData::String(CharType::ASCII(ASCIIData { data }))) => { match String::from_utf8(data) { @@ -148,7 +146,7 @@ pub fn native_string_to_int_generic( Err(_error) => Ok(Value::none()), } } - _ => Err(CheckErrors::UnionTypeValueError( + _ => Err(CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::STRING_ASCII_MAX, TypeSignature::STRING_UTF8_MAX, @@ -159,7 +157,7 @@ pub fn native_string_to_int_generic( } } -fn safe_convert_string_to_int(raw_string: String) -> Result { +fn safe_convert_string_to_int(raw_string: String) -> Result { let possible_int = raw_string.parse::(); match possible_int { Ok(val) => Value::some(Value::Int(val)), @@ -167,11 +165,11 @@ fn safe_convert_string_to_int(raw_string: String) -> Result { } } -pub fn native_string_to_int(value: Value) -> Result { +pub fn native_string_to_int(value: Value) -> Result { native_string_to_int_generic(value, safe_convert_string_to_int) } -fn safe_convert_string_to_uint(raw_string: String) -> Result { +fn safe_convert_string_to_uint(raw_string: String) -> Result { let possible_int = raw_string.parse::(); match possible_int { Ok(val) => Value::some(Value::UInt(val)), @@ -179,7 +177,7 @@ fn safe_convert_string_to_uint(raw_string: String) -> Result { } } -pub fn native_string_to_uint(value: Value) -> Result { +pub fn native_string_to_uint(value: Value) -> Result { native_string_to_int_generic(value, safe_convert_string_to_uint) } @@ -189,22 +187,22 @@ pub fn native_string_to_uint(value: Value) -> Result { // either an ASCII or UTF8 string, depending on the desired result. pub fn native_int_to_string_generic( value: Value, - bytes_to_value_fn: fn(bytes: Vec) -> Result, -) -> Result { + bytes_to_value_fn: fn(bytes: Vec) -> Result, +) -> Result { match value { Value::Int(ref int_value) => { let as_string = int_value.to_string(); Ok(bytes_to_value_fn(as_string.into()).map_err(|_| { - InterpreterError::Expect("Unexpected error converting Int to string.".into()) + VmInternalError::Expect("Unexpected error converting Int to string.".into()) })?) } Value::UInt(ref uint_value) => { let as_string = uint_value.to_string(); Ok(bytes_to_value_fn(as_string.into()).map_err(|_| { - InterpreterError::Expect("Unexpected error converting UInt to string.".into()) + VmInternalError::Expect("Unexpected error converting UInt to string.".into()) })?) } - _ => Err(CheckErrors::UnionTypeValueError( + _ => Err(CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(value), ) @@ -212,27 +210,27 @@ pub fn native_int_to_string_generic( } } -pub fn native_int_to_ascii(value: Value) -> Result { +pub fn native_int_to_ascii(value: Value) -> Result { // Given an integer, convert this to Clarity ASCII value. native_int_to_string_generic(value, Value::string_ascii_from_bytes) } -pub fn native_int_to_utf8(value: Value) -> Result { +pub fn native_int_to_utf8(value: Value) -> Result { // Given an integer, convert this to Clarity UTF8 value. native_int_to_string_generic(value, Value::string_utf8_from_bytes) } /// Helper function to convert a string to ASCII and wrap in Ok response /// This should only fail due to system errors, not conversion failures -fn convert_string_to_ascii_ok(s: String) -> Result { +fn convert_string_to_ascii_ok(s: String) -> Result { let ascii_value = Value::string_ascii_from_bytes(s.into_bytes()).map_err(|_| { - InterpreterError::Expect("Unexpected error converting string to ASCII".into()) + VmInternalError::Expect("Unexpected error converting string to ASCII".into()) })?; Value::okay(ascii_value) } /// Helper function for UTF8 conversion that can return err u1 for non-ASCII characters -fn convert_utf8_to_ascii(s: String) -> Result { +fn convert_utf8_to_ascii(s: String) -> Result { match Value::string_ascii_from_bytes(s.into_bytes()) { Ok(ascii_value) => Value::okay(ascii_value), Err(_) => Ok(Value::err_uint(1)), // Non-ASCII characters in UTF8 @@ -243,7 +241,7 @@ pub fn special_to_ascii( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let value = eval(&args[0], env, context)?; @@ -270,7 +268,7 @@ pub fn special_to_ascii( Err(_) => Ok(Value::err_uint(1)), // Invalid UTF8 } } - _ => Err(CheckErrors::UnionTypeValueError( + _ => Err(CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -288,11 +286,11 @@ pub fn special_to_ascii( /// Returns `value` consensus serialized into a `(optional buff)` object. /// If the value cannot fit as serialized into the maximum buffer size, /// this returns `none`, otherwise, it will be `(some consensus-serialized-buffer)` -pub fn to_consensus_buff(value: Value) -> Result { +pub fn to_consensus_buff(value: Value) -> Result { let mut clar_buff_serialized = vec![]; value .serialize_write(&mut clar_buff_serialized) - .map_err(|_| InterpreterError::Expect("FATAL: failed to serialize to vec".into()))?; + .map_err(|_| VmInternalError::Expect("FATAL: failed to serialize to vec".into()))?; let clar_buff_serialized = match Value::buff_from(clar_buff_serialized) { Ok(x) => x, @@ -312,7 +310,7 @@ pub fn from_consensus_buff( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let type_arg = TypeSignature::parse_type_repr(*env.epoch(), &args[0], env)?; @@ -323,7 +321,7 @@ pub fn from_consensus_buff( let input_bytes = if let Value::Sequence(SequenceData::Buffer(buff_data)) = value { Ok(buff_data.data) } else { - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_MAX), Box::new(value), )) @@ -345,7 +343,7 @@ pub fn from_consensus_buff( ) { Ok(value) => value, Err(SerializationError::UnexpectedSerialization) => { - return Err(CheckErrors::Expects("UnexpectedSerialization".into()).into()); + return Err(CheckErrorKind::Expects("UnexpectedSerialization".into()).into()); } Err(_) => return Ok(Value::none()), }; diff --git a/clarity/src/vm/functions/crypto.rs b/clarity/src/vm/functions/crypto.rs index 9628c735e87..d3a6384e826 100644 --- a/clarity/src/vm/functions/crypto.rs +++ b/clarity/src/vm/functions/crypto.rs @@ -24,21 +24,19 @@ use stacks_common::util::secp256r1::secp256r1_verify; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; -use crate::vm::errors::{ - check_argument_count, CheckErrors, InterpreterError, InterpreterResult as Result, -}; +use crate::vm::errors::{check_argument_count, CheckErrorKind, VmExecutionError, VmInternalError}; use crate::vm::representations::SymbolicExpression; use crate::vm::types::{BuffData, SequenceData, TypeSignature, Value}; use crate::vm::{eval, ClarityVersion, Environment, LocalContext}; macro_rules! native_hash_func { ($name:ident, $module:ty) => { - pub fn $name(input: Value) -> Result { + pub fn $name(input: Value) -> Result { let bytes = match input { Value::Int(value) => Ok(value.to_le_bytes().to_vec()), Value::UInt(value) => Ok(value.to_le_bytes().to_vec()), Value::Sequence(SequenceData::Buffer(value)) => Ok(value.data), - _ => Err(CheckErrors::UnionTypeValueError( + _ => Err(CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -61,19 +59,22 @@ native_hash_func!(native_keccak256, hash::Keccak256Hash); // Note: Clarity1 had a bug in how the address is computed (issues/2619). // This method preserves the old, incorrect behavior for those running Clarity1. -fn pubkey_to_address_v1(pub_key: Secp256k1PublicKey) -> Result { +fn pubkey_to_address_v1(pub_key: Secp256k1PublicKey) -> Result { StacksAddress::from_public_keys( C32_ADDRESS_VERSION_TESTNET_SINGLESIG, &AddressHashMode::SerializeP2PKH, 1, &vec![pub_key], ) - .ok_or_else(|| InterpreterError::Expect("Failed to create address from pubkey".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to create address from pubkey".into()).into()) } // Note: Clarity1 had a bug in how the address is computed (issues/2619). // This version contains the code for Clarity2 and going forward. -fn pubkey_to_address_v2(pub_key: Secp256k1PublicKey, is_mainnet: bool) -> Result { +fn pubkey_to_address_v2( + pub_key: Secp256k1PublicKey, + is_mainnet: bool, +) -> Result { let network_byte = if is_mainnet { C32_ADDRESS_VERSION_MAINNET_SINGLESIG } else { @@ -85,14 +86,14 @@ fn pubkey_to_address_v2(pub_key: Secp256k1PublicKey, is_mainnet: bool) -> Result 1, &vec![pub_key], ) - .ok_or_else(|| InterpreterError::Expect("Failed to create address from pubkey".into()).into()) + .ok_or_else(|| VmInternalError::Expect("Failed to create address from pubkey".into()).into()) } pub fn special_principal_of( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (principal-of? (..)) // arg0 => (buff 33) check_argument_count(1, args)?; @@ -103,7 +104,7 @@ pub fn special_principal_of( let pub_key = match param0 { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() != 33 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_33), Box::new(param0), ) @@ -112,7 +113,7 @@ pub fn special_principal_of( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_33), Box::new(param0), ) @@ -130,7 +131,7 @@ pub fn special_principal_of( }; let principal = addr.into(); Ok(Value::okay(Value::Principal(principal)) - .map_err(|_| InterpreterError::Expect("Failed to construct ok".into()))?) + .map_err(|_| VmInternalError::Expect("Failed to construct ok".into()))?) } else { Ok(Value::err_uint(1)) } @@ -140,7 +141,7 @@ pub fn special_secp256k1_recover( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (secp256k1-recover? (..)) // arg0 => (buff 32), arg1 => (buff 65) check_argument_count(2, args)?; @@ -151,7 +152,7 @@ pub fn special_secp256k1_recover( let message = match param0 { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() != 32 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_32), Box::new(param0), ) @@ -160,7 +161,7 @@ pub fn special_secp256k1_recover( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_32), Box::new(param0), ) @@ -172,7 +173,7 @@ pub fn special_secp256k1_recover( let signature = match param1 { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() > 65 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_65), Box::new(param1), ) @@ -184,7 +185,7 @@ pub fn special_secp256k1_recover( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_65), Box::new(param1), ) @@ -192,12 +193,14 @@ pub fn special_secp256k1_recover( } }; - match secp256k1_recover(message, signature).map_err(|_| CheckErrors::InvalidSecp65k1Signature) { + match secp256k1_recover(message, signature) + .map_err(|_| CheckErrorKind::InvalidSecp65k1Signature) + { Ok(pubkey) => Ok(Value::okay( Value::buff_from(pubkey.to_vec()) - .map_err(|_| InterpreterError::Expect("Failed to construct buff".into()))?, + .map_err(|_| VmInternalError::Expect("Failed to construct buff".into()))?, ) - .map_err(|_| InterpreterError::Expect("Failed to construct ok".into()))?), + .map_err(|_| VmInternalError::Expect("Failed to construct ok".into()))?), _ => Ok(Value::err_uint(1)), } } @@ -206,7 +209,7 @@ pub fn special_secp256k1_verify( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (secp256k1-verify (..)) // arg0 => (buff 32), arg1 => (buff 65), arg2 => (buff 33) check_argument_count(3, args)?; @@ -217,7 +220,7 @@ pub fn special_secp256k1_verify( let message = match param0 { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() != 32 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_32), Box::new(param0), ) @@ -226,7 +229,7 @@ pub fn special_secp256k1_verify( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_32), Box::new(param0), ) @@ -238,7 +241,7 @@ pub fn special_secp256k1_verify( let signature = match param1 { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() > 65 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_65), Box::new(param1), ) @@ -253,7 +256,7 @@ pub fn special_secp256k1_verify( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_65), Box::new(param1), ) @@ -265,7 +268,7 @@ pub fn special_secp256k1_verify( let pubkey = match param2 { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() != 33 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_33), Box::new(param2), ) @@ -274,7 +277,7 @@ pub fn special_secp256k1_verify( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_33), Box::new(param2), ) @@ -291,7 +294,7 @@ pub fn special_secp256r1_verify( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (secp256r1-verify message-hash signature public-key) // message-hash: (buff 32), signature: (buff 64), public-key: (buff 33) check_argument_count(3, args)?; @@ -300,12 +303,12 @@ pub fn special_secp256r1_verify( let arg0 = args .first() - .ok_or(CheckErrors::IncorrectArgumentCount(0, 3))?; + .ok_or(CheckErrorKind::IncorrectArgumentCount(0, 3))?; let message_value = eval(arg0, env, context)?; let message = match message_value { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() != 32 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_32), Box::new(message_value), ) @@ -314,7 +317,7 @@ pub fn special_secp256r1_verify( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_32), Box::new(message_value), ) @@ -324,12 +327,12 @@ pub fn special_secp256r1_verify( let arg1 = args .get(1) - .ok_or(CheckErrors::IncorrectArgumentCount(1, 3))?; + .ok_or(CheckErrorKind::IncorrectArgumentCount(1, 3))?; let signature_value = eval(arg1, env, context)?; let signature = match signature_value { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() > 64 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_64), Box::new(signature_value), ) @@ -341,7 +344,7 @@ pub fn special_secp256r1_verify( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_64), Box::new(signature_value), ) @@ -351,12 +354,12 @@ pub fn special_secp256r1_verify( let arg2 = args .get(2) - .ok_or(CheckErrors::IncorrectArgumentCount(2, 3))?; + .ok_or(CheckErrorKind::IncorrectArgumentCount(2, 3))?; let pubkey_value = eval(arg2, env, context)?; let pubkey = match pubkey_value { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => { if data.len() != 33 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_33), Box::new(pubkey_value), ) @@ -365,7 +368,7 @@ pub fn special_secp256r1_verify( data } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_33), Box::new(pubkey_value), ) diff --git a/clarity/src/vm/functions/database.rs b/clarity/src/vm/functions/database.rs index a9e759fd806..e32624ef823 100644 --- a/clarity/src/vm/functions/database.rs +++ b/clarity/src/vm/functions/database.rs @@ -22,8 +22,8 @@ use crate::vm::callables::DefineType; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{constants as cost_constants, runtime_cost, CostTracker, MemoryConsumer}; use crate::vm::errors::{ - check_argument_count, check_arguments_at_least, CheckErrors, InterpreterError, - InterpreterResult as Result, RuntimeErrorType, + check_argument_count, check_arguments_at_least, CheckErrorKind, RuntimeError, VmExecutionError, + VmInternalError, }; use crate::vm::representations::{SymbolicExpression, SymbolicExpressionType}; use crate::vm::types::{ @@ -61,7 +61,7 @@ pub fn special_contract_call( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; // the second part of the contract_call cost (i.e., the load contract cost) @@ -69,7 +69,7 @@ pub fn special_contract_call( // is checked in callables::DefinedFunction::execute_apply. runtime_cost(ClarityCostFunction::ContractCall, env, 0)?; - let function_name = args[1].match_atom().ok_or(CheckErrors::ExpectedName)?; + let function_name = args[1].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let rest_args_slice = &args[2..]; let rest_args_len = rest_args_slice.len(); let mut rest_args = Vec::with_capacity(rest_args_len); @@ -93,7 +93,7 @@ pub fn special_contract_call( Some(trait_data) => { // Ensure that contract-call is used for inter-contract calls only if trait_data.contract_identifier == env.contract_context.contract_identifier { - return Err(CheckErrors::CircularReference(vec![trait_data + return Err(CheckErrorKind::CircularReference(vec![trait_data .contract_identifier .name .to_string()]) @@ -105,7 +105,9 @@ pub fn special_contract_call( .database .get_contract(&trait_data.contract_identifier) .map_err(|_e| { - CheckErrors::NoSuchContract(trait_data.contract_identifier.to_string()) + CheckErrorKind::NoSuchContract( + trait_data.contract_identifier.to_string(), + ) })?; let contract_context_to_check = contract_to_check.contract_context; @@ -114,7 +116,7 @@ pub fn special_contract_call( let trait_identifier = trait_data .trait_identifier .as_ref() - .ok_or(CheckErrors::ExpectedTraitIdentifier)?; + .ok_or(CheckErrorKind::ExpectedTraitIdentifier)?; // Attempt to short circuit the dynamic dispatch checks: // If the contract is explicitely implementing the trait with `impl-trait`, @@ -131,7 +133,7 @@ pub fn special_contract_call( .database .get_contract(&trait_identifier.contract_identifier) .map_err(|_e| { - CheckErrors::NoSuchContract( + CheckErrorKind::NoSuchContract( trait_identifier.contract_identifier.to_string(), ) })?; @@ -141,19 +143,19 @@ pub fn special_contract_call( // Retrieve the function that will be invoked let function_to_check = contract_context_to_check .lookup_function(function_name) - .ok_or(CheckErrors::BadTraitImplementation( + .ok_or(CheckErrorKind::BadTraitImplementation( trait_name.clone(), function_name.to_string(), ))?; // Check read/write compatibility if env.global_context.is_read_only() { - return Err(CheckErrors::TraitBasedContractCallInReadOnly.into()); + return Err(CheckErrorKind::TraitBasedContractCallInReadOnly.into()); } // Check visibility if function_to_check.define_type == DefineType::Private { - return Err(CheckErrors::NoSuchPublicFunction( + return Err(CheckErrorKind::NoSuchPublicFunction( trait_data.contract_identifier.to_string(), function_name.to_string(), ) @@ -169,9 +171,12 @@ pub fn special_contract_call( // Retrieve the expected method signature let constraining_trait = contract_context_defining_trait .lookup_trait_definition(&trait_name) - .ok_or(CheckErrors::TraitReferenceUnknown(trait_name.clone()))?; + .ok_or(CheckErrorKind::TraitReferenceUnknown(trait_name.clone()))?; let expected_sig = constraining_trait.get(function_name).ok_or( - CheckErrors::TraitMethodUnknown(trait_name, function_name.to_string()), + CheckErrorKind::TraitMethodUnknown( + trait_name, + function_name.to_string(), + ), )?; ( &trait_data.contract_identifier, @@ -179,10 +184,10 @@ pub fn special_contract_call( ) } } - _ => return Err(CheckErrors::ContractCallExpectName.into()), + _ => return Err(CheckErrorKind::ContractCallExpectName.into()), } } - _ => return Err(CheckErrors::ContractCallExpectName.into()), + _ => return Err(CheckErrorKind::ContractCallExpectName.into()), }; let contract_principal = env.contract_context.contract_identifier.clone().into(); @@ -203,14 +208,14 @@ pub fn special_contract_call( // sanitize contract-call outputs in epochs >= 2.4 let result_type = TypeSignature::type_of(&result)?; let (result, _) = Value::sanitize_value(env.epoch(), &result_type, result) - .ok_or_else(|| CheckErrors::CouldNotDetermineType)?; + .ok_or_else(|| CheckErrorKind::CouldNotDetermineType)?; // Ensure that the expected type from the trait spec admits // the type of the value returned by the dynamic dispatch. if let Some(returns_type_signature) = type_returns_constraint { let actual_returns = TypeSignature::type_of(&result)?; if !returns_type_signature.admits_type(env.epoch(), &actual_returns)? { - return Err(CheckErrors::ReturnTypesMustMatch( + return Err(CheckErrorKind::ReturnTypesMustMatch( Box::new(returns_type_signature), Box::new(actual_returns), ) @@ -225,10 +230,10 @@ pub fn special_fetch_variable_v200( args: &[SymbolicExpression], env: &mut Environment, _context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; - let var_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let var_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -236,7 +241,7 @@ pub fn special_fetch_variable_v200( .contract_context .meta_data_var .get(var_name) - .ok_or(CheckErrors::NoSuchDataVariable(var_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchDataVariable(var_name.to_string()))?; runtime_cost( ClarityCostFunction::FetchVar, @@ -256,10 +261,10 @@ pub fn special_fetch_variable_v205( args: &[SymbolicExpression], env: &mut Environment, _context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; - let var_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let var_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -267,7 +272,7 @@ pub fn special_fetch_variable_v205( .contract_context .meta_data_var .get(var_name) - .ok_or(CheckErrors::NoSuchDataVariable(var_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchDataVariable(var_name.to_string()))?; let epoch = *env.epoch(); let result = env @@ -289,16 +294,16 @@ pub fn special_set_variable_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if env.global_context.is_read_only() { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } check_argument_count(2, args)?; let value = eval(&args[1], env, context)?; - let var_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let var_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -306,7 +311,7 @@ pub fn special_set_variable_v200( .contract_context .meta_data_var .get(var_name) - .ok_or(CheckErrors::NoSuchDataVariable(var_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchDataVariable(var_name.to_string()))?; runtime_cost( ClarityCostFunction::SetVar, @@ -329,16 +334,16 @@ pub fn special_set_variable_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if env.global_context.is_read_only() { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } check_argument_count(2, args)?; let value = eval(&args[1], env, context)?; - let var_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let var_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -346,7 +351,7 @@ pub fn special_set_variable_v205( .contract_context .meta_data_var .get(var_name) - .ok_or(CheckErrors::NoSuchDataVariable(var_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchDataVariable(var_name.to_string()))?; let epoch = *env.epoch(); let result = env @@ -370,10 +375,10 @@ pub fn special_fetch_entry_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let key = eval(&args[1], env, context)?; @@ -383,7 +388,7 @@ pub fn special_fetch_entry_v200( .contract_context .meta_data_map .get(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::FetchEntry, @@ -403,10 +408,10 @@ pub fn special_fetch_entry_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let key = eval(&args[1], env, context)?; @@ -416,7 +421,7 @@ pub fn special_fetch_entry_v205( .contract_context .meta_data_map .get(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; let epoch = *env.epoch(); let result = env @@ -438,7 +443,7 @@ pub fn special_at_block( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::AtBlock, env, 0)?; @@ -446,13 +451,13 @@ pub fn special_at_block( let bhh = match eval(&args[0], env, context)? { Value::Sequence(SequenceData::Buffer(BuffData { data })) => { if data.len() != 32 { - return Err(RuntimeErrorType::BadBlockHash(data).into()); + return Err(RuntimeError::BadBlockHash(data).into()); } else { StacksBlockId::from(data.as_slice()) } } x => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_32), Box::new(x), ) @@ -471,9 +476,9 @@ pub fn special_set_entry_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if env.global_context.is_read_only() { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } check_argument_count(3, args)?; @@ -482,7 +487,7 @@ pub fn special_set_entry_v200( let value = eval(&args[2], env, context)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -490,7 +495,7 @@ pub fn special_set_entry_v200( .contract_context .meta_data_map .get(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::SetEntry, @@ -514,9 +519,9 @@ pub fn special_set_entry_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if env.global_context.is_read_only() { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } check_argument_count(3, args)?; @@ -525,7 +530,7 @@ pub fn special_set_entry_v205( let value = eval(&args[2], env, context)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -533,7 +538,7 @@ pub fn special_set_entry_v205( .contract_context .meta_data_map .get(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; let epoch = *env.epoch(); let result = env @@ -557,9 +562,9 @@ pub fn special_insert_entry_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if env.global_context.is_read_only() { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } check_argument_count(3, args)?; @@ -568,7 +573,7 @@ pub fn special_insert_entry_v200( let value = eval(&args[2], env, context)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -576,7 +581,7 @@ pub fn special_insert_entry_v200( .contract_context .meta_data_map .get(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::SetEntry, @@ -601,9 +606,9 @@ pub fn special_insert_entry_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if env.global_context.is_read_only() { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } check_argument_count(3, args)?; @@ -612,7 +617,7 @@ pub fn special_insert_entry_v205( let value = eval(&args[2], env, context)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -620,7 +625,7 @@ pub fn special_insert_entry_v205( .contract_context .meta_data_map .get(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; let epoch = *env.epoch(); let result = env @@ -644,16 +649,16 @@ pub fn special_delete_entry_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if env.global_context.is_read_only() { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } check_argument_count(2, args)?; let key = eval(&args[1], env, context)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -661,7 +666,7 @@ pub fn special_delete_entry_v200( .contract_context .meta_data_map .get(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; runtime_cost( ClarityCostFunction::SetEntry, @@ -684,16 +689,16 @@ pub fn special_delete_entry_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if env.global_context.is_read_only() { - return Err(CheckErrors::WriteAttemptedInReadOnly.into()); + return Err(CheckErrorKind::WriteAttemptedInReadOnly.into()); } check_argument_count(2, args)?; let key = eval(&args[1], env, context)?; - let map_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let map_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let contract = &env.contract_context.contract_identifier; @@ -701,7 +706,7 @@ pub fn special_delete_entry_v205( .contract_context .meta_data_map .get(map_name) - .ok_or(CheckErrors::NoSuchMap(map_name.to_string()))?; + .ok_or(CheckErrorKind::NoSuchMap(map_name.to_string()))?; let epoch = *env.epoch(); let result = env @@ -735,15 +740,15 @@ pub fn special_delete_entry_v205( /// - `block-reward` returns the block reward for the block at `block-height` /// /// # Errors: -/// - CheckErrors::IncorrectArgumentCount if there aren't 2 arguments. -/// - CheckErrors::GetStacksBlockInfoExpectPropertyName if `args[0]` isn't a ClarityName. -/// - CheckErrors::NoSuchStacksBlockInfoProperty if `args[0]` isn't a StacksBlockInfoProperty. -/// - CheckErrors::TypeValueError if `args[1]` isn't a `uint`. +/// - CheckErrorKind::IncorrectArgumentCount if there aren't 2 arguments. +/// - CheckErrorKind::GetStacksBlockInfoExpectPropertyName if `args[0]` isn't a ClarityName. +/// - CheckErrorKind::NoSuchStacksBlockInfoProperty if `args[0]` isn't a StacksBlockInfoProperty. +/// - CheckErrorKind::TypeValueError if `args[1]` isn't a `uint`. pub fn special_get_block_info( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (get-block-info? property-name block-height-uint) runtime_cost(ClarityCostFunction::BlockInfo, env, 0)?; @@ -752,18 +757,18 @@ pub fn special_get_block_info( // Handle the block property name input arg. let property_name = args[0] .match_atom() - .ok_or(CheckErrors::GetBlockInfoExpectPropertyName)?; + .ok_or(CheckErrorKind::GetBlockInfoExpectPropertyName)?; let version = env.contract_context.get_clarity_version(); let block_info_prop = BlockInfoProperty::lookup_by_name_at_version(property_name, version) - .ok_or(CheckErrors::GetBlockInfoExpectPropertyName)?; + .ok_or(CheckErrorKind::GetBlockInfoExpectPropertyName)?; // Handle the block-height input arg clause. let height_eval = eval(&args[1], env, context)?; let height_value = match height_eval { Value::UInt(result) => Ok(result), - x => Err(CheckErrors::TypeValueError( + x => Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(x), )), @@ -887,15 +892,15 @@ pub fn special_get_block_info( /// - `pox_addrs` returns the list of PoX addresses paid out at `burn_block_height` /// /// # Errors: -/// - CheckErrors::IncorrectArgumentCount if there aren't 2 arguments. -/// - CheckErrors::GetBlockInfoExpectPropertyName if `args[0]` isn't a ClarityName. -/// - CheckErrors::NoSuchBurnBlockInfoProperty if `args[0]` isn't a BurnBlockInfoProperty. -/// - CheckErrors::TypeValueError if `args[1]` isn't a `uint`. +/// - CheckErrorKind::IncorrectArgumentCount if there aren't 2 arguments. +/// - CheckErrorKind::GetBlockInfoExpectPropertyName if `args[0]` isn't a ClarityName. +/// - CheckErrorKind::NoSuchBurnBlockInfoProperty if `args[0]` isn't a BurnBlockInfoProperty. +/// - CheckErrorKind::TypeValueError if `args[1]` isn't a `uint`. pub fn special_get_burn_block_info( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { runtime_cost(ClarityCostFunction::GetBurnBlockInfo, env, 0)?; check_argument_count(2, args)?; @@ -903,10 +908,10 @@ pub fn special_get_burn_block_info( // Handle the block property name input arg. let property_name = args[0] .match_atom() - .ok_or(CheckErrors::GetBlockInfoExpectPropertyName)?; + .ok_or(CheckErrorKind::GetBlockInfoExpectPropertyName)?; let block_info_prop = BurnBlockInfoProperty::lookup_by_name(property_name).ok_or( - CheckErrors::NoSuchBurnBlockInfoProperty(property_name.to_string()), + CheckErrorKind::NoSuchBurnBlockInfoProperty(property_name.to_string()), )?; // Handle the block-height input arg clause. @@ -914,7 +919,7 @@ pub fn special_get_burn_block_info( let height_value = match height_eval { Value::UInt(result) => result, x => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(x), ) @@ -960,7 +965,7 @@ pub fn special_get_burn_block_info( env.epoch(), ) .map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "FATAL: could not convert address list to Value".into(), ) })?, @@ -968,12 +973,12 @@ pub fn special_get_burn_block_info( ("payout".into(), Value::UInt(payout)), ]) .map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "FATAL: failed to build pox addrs and payout tuple".into(), ) })?, )) - .map_err(|_| InterpreterError::Expect("FATAL: could not build Some(..)".into()))?), + .map_err(|_| VmInternalError::Expect("FATAL: could not build Some(..)".into()))?), None => Ok(Value::none()), } } @@ -988,15 +993,15 @@ pub fn special_get_burn_block_info( /// - `time` returns the block time at `block-height` /// /// # Errors: -/// - CheckErrors::IncorrectArgumentCount if there aren't 2 arguments. -/// - CheckErrors::GetStacksBlockInfoExpectPropertyName if `args[0]` isn't a ClarityName. -/// - CheckErrors::NoSuchStacksBlockInfoProperty if `args[0]` isn't a StacksBlockInfoProperty. -/// - CheckErrors::TypeValueError if `args[1]` isn't a `uint`. +/// - CheckErrorKind::IncorrectArgumentCount if there aren't 2 arguments. +/// - CheckErrorKind::GetStacksBlockInfoExpectPropertyName if `args[0]` isn't a ClarityName. +/// - CheckErrorKind::NoSuchStacksBlockInfoProperty if `args[0]` isn't a StacksBlockInfoProperty. +/// - CheckErrorKind::TypeValueError if `args[1]` isn't a `uint`. pub fn special_get_stacks_block_info( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (get-stacks-block-info? property-name block-height-uint) runtime_cost(ClarityCostFunction::BlockInfo, env, 0)?; @@ -1005,17 +1010,17 @@ pub fn special_get_stacks_block_info( // Handle the block property name input arg. let property_name = args[0] .match_atom() - .ok_or(CheckErrors::GetStacksBlockInfoExpectPropertyName)?; + .ok_or(CheckErrorKind::GetStacksBlockInfoExpectPropertyName)?; let block_info_prop = StacksBlockInfoProperty::lookup_by_name(property_name).ok_or( - CheckErrors::NoSuchStacksBlockInfoProperty(property_name.to_string()), + CheckErrorKind::NoSuchStacksBlockInfoProperty(property_name.to_string()), )?; // Handle the block-height input arg. let height_eval = eval(&args[1], env, context)?; let height_value = match height_eval { Value::UInt(result) => Ok(result), - x => Err(CheckErrors::TypeValueError( + x => Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(x), )), @@ -1070,15 +1075,15 @@ pub fn special_get_stacks_block_info( /// - `block-reward` returns the block reward for the tenure of which `block-height` is a part /// /// # Errors: -/// - CheckErrors::IncorrectArgumentCount if there aren't 2 arguments. -/// - CheckErrors::GetTenureInfoExpectPropertyName if `args[0]` isn't a ClarityName. -/// - CheckErrors::NoSuchTenureInfoProperty if `args[0]` isn't a TenureInfoProperty. -/// - CheckErrors::TypeValueError if `args[1]` isn't a `uint`. +/// - CheckErrorKind::IncorrectArgumentCount if there aren't 2 arguments. +/// - CheckErrorKind::GetTenureInfoExpectPropertyName if `args[0]` isn't a ClarityName. +/// - CheckErrorKind::NoSuchTenureInfoProperty if `args[0]` isn't a TenureInfoProperty. +/// - CheckErrorKind::TypeValueError if `args[1]` isn't a `uint`. pub fn special_get_tenure_info( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (get-tenure-info? property-name block-height-uint) runtime_cost(ClarityCostFunction::BlockInfo, env, 0)?; @@ -1087,16 +1092,16 @@ pub fn special_get_tenure_info( // Handle the block property name input arg. let property_name = args[0] .match_atom() - .ok_or(CheckErrors::GetTenureInfoExpectPropertyName)?; + .ok_or(CheckErrorKind::GetTenureInfoExpectPropertyName)?; let block_info_prop = TenureInfoProperty::lookup_by_name(property_name) - .ok_or(CheckErrors::GetTenureInfoExpectPropertyName)?; + .ok_or(CheckErrorKind::GetTenureInfoExpectPropertyName)?; // Handle the block-height input arg. let height_eval = eval(&args[1], env, context)?; let height_value = match height_eval { Value::UInt(result) => Ok(result), - x => Err(CheckErrors::TypeValueError( + x => Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(x), )), @@ -1176,11 +1181,11 @@ pub fn special_contract_hash( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; let contract_expr = args .first() - .ok_or(CheckErrors::IncorrectArgumentCount(1, 0))?; + .ok_or(CheckErrorKind::IncorrectArgumentCount(1, 0))?; let contract_value = eval(contract_expr, env, context)?; let contract_identifier = match contract_value { Value::Principal(PrincipalData::Standard(_)) => { @@ -1191,7 +1196,7 @@ pub fn special_contract_hash( _ => { // If the value is not a principal, we return a check error. return Err( - CheckErrors::ExpectedContractPrincipalValue(Box::new(contract_value)).into(), + CheckErrorKind::ExpectedContractPrincipalValue(Box::new(contract_value)).into(), ); } }; diff --git a/clarity/src/vm/functions/define.rs b/clarity/src/vm/functions/define.rs index 7fc3ba77b62..b692d584217 100644 --- a/clarity/src/vm/functions/define.rs +++ b/clarity/src/vm/functions/define.rs @@ -19,8 +19,8 @@ use std::collections::BTreeMap; use crate::vm::callables::{DefineType, DefinedFunction}; use crate::vm::contexts::{ContractContext, Environment, LocalContext}; use crate::vm::errors::{ - check_argument_count, check_arguments_at_least, CheckErrors, InterpreterResult as Result, - SyntaxBindingErrorType, + check_argument_count, check_arguments_at_least, CheckErrorKind, SyntaxBindingErrorType, + VmExecutionError, }; use crate::vm::eval; use crate::vm::representations::SymbolicExpressionType::Field; @@ -108,9 +108,12 @@ pub enum DefineResult { NoDefine, } -fn check_legal_define(name: &str, contract_context: &ContractContext) -> Result<()> { +fn check_legal_define( + name: &str, + contract_context: &ContractContext, +) -> Result<(), VmExecutionError> { if contract_context.is_name_used(name) { - Err(CheckErrors::NameAlreadyUsed(name.to_string()).into()) + Err(CheckErrorKind::NameAlreadyUsed(name.to_string()).into()) } else { Ok(()) } @@ -120,7 +123,7 @@ fn handle_define_variable( variable: &ClarityName, expression: &SymbolicExpression, env: &mut Environment, -) -> Result { +) -> Result { // is the variable name legal? check_legal_define(variable, env.contract_context)?; let context = LocalContext::new(); @@ -133,18 +136,18 @@ fn handle_define_function( expression: &SymbolicExpression, env: &mut Environment, define_type: DefineType, -) -> Result { +) -> Result { let (function_symbol, arg_symbols) = signature .split_first() - .ok_or(CheckErrors::DefineFunctionBadSignature)?; + .ok_or(CheckErrorKind::DefineFunctionBadSignature)?; let function_name = function_symbol .match_atom() - .ok_or(CheckErrors::ExpectedName)?; + .ok_or(CheckErrorKind::ExpectedName)?; check_legal_define(function_name, env.contract_context)?; - let arguments = parse_name_type_pairs::<_, CheckErrors>( + let arguments = parse_name_type_pairs::<_, CheckErrorKind>( *env.epoch(), arg_symbols, SyntaxBindingErrorType::Eval, @@ -171,7 +174,7 @@ fn handle_define_persisted_variable( value_type: &SymbolicExpression, value: &SymbolicExpression, env: &mut Environment, -) -> Result { +) -> Result { check_legal_define(variable_str, env.contract_context)?; let value_type_signature = TypeSignature::parse_type_repr(*env.epoch(), value_type, env)?; @@ -190,7 +193,7 @@ fn handle_define_nonfungible_asset( asset_name: &ClarityName, key_type: &SymbolicExpression, env: &mut Environment, -) -> Result { +) -> Result { check_legal_define(asset_name, env.contract_context)?; let key_type_signature = TypeSignature::parse_type_repr(*env.epoch(), key_type, env)?; @@ -205,7 +208,7 @@ fn handle_define_fungible_token( asset_name: &ClarityName, total_supply: Option<&SymbolicExpression>, env: &mut Environment, -) -> Result { +) -> Result { check_legal_define(asset_name, env.contract_context)?; if let Some(total_supply_expr) = total_supply { @@ -217,7 +220,7 @@ fn handle_define_fungible_token( Some(total_supply_int), )) } else { - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(total_supply_value), ) @@ -233,7 +236,7 @@ fn handle_define_map( key_type: &SymbolicExpression, value_type: &SymbolicExpression, env: &mut Environment, -) -> Result { +) -> Result { check_legal_define(map_str, env.contract_context)?; let key_type_signature = TypeSignature::parse_type_repr(*env.epoch(), key_type, env)?; @@ -250,7 +253,7 @@ fn handle_define_trait( name: &ClarityName, functions: &[SymbolicExpression], env: &mut Environment, -) -> Result { +) -> Result { check_legal_define(name, env.contract_context)?; let trait_signature = TypeSignature::parse_trait_type_repr( @@ -288,7 +291,7 @@ impl<'a> DefineFunctionsParsed<'a> { /// a define-statement, returns None if the supplied expression is not a define. pub fn try_parse( expression: &'a SymbolicExpression, - ) -> std::result::Result>, CheckErrors> { + ) -> std::result::Result>, CheckErrorKind> { let (define_type, args) = match DefineFunctions::try_parse(expression) { Some(x) => x, None => return Ok(None), @@ -296,7 +299,7 @@ impl<'a> DefineFunctionsParsed<'a> { let result = match define_type { DefineFunctions::Constant => { check_argument_count(2, args)?; - let name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; DefineFunctionsParsed::Constant { name, value: &args[1], @@ -306,7 +309,7 @@ impl<'a> DefineFunctionsParsed<'a> { check_argument_count(2, args)?; let signature = args[0] .match_list() - .ok_or(CheckErrors::DefineFunctionBadSignature)?; + .ok_or(CheckErrorKind::DefineFunctionBadSignature)?; DefineFunctionsParsed::PrivateFunction { signature, body: &args[1], @@ -316,7 +319,7 @@ impl<'a> DefineFunctionsParsed<'a> { check_argument_count(2, args)?; let signature = args[0] .match_list() - .ok_or(CheckErrors::DefineFunctionBadSignature)?; + .ok_or(CheckErrorKind::DefineFunctionBadSignature)?; DefineFunctionsParsed::ReadOnlyFunction { signature, body: &args[1], @@ -326,7 +329,7 @@ impl<'a> DefineFunctionsParsed<'a> { check_argument_count(2, args)?; let signature = args[0] .match_list() - .ok_or(CheckErrors::DefineFunctionBadSignature)?; + .ok_or(CheckErrorKind::DefineFunctionBadSignature)?; DefineFunctionsParsed::PublicFunction { signature, body: &args[1], @@ -334,7 +337,7 @@ impl<'a> DefineFunctionsParsed<'a> { } DefineFunctions::NonFungibleToken => { check_argument_count(2, args)?; - let name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; DefineFunctionsParsed::NonFungibleToken { name, nft_type: &args[1], @@ -342,7 +345,7 @@ impl<'a> DefineFunctionsParsed<'a> { } DefineFunctions::FungibleToken => { check_arguments_at_least(1, args)?; - let name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; if args.len() == 1 { DefineFunctionsParsed::UnboundedFungibleToken { name } } else if args.len() == 2 { @@ -351,12 +354,12 @@ impl<'a> DefineFunctionsParsed<'a> { max_supply: &args[1], } } else { - return Err(CheckErrors::IncorrectArgumentCount(1, args.len())); + return Err(CheckErrorKind::IncorrectArgumentCount(1, args.len())); } } DefineFunctions::Map => { check_argument_count(3, args)?; - let name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; DefineFunctionsParsed::Map { name, key_type: &args[1], @@ -365,7 +368,7 @@ impl<'a> DefineFunctionsParsed<'a> { } DefineFunctions::PersistedVariable => { check_argument_count(3, args)?; - let name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; DefineFunctionsParsed::PersistedVariable { name, data_type: &args[1], @@ -374,7 +377,7 @@ impl<'a> DefineFunctionsParsed<'a> { } DefineFunctions::Trait => { check_argument_count(2, args)?; - let name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; DefineFunctionsParsed::Trait { name, functions: &args[1..], @@ -382,13 +385,13 @@ impl<'a> DefineFunctionsParsed<'a> { } DefineFunctions::UseTrait => { check_argument_count(2, args)?; - let name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; match &args[1].expr { Field(ref field) => DefineFunctionsParsed::UseTrait { name, trait_identifier: field, }, - _ => return Err(CheckErrors::ExpectedTraitIdentifier), + _ => return Err(CheckErrorKind::ExpectedTraitIdentifier), } } DefineFunctions::ImplTrait => { @@ -397,7 +400,7 @@ impl<'a> DefineFunctionsParsed<'a> { Field(ref field) => DefineFunctionsParsed::ImplTrait { trait_identifier: field, }, - _ => return Err(CheckErrors::ExpectedTraitIdentifier), + _ => return Err(CheckErrorKind::ExpectedTraitIdentifier), } } }; @@ -408,7 +411,7 @@ impl<'a> DefineFunctionsParsed<'a> { pub fn evaluate_define( expression: &SymbolicExpression, env: &mut Environment, -) -> Result { +) -> Result { if let Some(define_type) = DefineFunctionsParsed::try_parse(expression)? { match define_type { DefineFunctionsParsed::Constant { name, value } => { diff --git a/clarity/src/vm/functions/mod.rs b/clarity/src/vm/functions/mod.rs index 37aef1e0804..7877a0dd34f 100644 --- a/clarity/src/vm/functions/mod.rs +++ b/clarity/src/vm/functions/mod.rs @@ -20,8 +20,8 @@ use crate::vm::callables::{cost_input_sized_vararg, CallableType, NativeHandle}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{constants as cost_constants, runtime_cost, CostTracker, MemoryConsumer}; use crate::vm::errors::{ - check_argument_count, check_arguments_at_least, CheckErrors, Error, - InterpreterResult as Result, ShortReturnType, SyntaxBindingError, SyntaxBindingErrorType, + check_argument_count, check_arguments_at_least, CheckErrorKind, EarlyReturnError, + SyntaxBindingError, SyntaxBindingErrorType, VmExecutionError, }; pub use crate::vm::functions::assets::stx_transfer_consolidated; use crate::vm::representations::{ClarityName, SymbolicExpression, SymbolicExpressionType}; @@ -35,7 +35,7 @@ macro_rules! switch_on_global_epoch { args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, - ) -> Result { + ) -> std::result::Result { match env.epoch() { StacksEpochId::Epoch10 => { panic!("Executing Clarity method during Epoch 1.0, before Clarity") @@ -65,7 +65,7 @@ macro_rules! switch_on_global_epoch { }; } -use super::errors::InterpreterError; +use super::errors::VmInternalError; use crate::vm::ClarityVersion; mod arithmetic; @@ -598,7 +598,7 @@ pub fn lookup_reserved_functions(name: &str, version: &ClarityVersion) -> Option } } -fn native_eq(args: Vec, env: &mut Environment) -> Result { +fn native_eq(args: Vec, env: &mut Environment) -> Result { // TODO: this currently uses the derived equality checks of Value, // however, that's probably not how we want to implement equality // checks on the ::ListTypes @@ -623,10 +623,10 @@ fn native_eq(args: Vec, env: &mut Environment) -> Result { } } -fn native_begin(mut args: Vec) -> Result { +fn native_begin(mut args: Vec) -> Result { match args.pop() { Some(v) => Ok(v), - None => Err(CheckErrors::RequiresAtLeastArguments(1, 0).into()), + None => Err(CheckErrorKind::RequiresAtLeastArguments(1, 0).into()), } } @@ -634,9 +634,9 @@ fn special_print( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { let arg = args.first().ok_or_else(|| { - InterpreterError::BadSymbolicRepresentation("Print should have an argument".into()) + VmInternalError::BadSymbolicRepresentation("Print should have an argument".into()) })?; let input = eval(arg, env, context)?; @@ -654,7 +654,7 @@ fn special_if( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::If, env, 0)?; @@ -668,7 +668,7 @@ fn special_if( eval(&args[2], env, context) } } - _ => Err(CheckErrors::TypeValueError( + _ => Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BoolType), Box::new(conditional), ) @@ -680,7 +680,7 @@ fn special_asserts( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::Asserts, env, 0)?; @@ -693,10 +693,10 @@ fn special_asserts( Ok(conditional) } else { let thrown = eval(&args[1], env, context)?; - Err(ShortReturnType::AssertionFailed(Box::new(thrown)).into()) + Err(EarlyReturnError::AssertionFailed(Box::new(thrown)).into()) } } - _ => Err(CheckErrors::TypeValueError( + _ => Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BoolType), Box::new(conditional), ) @@ -711,7 +711,7 @@ pub fn handle_binding_list( ) -> std::result::Result<(), E> where F: FnMut(&ClarityName, &SymbolicExpression) -> std::result::Result<(), E>, - E: for<'a> From<(CheckErrors, &'a SymbolicExpression)>, + E: for<'a> From<(CheckErrorKind, &'a SymbolicExpression)>, { for (i, binding) in bindings.iter().enumerate() { let binding_expression = binding.match_list().ok_or_else(|| { @@ -745,7 +745,7 @@ pub fn parse_eval_bindings( binding_error_type: SyntaxBindingErrorType, env: &mut Environment, context: &LocalContext, -) -> Result> { +) -> Result, VmExecutionError> { let mut result = Vec::with_capacity(bindings.len()); handle_binding_list(bindings, binding_error_type, |var_name, var_sexp| { eval(var_sexp, env, context).map(|value| result.push((var_name.clone(), value))) @@ -758,14 +758,14 @@ fn special_let( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (let ((x 1) (y 2)) (+ x y)) -> 3 // arg0 => binding list // arg1..n => body check_arguments_at_least(2, args)?; // parse and eval the bindings. - let bindings = args[0].match_list().ok_or(CheckErrors::BadLetSyntax)?; + let bindings = args[0].match_list().ok_or(CheckErrorKind::BadLetSyntax)?; runtime_cost(ClarityCostFunction::Let, env, bindings.len())?; @@ -775,11 +775,11 @@ fn special_let( let mut memory_use = 0; finally_drop_memory!( env, memory_use; { - handle_binding_list::<_, Error>(bindings, SyntaxBindingErrorType::Let, |binding_name, var_sexp| { + handle_binding_list::<_, VmExecutionError>(bindings, SyntaxBindingErrorType::Let, |binding_name, var_sexp| { if is_reserved(binding_name, env.contract_context.get_clarity_version()) || env.contract_context.lookup_function(binding_name).is_some() || inner_context.lookup_variable(binding_name).is_some() { - return Err(CheckErrors::NameAlreadyUsed(binding_name.clone().into()).into()) + return Err(CheckErrorKind::NameAlreadyUsed(binding_name.clone().into()).into()) } let binding_value = eval(var_sexp, env, &inner_context)?; @@ -803,7 +803,7 @@ fn special_let( last_result.replace(body_result); } // last_result should always be Some(...), because of the arg len check above. - last_result.ok_or_else(|| InterpreterError::Expect("Failed to get let result".into()).into()) + last_result.ok_or_else(|| VmInternalError::Expect("Failed to get let result".into()).into()) }) } @@ -811,7 +811,7 @@ fn special_as_contract( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (as-contract (..)) // arg0 => body check_argument_count(1, args)?; @@ -838,7 +838,7 @@ fn special_contract_of( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (contract-of (..)) // arg0 => trait check_argument_count(1, args)?; @@ -847,7 +847,7 @@ fn special_contract_of( let contract_ref = match &args[0].expr { SymbolicExpressionType::Atom(contract_ref) => contract_ref, - _ => return Err(CheckErrors::ContractOfExpectsTrait.into()), + _ => return Err(CheckErrorKind::ContractOfExpectsTrait.into()), }; let contract_identifier = match context.lookup_callable_contract(contract_ref) { @@ -856,12 +856,12 @@ fn special_contract_of( .database .get_contract(&trait_data.contract_identifier) .map_err(|_e| { - CheckErrors::NoSuchContract(trait_data.contract_identifier.to_string()) + CheckErrorKind::NoSuchContract(trait_data.contract_identifier.to_string()) })?; &trait_data.contract_identifier } - _ => return Err(CheckErrors::ContractOfExpectsTrait.into()), + _ => return Err(CheckErrorKind::ContractOfExpectsTrait.into()), }; let contract_principal = Value::Principal(PrincipalData::Contract(contract_identifier.clone())); diff --git a/clarity/src/vm/functions/options.rs b/clarity/src/vm/functions/options.rs index c47dae91ccd..d8fe8959b0f 100644 --- a/clarity/src/vm/functions/options.rs +++ b/clarity/src/vm/functions/options.rs @@ -18,14 +18,14 @@ use crate::vm::contexts::{Environment, LocalContext}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{runtime_cost, CostTracker, MemoryConsumer}; use crate::vm::errors::{ - check_arguments_at_least, CheckErrors, InterpreterError, InterpreterResult as Result, - RuntimeErrorType, ShortReturnType, + check_arguments_at_least, CheckErrorKind, EarlyReturnError, RuntimeError, VmExecutionError, + VmInternalError, }; use crate::vm::types::{CallableData, OptionalData, ResponseData, TypeSignature, Value}; use crate::vm::Value::CallableContract; use crate::vm::{self, ClarityName, ClarityVersion, SymbolicExpression}; -fn inner_unwrap(to_unwrap: Value) -> Result> { +fn inner_unwrap(to_unwrap: Value) -> Result, VmExecutionError> { let result = match to_unwrap { Value::Optional(data) => data.data.map(|data| *data), Value::Response(data) => { @@ -35,13 +35,15 @@ fn inner_unwrap(to_unwrap: Value) -> Result> { None } } - _ => return Err(CheckErrors::ExpectedOptionalOrResponseValue(Box::new(to_unwrap)).into()), + _ => { + return Err(CheckErrorKind::ExpectedOptionalOrResponseValue(Box::new(to_unwrap)).into()) + } }; Ok(result) } -fn inner_unwrap_err(to_unwrap: Value) -> Result> { +fn inner_unwrap_err(to_unwrap: Value) -> Result, VmExecutionError> { let result = match to_unwrap { Value::Response(data) => { if !data.committed { @@ -50,59 +52,59 @@ fn inner_unwrap_err(to_unwrap: Value) -> Result> { None } } - _ => return Err(CheckErrors::ExpectedResponseValue(Box::new(to_unwrap)).into()), + _ => return Err(CheckErrorKind::ExpectedResponseValue(Box::new(to_unwrap)).into()), }; Ok(result) } -pub fn native_unwrap(input: Value) -> Result { +pub fn native_unwrap(input: Value) -> Result { inner_unwrap(input).and_then(|opt_value| match opt_value { Some(v) => Ok(v), - None => Err(RuntimeErrorType::UnwrapFailure.into()), + None => Err(RuntimeError::UnwrapFailure.into()), }) } -pub fn native_unwrap_or_ret(input: Value, thrown: Value) -> Result { +pub fn native_unwrap_or_ret(input: Value, thrown: Value) -> Result { inner_unwrap(input).and_then(|opt_value| match opt_value { Some(v) => Ok(v), - None => Err(ShortReturnType::ExpectedValue(Box::new(thrown)).into()), + None => Err(EarlyReturnError::UnwrapFailed(Box::new(thrown)).into()), }) } -pub fn native_unwrap_err(input: Value) -> Result { +pub fn native_unwrap_err(input: Value) -> Result { inner_unwrap_err(input).and_then(|opt_value| match opt_value { Some(v) => Ok(v), - None => Err(RuntimeErrorType::UnwrapFailure.into()), + None => Err(RuntimeError::UnwrapFailure.into()), }) } -pub fn native_unwrap_err_or_ret(input: Value, thrown: Value) -> Result { +pub fn native_unwrap_err_or_ret(input: Value, thrown: Value) -> Result { inner_unwrap_err(input).and_then(|opt_value| match opt_value { Some(v) => Ok(v), - None => Err(ShortReturnType::ExpectedValue(Box::new(thrown)).into()), + None => Err(EarlyReturnError::UnwrapFailed(Box::new(thrown)).into()), }) } -pub fn native_try_ret(input: Value) -> Result { +pub fn native_try_ret(input: Value) -> Result { match input { Value::Optional(data) => match data.data { Some(data) => Ok(*data), - None => Err(ShortReturnType::ExpectedValue(Box::new(Value::none())).into()), + None => Err(EarlyReturnError::UnwrapFailed(Box::new(Value::none())).into()), }, Value::Response(data) => { if data.committed { Ok(*data.data) } else { let short_return_val = Value::error(*data.data).map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "BUG: Failed to construct new response type from old response type".into(), ) })?; - Err(ShortReturnType::ExpectedValue(Box::new(short_return_val)).into()) + Err(EarlyReturnError::UnwrapFailed(Box::new(short_return_val)).into()) } } - _ => Err(CheckErrors::ExpectedOptionalOrResponseValue(Box::new(input)).into()), + _ => Err(CheckErrorKind::ExpectedOptionalOrResponseValue(Box::new(input)).into()), } } @@ -112,13 +114,13 @@ fn eval_with_new_binding( bind_value: Value, env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { let mut inner_context = context.extend()?; if vm::is_reserved(&bind_name, env.contract_context.get_clarity_version()) || env.contract_context.lookup_function(&bind_name).is_some() || inner_context.lookup_variable(&bind_name).is_some() { - return Err(CheckErrors::NameAlreadyUsed(bind_name.into()).into()); + return Err(CheckErrorKind::NameAlreadyUsed(bind_name.into()).into()); } let memory_use = bind_value.get_memory_use()?; @@ -148,16 +150,18 @@ fn special_match_opt( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if args.len() != 3 { - Err(CheckErrors::BadMatchOptionSyntax(Box::new( - CheckErrors::IncorrectArgumentCount(4, args.len() + 1), + Err(CheckErrorKind::BadMatchOptionSyntax(Box::new( + CheckErrorKind::IncorrectArgumentCount(4, args.len() + 1), )))?; } let bind_name = args[0] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchOptionSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchOptionSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let some_branch = &args[1]; let none_branch = &args[2]; @@ -173,21 +177,25 @@ fn special_match_resp( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { if args.len() != 4 { - Err(CheckErrors::BadMatchResponseSyntax(Box::new( - CheckErrors::IncorrectArgumentCount(5, args.len() + 1), + Err(CheckErrorKind::BadMatchResponseSyntax(Box::new( + CheckErrorKind::IncorrectArgumentCount(5, args.len() + 1), )))?; } let ok_bind_name = args[0] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let ok_branch = &args[1]; let err_bind_name = args[2] .match_atom() - .ok_or_else(|| CheckErrors::BadMatchResponseSyntax(Box::new(CheckErrors::ExpectedName)))? + .ok_or_else(|| { + CheckErrorKind::BadMatchResponseSyntax(Box::new(CheckErrorKind::ExpectedName)) + })? .clone(); let err_branch = &args[3]; @@ -202,7 +210,7 @@ pub fn special_match( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_arguments_at_least(1, args)?; let input = vm::eval(&args[0], env, context)?; @@ -212,58 +220,58 @@ pub fn special_match( match input { Value::Response(data) => special_match_resp(data, &args[1..], env, context), Value::Optional(data) => special_match_opt(data, &args[1..], env, context), - _ => Err(CheckErrors::BadMatchInput(Box::new(TypeSignature::type_of(&input)?)).into()), + _ => Err(CheckErrorKind::BadMatchInput(Box::new(TypeSignature::type_of(&input)?)).into()), } } -pub fn native_some(input: Value) -> Result { +pub fn native_some(input: Value) -> Result { Value::some(input) } -fn is_some(input: Value) -> Result { +fn is_some(input: Value) -> Result { match input { Value::Optional(ref data) => Ok(data.data.is_some()), - _ => Err(CheckErrors::ExpectedOptionalValue(Box::new(input)).into()), + _ => Err(CheckErrorKind::ExpectedOptionalValue(Box::new(input)).into()), } } -fn is_okay(input: Value) -> Result { +fn is_okay(input: Value) -> Result { match input { Value::Response(data) => Ok(data.committed), - _ => Err(CheckErrors::ExpectedResponseValue(Box::new(input)).into()), + _ => Err(CheckErrorKind::ExpectedResponseValue(Box::new(input)).into()), } } -pub fn native_is_some(input: Value) -> Result { +pub fn native_is_some(input: Value) -> Result { is_some(input).map(Value::Bool) } -pub fn native_is_none(input: Value) -> Result { +pub fn native_is_none(input: Value) -> Result { is_some(input).map(|is_some| Value::Bool(!is_some)) } -pub fn native_is_okay(input: Value) -> Result { +pub fn native_is_okay(input: Value) -> Result { is_okay(input).map(Value::Bool) } -pub fn native_is_err(input: Value) -> Result { +pub fn native_is_err(input: Value) -> Result { is_okay(input).map(|is_ok| Value::Bool(!is_ok)) } -pub fn native_okay(input: Value) -> Result { +pub fn native_okay(input: Value) -> Result { Value::okay(input) } -pub fn native_error(input: Value) -> Result { +pub fn native_error(input: Value) -> Result { Value::error(input) } -pub fn native_default_to(default: Value, input: Value) -> Result { +pub fn native_default_to(default: Value, input: Value) -> Result { match input { Value::Optional(data) => match data.data { Some(data) => Ok(*data), None => Ok(default), }, - _ => Err(CheckErrors::ExpectedOptionalValue(Box::new(input)).into()), + _ => Err(CheckErrorKind::ExpectedOptionalValue(Box::new(input)).into()), } } diff --git a/clarity/src/vm/functions/post_conditions.rs b/clarity/src/vm/functions/post_conditions.rs index 9786b653eb5..d50638f8189 100644 --- a/clarity/src/vm/functions/post_conditions.rs +++ b/clarity/src/vm/functions/post_conditions.rs @@ -22,7 +22,7 @@ use crate::vm::contexts::AssetMap; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{constants as cost_constants, runtime_cost, CostTracker, MemoryConsumer}; use crate::vm::errors::{ - check_arguments_at_least, CheckErrors, InterpreterError, InterpreterResult, + check_arguments_at_least, CheckErrorKind, VmExecutionError, VmInternalError, }; use crate::vm::functions::NativeFunctions; use crate::vm::representations::SymbolicExpression; @@ -59,7 +59,7 @@ impl Allowance { /// Returns the size in bytes of the allowance when stored in memory. /// This is used to account for memory usage when evaluating `as-contract?` /// and `restrict-assets?` expressions. - pub fn size_in_bytes(&self) -> Result { + pub fn size_in_bytes(&self) -> Result { match self { Allowance::Stx(_) => Ok(std::mem::size_of::()), Allowance::Ft(ft) => Ok(std::mem::size_of::() @@ -74,7 +74,7 @@ impl Allowance { for id in &nft.asset_ids { let memory_use = id.get_memory_use().map_err(|e| { - InterpreterError::Expect(format!("Failed to calculate memory use: {e}")) + VmInternalError::Expect(format!("Failed to calculate memory use: {e}")) })?; total_size += memory_use as usize; } @@ -91,25 +91,27 @@ fn eval_allowance( allowance_expr: &SymbolicExpression, env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { let list = allowance_expr .match_list() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; let (name_expr, rest) = list .split_first() - .ok_or(CheckErrors::NonFunctionApplication)?; - let name = name_expr.match_atom().ok_or(CheckErrors::BadFunctionName)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; + let name = name_expr + .match_atom() + .ok_or(CheckErrorKind::BadFunctionName)?; let Some(ref native_function) = NativeFunctions::lookup_by_name_at_version( name, env.contract_context.get_clarity_version(), ) else { - return Err(CheckErrors::ExpectedAllowanceExpr(name.to_string()).into()); + return Err(CheckErrorKind::ExpectedAllowanceExpr(name.to_string()).into()); }; match native_function { NativeFunctions::AllowanceWithStx => { if rest.len() != 1 { - return Err(CheckErrors::IncorrectArgumentCount(1, rest.len()).into()); + return Err(CheckErrorKind::IncorrectArgumentCount(1, rest.len()).into()); } let amount = eval(&rest[0], env, context)?; let amount = amount.expect_u128()?; @@ -117,16 +119,17 @@ fn eval_allowance( } NativeFunctions::AllowanceWithFt => { if rest.len() != 3 { - return Err(CheckErrors::IncorrectArgumentCount(3, rest.len()).into()); + return Err(CheckErrorKind::IncorrectArgumentCount(3, rest.len()).into()); } let contract_value = eval(&rest[0], env, context)?; let contract = contract_value.clone().expect_principal()?; let contract_identifier = match contract { PrincipalData::Standard(_) => { - return Err( - CheckErrors::ExpectedContractPrincipalValue(contract_value.into()).into(), - ); + return Err(CheckErrorKind::ExpectedContractPrincipalValue( + contract_value.into(), + ) + .into()); } PrincipalData::Contract(c) => c, }; @@ -146,16 +149,17 @@ fn eval_allowance( } NativeFunctions::AllowanceWithNft => { if rest.len() != 3 { - return Err(CheckErrors::IncorrectArgumentCount(3, rest.len()).into()); + return Err(CheckErrorKind::IncorrectArgumentCount(3, rest.len()).into()); } let contract_value = eval(&rest[0], env, context)?; let contract = contract_value.clone().expect_principal()?; let contract_identifier = match contract { PrincipalData::Standard(_) => { - return Err( - CheckErrors::ExpectedContractPrincipalValue(contract_value.into()).into(), - ); + return Err(CheckErrorKind::ExpectedContractPrincipalValue( + contract_value.into(), + ) + .into()); } PrincipalData::Contract(c) => c, }; @@ -175,7 +179,7 @@ fn eval_allowance( } NativeFunctions::AllowanceWithStacking => { if rest.len() != 1 { - return Err(CheckErrors::IncorrectArgumentCount(1, rest.len()).into()); + return Err(CheckErrorKind::IncorrectArgumentCount(1, rest.len()).into()); } let amount = eval(&rest[0], env, context)?; let amount = amount.expect_u128()?; @@ -183,11 +187,11 @@ fn eval_allowance( } NativeFunctions::AllowanceAll => { if !rest.is_empty() { - return Err(CheckErrors::IncorrectArgumentCount(1, rest.len()).into()); + return Err(CheckErrorKind::IncorrectArgumentCount(1, rest.len()).into()); } Ok(Allowance::All) } - _ => Err(CheckErrors::ExpectedAllowanceExpr(name.to_string()).into()), + _ => Err(CheckErrorKind::ExpectedAllowanceExpr(name.to_string()).into()), } } @@ -196,7 +200,7 @@ pub fn special_restrict_assets( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { // (restrict-assets? asset-owner ((with-stx|with-ft|with-nft|with-stacking)*) expr-body1 expr-body2 ... expr-body-last) // arg1 => asset owner to protect // arg2 => list of asset allowances @@ -206,7 +210,7 @@ pub fn special_restrict_assets( let asset_owner_expr = &args[0]; let allowance_list = args[1] .match_list() - .ok_or(CheckErrors::ExpectedListOfAllowances( + .ok_or(CheckErrorKind::ExpectedListOfAllowances( "restrict-assets?".into(), 2, ))?; @@ -222,7 +226,7 @@ pub fn special_restrict_assets( )?; if allowance_list.len() > MAX_ALLOWANCES { - return Err(CheckErrors::TooManyAllowances(MAX_ALLOWANCES, allowance_list.len()).into()); + return Err(CheckErrorKind::TooManyAllowances(MAX_ALLOWANCES, allowance_list.len()).into()); } let mut allowances = Vec::with_capacity(allowance_list.len()); @@ -235,14 +239,15 @@ pub fn special_restrict_assets( env.global_context.begin(); // Evaluate the body expressions inside a closure so `?` only exits the closure - let eval_result: InterpreterResult> = (|| -> InterpreterResult> { - let mut last_result = None; - for expr in body_exprs { - let result = eval(expr, env, context)?; - last_result.replace(result); - } - Ok(last_result) - })(); + let eval_result: Result, VmExecutionError> = + (|| -> Result, VmExecutionError> { + let mut last_result = None; + for expr in body_exprs { + let result = eval(expr, env, context)?; + last_result.replace(result); + } + Ok(last_result) + })(); let asset_maps = env.global_context.get_readonly_asset_map()?; @@ -271,7 +276,7 @@ pub fn special_restrict_assets( } Ok(None) => { // Body had no expressions (shouldn't happen due to argument checks) - Err(InterpreterError::Expect("Failed to get body result".into()).into()) + Err(VmInternalError::Expect("Failed to get body result".into()).into()) } Err(e) => { // Runtime error inside body, pass it up @@ -285,7 +290,7 @@ pub fn special_as_contract( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> InterpreterResult { +) -> Result { // (as-contract? ((with-stx|with-ft|with-nft|with-stacking)*) expr-body1 expr-body2 ... expr-body-last) // arg1 => list of asset allowances // arg2..n => body @@ -293,7 +298,7 @@ pub fn special_as_contract( let allowance_list = args[0] .match_list() - .ok_or(CheckErrors::ExpectedListOfAllowances( + .ok_or(CheckErrorKind::ExpectedListOfAllowances( "as-contract?".into(), 1, ))?; @@ -312,7 +317,7 @@ pub fn special_as_contract( for allowance_expr in allowance_list { let allowance = eval_allowance(allowance_expr, env, context)?; let allowance_memory = u64::try_from(allowance.size_in_bytes()?) - .map_err(|_| InterpreterError::Expect("Allowance size too large".into()))?; + .map_err(|_| VmInternalError::Expect("Allowance size too large".into()))?; env.add_memory(allowance_memory)?; memory_use += allowance_memory; allowances.push(allowance); @@ -329,7 +334,7 @@ pub fn special_as_contract( nested_env.global_context.begin(); // Evaluate the body expressions inside a closure so `?` only exits the closure - let eval_result: InterpreterResult> = (|| -> InterpreterResult> { + let eval_result: Result, VmExecutionError> = (|| -> Result, VmExecutionError> { let mut last_result = None; for expr in body_exprs { let result = eval(expr, &mut nested_env, context)?; @@ -365,7 +370,7 @@ pub fn special_as_contract( } Ok(None) => { // Body had no expressions (shouldn't happen due to argument checks) - Err(InterpreterError::Expect("Failed to get body result".into()).into()) + Err(VmInternalError::Expect("Failed to get body result".into()).into()) } Err(e) => { // Runtime error inside body, pass it up @@ -383,7 +388,7 @@ fn check_allowances( owner: &PrincipalData, allowances: Vec, assets: &AssetMap, -) -> InterpreterResult> { +) -> Result, VmExecutionError> { let mut earliest_violation: Option = None; let mut record_violation = |candidate: u128| { if earliest_violation.is_none_or(|current| candidate < current) { @@ -549,6 +554,6 @@ pub fn special_allowance( _args: &[SymbolicExpression], _env: &mut Environment, _context: &LocalContext, -) -> InterpreterResult { - Err(CheckErrors::AllowanceExprNotAllowed.into()) +) -> Result { + Err(CheckErrorKind::AllowanceExprNotAllowed.into()) } diff --git a/clarity/src/vm/functions/principals.rs b/clarity/src/vm/functions/principals.rs index c2511881e70..b708ca62e8e 100644 --- a/clarity/src/vm/functions/principals.rs +++ b/clarity/src/vm/functions/principals.rs @@ -7,8 +7,8 @@ use crate::vm::contexts::GlobalContext; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; use crate::vm::errors::{ - check_argument_count, check_arguments_at_least, check_arguments_at_most, CheckErrors, - InterpreterError, InterpreterResult as Result, + check_argument_count, check_arguments_at_least, check_arguments_at_most, CheckErrorKind, + VmExecutionError, VmInternalError, }; use crate::vm::representations::{ SymbolicExpression, CONTRACT_MAX_NAME_LENGTH, CONTRACT_MIN_NAME_LENGTH, @@ -52,7 +52,7 @@ pub fn special_is_standard( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::IsStandard, env, 0)?; let owner = eval(&args[0], env, context)?; @@ -60,7 +60,7 @@ pub fn special_is_standard( let version = if let Value::Principal(ref p) = owner { p.version() } else { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::PrincipalType), Box::new(owner), ) @@ -79,7 +79,7 @@ fn create_principal_destruct_tuple( version: u8, hash_bytes: &[u8; 20], name_opt: Option, -) -> Result { +) -> Result { Ok(Value::Tuple( TupleData::from_data(vec![ ( @@ -101,7 +101,7 @@ fn create_principal_destruct_tuple( }), ), ]) - .map_err(|_| InterpreterError::Expect("FAIL: Failed to initialize tuple.".into()))?, + .map_err(|_| VmInternalError::Expect("FAIL: Failed to initialize tuple.".into()))?, )) } @@ -109,16 +109,18 @@ fn create_principal_destruct_tuple( /// /// The response is an error Response, where the `err` value is a tuple `{error_code, parse_tuple}`. /// `error_int` is of type `UInt`, `parse_tuple` is None. -fn create_principal_true_error_response(error_int: PrincipalConstructErrorCode) -> Result { +fn create_principal_true_error_response( + error_int: PrincipalConstructErrorCode, +) -> Result { Value::error(Value::Tuple( TupleData::from_data(vec![ ("error_code".into(), Value::UInt(error_int as u128)), ("value".into(), Value::none()), ]) - .map_err(|_| InterpreterError::Expect("FAIL: Failed to initialize tuple.".into()))?, + .map_err(|_| VmInternalError::Expect("FAIL: Failed to initialize tuple.".into()))?, )) .map_err(|_| { - InterpreterError::Expect("FAIL: Failed to initialize (err ..) response".into()).into() + VmInternalError::Expect("FAIL: Failed to initialize (err ..) response".into()).into() }) } @@ -130,21 +132,21 @@ fn create_principal_true_error_response(error_int: PrincipalConstructErrorCode) fn create_principal_value_error_response( error_int: PrincipalConstructErrorCode, value: Value, -) -> Result { +) -> Result { Value::error(Value::Tuple( TupleData::from_data(vec![ ("error_code".into(), Value::UInt(error_int as u128)), ( "value".into(), Value::some(value).map_err(|_| { - InterpreterError::Expect("Unexpected problem creating Value.".into()) + VmInternalError::Expect("Unexpected problem creating Value.".into()) })?, ), ]) - .map_err(|_| InterpreterError::Expect("FAIL: Failed to initialize tuple.".into()))?, + .map_err(|_| VmInternalError::Expect("FAIL: Failed to initialize tuple.".into()))?, )) .map_err(|_| { - InterpreterError::Expect("FAIL: Failed to initialize (err ..) response".into()).into() + VmInternalError::Expect("FAIL: Failed to initialize (err ..) response".into()).into() }) } @@ -152,7 +154,7 @@ pub fn special_principal_destruct( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(1, args)?; runtime_cost(ClarityCostFunction::PrincipalDestruct, env, 0)?; @@ -168,7 +170,7 @@ pub fn special_principal_destruct( (issuer.0, issuer.1, Some(name)) } _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::PrincipalType), Box::new(principal), ) @@ -191,7 +193,7 @@ pub fn special_principal_construct( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; check_arguments_at_most(3, args)?; runtime_cost(ClarityCostFunction::PrincipalConstruct, env, 0)?; @@ -210,7 +212,7 @@ pub fn special_principal_construct( _ => { return { // This is an aborting error because this should have been caught in analysis pass. - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_1), Box::new(version), ) @@ -221,7 +223,7 @@ pub fn special_principal_construct( let version_byte = if verified_version.len() > 1 { // should have been caught by the type-checker - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_1), Box::new(version), ) @@ -249,7 +251,7 @@ pub fn special_principal_construct( let verified_hash_bytes = match hash_bytes { Value::Sequence(SequenceData::Buffer(BuffData { ref data })) => data, _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_20), Box::new(hash_bytes), ) @@ -260,7 +262,7 @@ pub fn special_principal_construct( // This must have been a (buff 20). // This is an aborting error because this should have been caught in analysis pass. if verified_hash_bytes.len() > 20 { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_20), Box::new(hash_bytes), ) @@ -284,7 +286,7 @@ pub fn special_principal_construct( let name_bytes = match name { Value::Sequence(SequenceData::String(CharType::ASCII(ascii_data))) => ascii_data, _ => { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::CONTRACT_NAME_STRING_ASCII_MAX), Box::new(name), ) @@ -301,7 +303,7 @@ pub fn special_principal_construct( // if it's too long, then this should have been caught by the type-checker if name_bytes.data.len() > CONTRACT_MAX_NAME_LENGTH { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::CONTRACT_NAME_STRING_ASCII_MAX), Box::new(Value::from(name_bytes)), ) @@ -312,7 +314,7 @@ pub fn special_principal_construct( // it here at runtime. If it's not valid, then it warrants this function evaluating to // (err ..). let name_string = String::from_utf8(name_bytes.data).map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "FAIL: could not convert bytes of type (string-ascii 40) back to a UTF-8 string" .into(), ) @@ -339,7 +341,7 @@ pub fn special_principal_construct( if version_byte_is_valid { Ok(Value::okay(principal).map_err(|_| { - InterpreterError::Expect("FAIL: failed to build an (ok ..) response".into()) + VmInternalError::Expect("FAIL: failed to build an (ok ..) response".into()) })?) } else { create_principal_value_error_response(PrincipalConstructErrorCode::VERSION_BYTE, principal) diff --git a/clarity/src/vm/functions/sequences.rs b/clarity/src/vm/functions/sequences.rs index f15fb7811e5..a30ce53a410 100644 --- a/clarity/src/vm/functions/sequences.rs +++ b/clarity/src/vm/functions/sequences.rs @@ -21,8 +21,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::{runtime_cost, CostOverflowingMath}; use crate::vm::errors::{ - check_argument_count, check_arguments_at_least, CheckErrors, InterpreterResult as Result, - RuntimeErrorType, + check_argument_count, check_arguments_at_least, CheckErrorKind, RuntimeError, VmExecutionError, }; use crate::vm::representations::SymbolicExpression; use crate::vm::types::signatures::ListTypeData; @@ -34,8 +33,9 @@ pub fn list_cons( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { - let eval_tried: Result> = args.iter().map(|x| eval(x, env, context)).collect(); +) -> Result { + let eval_tried: Result, VmExecutionError> = + args.iter().map(|x| eval(x, env, context)).collect(); let args = eval_tried?; let mut arg_size = 0; @@ -52,12 +52,12 @@ pub fn special_filter( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; runtime_cost(ClarityCostFunction::Filter, env, 0)?; - let function_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let function_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let mut sequence = eval(&args[1], env, context)?; let function = lookup_function(function_name, env)?; @@ -71,7 +71,7 @@ pub fn special_filter( Ok(include) } else { Err( - CheckErrors::TypeValueError(Box::new(BoolType), Box::new(filter_eval)) + CheckErrorKind::TypeValueError(Box::new(BoolType), Box::new(filter_eval)) .into(), ) } @@ -79,7 +79,8 @@ pub fn special_filter( } _ => { return Err( - CheckErrors::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into(), + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)) + .into(), ) } }; @@ -90,12 +91,12 @@ pub fn special_fold( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; runtime_cost(ClarityCostFunction::Fold, env, 0)?; - let function_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let function_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let function = lookup_function(function_name, env)?; let mut sequence = eval(&args[1], env, context)?; @@ -113,9 +114,9 @@ pub fn special_fold( context, ) }), - _ => { - Err(CheckErrors::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into()) - } + _ => Err( + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into(), + ), } } @@ -123,12 +124,12 @@ pub fn special_map( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_arguments_at_least(2, args)?; runtime_cost(ClarityCostFunction::Map, env, args.len())?; - let function_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let function_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let function = lookup_function(function_name, env)?; // Let's consider a function f (f a b c ...) @@ -154,7 +155,7 @@ pub fn special_map( } _ => { return Err( - CheckErrors::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)) + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)) .into(), ) } @@ -184,7 +185,7 @@ pub fn special_append( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let sequence = eval(&args[0], env, context)?; @@ -210,7 +211,7 @@ pub fn special_append( TypeSignature::least_supertype(env.epoch(), &entry_type, &element_type) { let (element, _) = Value::sanitize_value(env.epoch(), &next_entry_type, element) - .ok_or_else(|| CheckErrors::ListTypesMustMatch)?; + .ok_or_else(|| CheckErrorKind::ListTypesMustMatch)?; let next_type_signature = ListTypeData::new_list(next_entry_type, size + 1)?; data.push(element); @@ -219,10 +220,10 @@ pub fn special_append( data, }))) } else { - Err(CheckErrors::TypeValueError(Box::new(entry_type), Box::new(element)).into()) + Err(CheckErrorKind::TypeValueError(Box::new(entry_type), Box::new(element)).into()) } } - _ => Err(CheckErrors::ExpectedListApplication.into()), + _ => Err(CheckErrorKind::ExpectedListApplication.into()), } } @@ -232,7 +233,7 @@ pub fn special_concat_v200( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let mut wrapped_seq = eval(&args[0], env, context)?; @@ -248,7 +249,7 @@ pub fn special_concat_v200( (Value::Sequence(ref mut seq), Value::Sequence(other_seq)) => { seq.concat(env.epoch(), other_seq) } - _ => Err(RuntimeErrorType::BadTypeConstruction.into()), + _ => Err(RuntimeError::BadTypeConstruction.into()), }?; Ok(wrapped_seq) @@ -258,7 +259,7 @@ pub fn special_concat_v205( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let mut wrapped_seq = eval(&args[0], env, context)?; @@ -276,7 +277,7 @@ pub fn special_concat_v205( } _ => { runtime_cost(ClarityCostFunction::Concat, env, 1)?; - Err(RuntimeErrorType::BadTypeConstruction.into()) + Err(RuntimeError::BadTypeConstruction.into()) } }?; @@ -287,7 +288,7 @@ pub fn special_as_max_len( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(2, args)?; let mut sequence = eval(&args[0], env, context)?; @@ -299,7 +300,7 @@ pub fn special_as_max_len( Value::Sequence(ref sequence_data) => sequence_data.len() as u128, _ => { return Err( - CheckErrors::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)) + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)) .into(), ) } @@ -314,7 +315,7 @@ pub fn special_as_max_len( } } else { let actual_len = eval(&args[1], env, context)?; - Err(CheckErrors::TypeError( + Err(CheckErrorKind::TypeError( Box::new(TypeSignature::UIntType), Box::new(TypeSignature::type_of(&actual_len)?), ) @@ -322,32 +323,32 @@ pub fn special_as_max_len( } } -pub fn native_len(sequence: Value) -> Result { +pub fn native_len(sequence: Value) -> Result { match sequence { Value::Sequence(sequence_data) => Ok(Value::UInt(sequence_data.len() as u128)), - _ => { - Err(CheckErrors::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into()) - } + _ => Err( + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into(), + ), } } -pub fn native_index_of(sequence: Value, to_find: Value) -> Result { +pub fn native_index_of(sequence: Value, to_find: Value) -> Result { if let Value::Sequence(sequence_data) = sequence { match sequence_data.contains(to_find)? { Some(index) => Value::some(Value::UInt(index as u128)), None => Ok(Value::none()), } } else { - Err(CheckErrors::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into()) + Err(CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into()) } } -pub fn native_element_at(sequence: Value, index: Value) -> Result { +pub fn native_element_at(sequence: Value, index: Value) -> Result { let sequence_data = if let Value::Sequence(sequence_data) = sequence { sequence_data } else { return Err( - CheckErrors::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into(), + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::type_of(&sequence)?)).into(), ); }; @@ -358,7 +359,7 @@ pub fn native_element_at(sequence: Value, index: Value) -> Result { return Ok(Value::none()); } } else { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(index), ) @@ -377,7 +378,7 @@ pub fn special_slice( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; let seq = eval(&args[0], env, context)?; @@ -410,7 +411,7 @@ pub fn special_slice( seq.slice(env.epoch(), left_position as usize, right_position as usize)?; Value::some(seq_value) } - _ => Err(RuntimeErrorType::BadTypeConstruction.into()), + _ => Err(RuntimeError::BadTypeConstruction.into()), } })(); @@ -427,7 +428,7 @@ pub fn special_replace_at( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { check_argument_count(3, args)?; let seq = eval(&args[0], env, context)?; @@ -439,7 +440,7 @@ pub fn special_replace_at( let expected_elem_type = if let TypeSignature::SequenceType(seq_subtype) = &seq_type { seq_subtype.unit_type() } else { - return Err(CheckErrors::ExpectedSequence(Box::new(seq_type)).into()); + return Err(CheckErrorKind::ExpectedSequence(Box::new(seq_type)).into()); }; let index_val = eval(&args[1], env, context)?; let new_element = eval(&args[2], env, context)?; @@ -447,7 +448,7 @@ pub fn special_replace_at( if expected_elem_type != TypeSignature::NoType && !expected_elem_type.admits(env.epoch(), &new_element)? { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(expected_elem_type), Box::new(new_element), ) @@ -461,7 +462,7 @@ pub fn special_replace_at( return Ok(Value::none()); } } else { - return Err(CheckErrors::TypeValueError( + return Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(index_val), ) @@ -475,6 +476,6 @@ pub fn special_replace_at( } data.replace_at(env.epoch(), index, new_element) } else { - Err(CheckErrors::ExpectedSequence(Box::new(seq_type)).into()) + Err(CheckErrorKind::ExpectedSequence(Box::new(seq_type)).into()) } } diff --git a/clarity/src/vm/functions/tuples.rs b/clarity/src/vm/functions/tuples.rs index 7db8f13959a..5fd0f2c7a77 100644 --- a/clarity/src/vm/functions/tuples.rs +++ b/clarity/src/vm/functions/tuples.rs @@ -16,8 +16,8 @@ use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; use crate::vm::errors::{ - check_argument_count, check_arguments_at_least, CheckErrors, InterpreterError, - InterpreterResult as Result, SyntaxBindingErrorType, + check_argument_count, check_arguments_at_least, CheckErrorKind, SyntaxBindingErrorType, + VmExecutionError, VmInternalError, }; use crate::vm::representations::SymbolicExpression; use crate::vm::types::{TupleData, TypeSignature, Value}; @@ -27,7 +27,7 @@ pub fn tuple_cons( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (tuple (arg-name value) // (arg-name value)) use super::parse_eval_bindings; @@ -44,12 +44,12 @@ pub fn tuple_get( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { // (get arg-name (tuple ...)) // if the tuple argument is an option type, then return option(field-name). check_argument_count(2, args)?; - let arg_name = args[0].match_atom().ok_or(CheckErrors::ExpectedName)?; + let arg_name = args[0].match_atom().ok_or(CheckErrorKind::ExpectedName)?; let value = eval(&args[1], env, context)?; @@ -60,13 +60,13 @@ pub fn tuple_get( if let Value::Tuple(tuple_data) = *data { runtime_cost(ClarityCostFunction::TupleGet, env, tuple_data.len())?; Ok(Value::some(tuple_data.get_owned(arg_name)?).map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "Tuple contents should *always* fit in a some wrapper".into(), ) })?) } else { Err( - CheckErrors::ExpectedTuple(Box::new(TypeSignature::type_of(&data)?)) + CheckErrorKind::ExpectedTuple(Box::new(TypeSignature::type_of(&data)?)) .into(), ) } @@ -78,21 +78,21 @@ pub fn tuple_get( runtime_cost(ClarityCostFunction::TupleGet, env, tuple_data.len())?; tuple_data.get_owned(arg_name) } - _ => Err(CheckErrors::ExpectedTuple(Box::new(TypeSignature::type_of(&value)?)).into()), + _ => Err(CheckErrorKind::ExpectedTuple(Box::new(TypeSignature::type_of(&value)?)).into()), } } -pub fn tuple_merge(base: Value, update: Value) -> Result { +pub fn tuple_merge(base: Value, update: Value) -> Result { let initial_values = match base { Value::Tuple(initial_values) => Ok(initial_values), - _ => Err(CheckErrors::ExpectedTuple(Box::new( + _ => Err(CheckErrorKind::ExpectedTuple(Box::new( TypeSignature::type_of(&base)?, ))), }?; let new_values = match update { Value::Tuple(new_values) => Ok(new_values), - _ => Err(CheckErrors::ExpectedTuple(Box::new( + _ => Err(CheckErrorKind::ExpectedTuple(Box::new( TypeSignature::type_of(&update)?, ))), }?; diff --git a/clarity/src/vm/mod.rs b/clarity/src/vm/mod.rs index cb13790e523..9a3799f92f8 100644 --- a/clarity/src/vm/mod.rs +++ b/clarity/src/vm/mod.rs @@ -72,9 +72,7 @@ use crate::vm::costs::{ }; // publish the non-generic StacksEpoch form for use throughout module pub use crate::vm::database::clarity_db::StacksEpoch; -use crate::vm::errors::{ - CheckErrors, Error, InterpreterError, InterpreterResult as Result, RuntimeErrorType, -}; +use crate::vm::errors::{CheckErrorKind, RuntimeError, VmExecutionError, VmInternalError}; use crate::vm::events::StacksTransactionEvent; use crate::vm::functions::define::DefineResult; pub use crate::vm::functions::stx_transfer_consolidated; @@ -155,19 +153,23 @@ pub trait EvalHook { _env: &mut Environment, _context: &LocalContext, _expr: &SymbolicExpression, - _res: &core::result::Result, + _res: &core::result::Result, ); // Called upon completion of the execution fn did_complete(&mut self, _result: core::result::Result<&mut ExecutionResult, String>); } -fn lookup_variable(name: &str, context: &LocalContext, env: &mut Environment) -> Result { +fn lookup_variable( + name: &str, + context: &LocalContext, + env: &mut Environment, +) -> Result { if name.starts_with(char::is_numeric) || name.starts_with('\'') { - Err(InterpreterError::BadSymbolicRepresentation(format!( - "Unexpected variable name: {name}" - )) - .into()) + Err( + VmInternalError::BadSymbolicRepresentation(format!("Unexpected variable name: {name}")) + .into(), + ) } else if let Some(value) = variables::lookup_reserved_variable(name, context, env)? { Ok(value) } else { @@ -183,7 +185,7 @@ fn lookup_variable(name: &str, context: &LocalContext, env: &mut Environment) -> runtime_cost(ClarityCostFunction::LookupVariableSize, env, value.size()?)?; let (value, _) = Value::sanitize_value(env.epoch(), &TypeSignature::type_of(&value)?, value) - .ok_or_else(|| CheckErrors::CouldNotDetermineType)?; + .ok_or_else(|| CheckErrorKind::CouldNotDetermineType)?; Ok(value) } else if let Some(callable_data) = context.lookup_callable_contract(name) { if env.contract_context.get_clarity_version() < &ClarityVersion::Clarity2 { @@ -192,12 +194,15 @@ fn lookup_variable(name: &str, context: &LocalContext, env: &mut Environment) -> Ok(Value::CallableContract(callable_data.clone())) } } else { - Err(CheckErrors::UndefinedVariable(name.to_string()).into()) + Err(CheckErrorKind::UndefinedVariable(name.to_string()).into()) } } } -pub fn lookup_function(name: &str, env: &mut Environment) -> Result { +pub fn lookup_function( + name: &str, + env: &mut Environment, +) -> Result { runtime_cost(ClarityCostFunction::LookupFunction, env, 0)?; if let Some(result) = @@ -208,13 +213,13 @@ pub fn lookup_function(name: &str, env: &mut Environment) -> Result, env: &Environment) { - if let Err(Error::Runtime(_, ref mut stack_trace)) = result { +fn add_stack_trace(result: &mut Result, env: &Environment) { + if let Err(VmExecutionError::Runtime(_, ref mut stack_trace)) = result { if stack_trace.is_none() { stack_trace.replace(env.call_stack.make_stack_trace()); } @@ -226,7 +231,7 @@ pub fn apply( args: &[SymbolicExpression], env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { let identifier = function.get_identifier(); // Aaron: in non-debug executions, we shouldn't track a full call-stack. // only enough to do recursion detection. @@ -234,11 +239,11 @@ pub fn apply( // do recursion check on user functions. let track_recursion = matches!(function, CallableType::UserFunction(_)); if track_recursion && env.call_stack.contains(&identifier) { - return Err(CheckErrors::CircularReference(vec![identifier.to_string()]).into()); + return Err(CheckErrorKind::CircularReference(vec![identifier.to_string()]).into()); } if env.call_stack.depth() >= MAX_CALL_STACK_DEPTH { - return Err(RuntimeErrorType::MaxStackDepthReached.into()); + return Err(RuntimeError::MaxStackDepthReached.into()); } if let CallableType::SpecialFunction(_, function) = function { @@ -266,7 +271,7 @@ pub fn apply( Err(e) => { env.drop_memory(used_memory)?; env.call_stack.decr_apply_depth(); - return Err(Error::from(e)); + return Err(VmExecutionError::from(e)); } }; used_memory += arg_value.get_memory_use()?; @@ -278,7 +283,7 @@ pub fn apply( let mut resp = match function { CallableType::NativeFunction(_, function, cost_function) => { runtime_cost(cost_function.clone(), env, evaluated_args.len()) - .map_err(Error::from) + .map_err(VmExecutionError::from) .and_then(|_| function.apply(evaluated_args, env)) } CallableType::NativeFunction205(_, function, cost_function, cost_input_handle) => { @@ -288,11 +293,11 @@ pub fn apply( evaluated_args.len() as u64 }; runtime_cost(cost_function.clone(), env, cost_input) - .map_err(Error::from) + .map_err(VmExecutionError::from) .and_then(|_| function.apply(evaluated_args, env)) } CallableType::UserFunction(function) => function.apply(&evaluated_args, env), - _ => return Err(InterpreterError::Expect("Should be unreachable.".into()).into()), + _ => return Err(VmInternalError::Expect("Should be unreachable.".into()).into()), }; add_stack_trace(&mut resp, env); env.drop_memory(used_memory)?; @@ -301,7 +306,9 @@ pub fn apply( } } -fn check_max_execution_time_expired(global_context: &GlobalContext) -> Result<()> { +fn check_max_execution_time_expired( + global_context: &GlobalContext, +) -> Result<(), VmExecutionError> { match global_context.execution_time_tracker { ExecutionTimeTracker::NoTracking => Ok(()), ExecutionTimeTracker::MaxTime { @@ -321,7 +328,7 @@ pub fn eval( exp: &SymbolicExpression, env: &mut Environment, context: &LocalContext, -) -> Result { +) -> Result { use crate::vm::representations::SymbolicExpressionType::{ Atom, AtomValue, Field, List, LiteralValue, TraitReference, }; @@ -341,16 +348,16 @@ pub fn eval( List(ref children) => { let (function_variable, rest) = children .split_first() - .ok_or(CheckErrors::NonFunctionApplication)?; + .ok_or(CheckErrorKind::NonFunctionApplication)?; let function_name = function_variable .match_atom() - .ok_or(CheckErrors::BadFunctionName)?; + .ok_or(CheckErrorKind::BadFunctionName)?; let f = lookup_function(function_name, env)?; apply(&f, rest, env, context) } TraitReference(_, _) | Field(_) => { - return Err(InterpreterError::BadSymbolicRepresentation( + return Err(VmInternalError::BadSymbolicRepresentation( "Unexpected trait reference".into(), ) .into()) @@ -380,7 +387,7 @@ pub fn eval_all( contract_context: &mut ContractContext, global_context: &mut GlobalContext, sponsor: Option, -) -> Result> { +) -> Result, VmExecutionError> { let mut last_executed = None; let context = LocalContext::new(); let mut total_memory_use = 0; @@ -414,7 +421,7 @@ pub fn eval_all( contract_context.persisted_names.insert(name.clone()); global_context.add_memory(value_type.type_size() - .map_err(|_| InterpreterError::Expect("Type size should be realizable".into()))? as u64)?; + .map_err(|_| VmInternalError::Expect("Type size should be realizable".into()))? as u64)?; global_context.add_memory(value.size()? as u64)?; @@ -430,9 +437,9 @@ pub fn eval_all( contract_context.persisted_names.insert(name.clone()); global_context.add_memory(key_type.type_size() - .map_err(|_| InterpreterError::Expect("Type size should be realizable".into()))? as u64)?; + .map_err(|_| VmInternalError::Expect("Type size should be realizable".into()))? as u64)?; global_context.add_memory(value_type.type_size() - .map_err(|_| InterpreterError::Expect("Type size should be realizable".into()))? as u64)?; + .map_err(|_| VmInternalError::Expect("Type size should be realizable".into()))? as u64)?; let data_type = global_context.database.create_map(&contract_context.contract_identifier, &name, key_type, value_type)?; @@ -443,7 +450,7 @@ pub fn eval_all( contract_context.persisted_names.insert(name.clone()); global_context.add_memory(TypeSignature::UIntType.type_size() - .map_err(|_| InterpreterError::Expect("Type size should be realizable".into()))? as u64)?; + .map_err(|_| VmInternalError::Expect("Type size should be realizable".into()))? as u64)?; let data_type = global_context.database.create_fungible_token(&contract_context.contract_identifier, &name, &total_supply)?; @@ -454,7 +461,7 @@ pub fn eval_all( contract_context.persisted_names.insert(name.clone()); global_context.add_memory(asset_type.type_size() - .map_err(|_| InterpreterError::Expect("Type size should be realizable".into()))? as u64)?; + .map_err(|_| VmInternalError::Expect("Type size should be realizable".into()))? as u64)?; let data_type = global_context.database.create_non_fungible_token(&contract_context.contract_identifier, &name, &asset_type)?; @@ -492,7 +499,10 @@ pub fn eval_all( /// This method executes the program in Epoch 2.0 *and* Epoch 2.05 and asserts /// that the result is the same before returning the result #[cfg(any(test, feature = "testing"))] -pub fn execute_on_network(program: &str, use_mainnet: bool) -> Result> { +pub fn execute_on_network( + program: &str, + use_mainnet: bool, +) -> Result, VmExecutionError> { let epoch_200_result = execute_with_parameters( program, ClarityVersion::Clarity2, @@ -524,10 +534,10 @@ pub fn execute_with_parameters_and_call_in_global_context( sender: clarity_types::types::StandardPrincipalData, mut before_function: F, mut after_function: G, -) -> Result> +) -> Result, VmExecutionError> where - F: FnMut(&mut GlobalContext) -> Result<()>, - G: FnMut(&mut GlobalContext) -> Result<()>, + F: FnMut(&mut GlobalContext) -> Result<(), VmExecutionError>, + G: FnMut(&mut GlobalContext) -> Result<(), VmExecutionError>, { use crate::vm::database::MemoryBackingStore; use crate::vm::tests::test_only_mainnet_to_chain_id; @@ -561,7 +571,7 @@ pub fn execute_with_parameters( clarity_version: ClarityVersion, epoch: StacksEpochId, use_mainnet: bool, -) -> Result> { +) -> Result, VmExecutionError> { execute_with_parameters_and_call_in_global_context( program, clarity_version, @@ -575,13 +585,16 @@ pub fn execute_with_parameters( /// Execute for test with `version`, Epoch20, testnet. #[cfg(any(test, feature = "testing"))] -pub fn execute_against_version(program: &str, version: ClarityVersion) -> Result> { +pub fn execute_against_version( + program: &str, + version: ClarityVersion, +) -> Result, VmExecutionError> { execute_with_parameters(program, version, StacksEpochId::Epoch20, false) } /// Execute for test in Clarity1, Epoch20, testnet. #[cfg(any(test, feature = "testing"))] -pub fn execute(program: &str) -> Result> { +pub fn execute(program: &str) -> Result, VmExecutionError> { execute_with_parameters( program, ClarityVersion::Clarity1, @@ -595,7 +608,7 @@ pub fn execute(program: &str) -> Result> { pub fn execute_with_limited_execution_time( program: &str, max_execution_time: std::time::Duration, -) -> Result> { +) -> Result, VmExecutionError> { execute_with_parameters_and_call_in_global_context( program, ClarityVersion::Clarity1, @@ -612,7 +625,7 @@ pub fn execute_with_limited_execution_time( /// Execute for test in Clarity2, Epoch21, testnet. #[cfg(any(test, feature = "testing"))] -pub fn execute_v2(program: &str) -> Result> { +pub fn execute_v2(program: &str) -> Result, VmExecutionError> { execute_with_parameters( program, ClarityVersion::Clarity2, diff --git a/clarity/src/vm/tests/assets.rs b/clarity/src/vm/tests/assets.rs index a6e953cd4c0..15a6522061f 100644 --- a/clarity/src/vm/tests/assets.rs +++ b/clarity/src/vm/tests/assets.rs @@ -17,7 +17,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::contexts::{AssetMap, OwnedEnvironment}; -use crate::vm::errors::Error; +use crate::vm::errors::VmExecutionError; use crate::vm::events::StacksTransactionEvent; use crate::vm::representations::SymbolicExpression; use crate::vm::tests::{test_clarity_versions, test_epochs}; @@ -25,7 +25,7 @@ use crate::vm::types::{PrincipalData, QualifiedContractIdentifier, Value}; #[cfg(test)] use crate::vm::{ contexts::AssetMapEntry, - errors::{CheckErrors, RuntimeErrorType}, + errors::{CheckErrorKind, RuntimeError}, tests::{ execute, is_committed, is_err_code, symbols_from_values, tl_env_factory as env_factory, TopLevelMemoryEnvironmentGenerator, @@ -136,7 +136,7 @@ fn execute_transaction( contract_identifier: &QualifiedContractIdentifier, tx: &str, args: &[SymbolicExpression], -) -> Result<(Value, AssetMap, Vec), Error> { +) -> Result<(Value, AssetMap, Vec), VmExecutionError> { env.execute_transaction(issuer, None, contract_identifier.clone(), tx, args) } @@ -296,7 +296,7 @@ fn test_native_stx_ops(epoch: StacksEpochId, mut env_factory: TopLevelMemoryEnvi // &symbols_from_values(vec![Value::UInt(2), p2.clone(), p1.clone()]) // ) // .unwrap_err(), - // RuntimeErrorType::ArithmeticOverflow.into() + // RuntimeError::ArithmeticOverflow.into() // ); // test 6: check balance @@ -606,7 +606,7 @@ fn test_simple_token_system( assert!(matches!( err, - Error::Unchecked(CheckErrors::TypeValueError(_, _)) + VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(_, _)) )); let (result, asset_map, _events) = execute_transaction( @@ -835,7 +835,7 @@ fn test_total_supply(epoch: StacksEpochId, mut env_factory: TopLevelMemoryEnviro .unwrap_err(); assert!(matches!( err, - Error::Unchecked(CheckErrors::TypeValueError(_, _)) + VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(_, _)) )); let err = owned_env @@ -843,7 +843,7 @@ fn test_total_supply(epoch: StacksEpochId, mut env_factory: TopLevelMemoryEnviro .unwrap_err(); assert!(matches!( err, - Error::Unchecked(CheckErrors::TypeValueError(_, _)) + VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(_, _)) )); owned_env @@ -890,7 +890,7 @@ fn test_total_supply(epoch: StacksEpochId, mut env_factory: TopLevelMemoryEnviro .unwrap_err(); println!("{err}"); assert!(match err { - Error::Runtime(RuntimeErrorType::SupplyOverflow(x, y), _) => (x, y) == (6, 5), + VmExecutionError::Runtime(RuntimeError::SupplyOverflow(x, y), _) => (x, y) == (6, 5), _ => false, }); } diff --git a/clarity/src/vm/tests/contracts.rs b/clarity/src/vm/tests/contracts.rs index 090e2872e84..225f6656e3c 100644 --- a/clarity/src/vm/tests/contracts.rs +++ b/clarity/src/vm/tests/contracts.rs @@ -26,8 +26,8 @@ use crate::vm::tests::{test_clarity_versions, test_epochs}; use crate::vm::types::{PrincipalData, QualifiedContractIdentifier, StandardPrincipalData, Value}; #[cfg(test)] use crate::vm::{ - ast::errors::ParseErrors, - errors::{CheckErrors, Error, RuntimeErrorType}, + ast::errors::ParseErrorKind, + errors::{CheckErrorKind, RuntimeError, VmExecutionError}, tests::{ env_factory, execute, is_committed, is_err_code_i128 as is_err_code, symbols_from_values, tl_env_factory, MemoryEnvironmentGenerator, TopLevelMemoryEnvironmentGenerator, @@ -114,12 +114,12 @@ fn test_get_block_info_eval( Ok(Value::none()), Ok(Value::none()), Ok(Value::none()), - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(Value::Int(-1)), ) .into()), - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::UIntType), Box::new(Value::Bool(true)), ) @@ -961,7 +961,7 @@ fn test_factorial_contract(epoch: StacksEpochId, mut env_factory: MemoryEnvironm .unwrap_err(); assert!(matches!( err_result, - Error::Unchecked(CheckErrors::NoSuchPublicFunction(_, _)) + VmExecutionError::Unchecked(CheckErrorKind::NoSuchPublicFunction(_, _)) )); let err_result = env @@ -974,7 +974,7 @@ fn test_factorial_contract(epoch: StacksEpochId, mut env_factory: MemoryEnvironm .unwrap_err(); assert!(matches!( err_result, - Error::Unchecked(CheckErrors::TypeValueError(_, _)) + VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(_, _)) )); } @@ -996,11 +996,9 @@ fn test_at_unknown_block( .unwrap_err(); eprintln!("{err}"); match err { - Error::Runtime(x, _) => assert_eq!( + VmExecutionError::Runtime(x, _) => assert_eq!( x, - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash::from( - vec![2_u8; 32].as_slice() - )) + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash::from(vec![2_u8; 32].as_slice())) ), _ => panic!("Unexpected error"), } @@ -1038,8 +1036,8 @@ fn test_ast_stack_depth() { "; assert_eq!( vm_execute(program).unwrap_err(), - RuntimeErrorType::ASTError(Box::new( - ParseErrors::VaryExpressionStackDepthTooDeep.into(), + RuntimeError::ASTError(Box::new( + ParseErrorKind::VaryExpressionStackDepthTooDeep.into(), )) .into() ); @@ -1061,7 +1059,7 @@ fn test_arg_stack_depth() { "; assert_eq!( vm_execute(program).unwrap_err(), - RuntimeErrorType::MaxStackDepthReached.into() + RuntimeError::MaxStackDepthReached.into() ); } @@ -1098,7 +1096,7 @@ fn test_cc_stack_depth( assert_eq!( env.initialize_contract(contract_identifier, contract_two) .unwrap_err(), - RuntimeErrorType::MaxStackDepthReached.into() + RuntimeError::MaxStackDepthReached.into() ); } @@ -1139,7 +1137,7 @@ fn test_cc_trait_stack_depth( assert_eq!( env.initialize_contract(contract_identifier, contract_two) .unwrap_err(), - RuntimeErrorType::MaxStackDepthReached.into() + RuntimeError::MaxStackDepthReached.into() ); } @@ -1167,7 +1165,7 @@ fn test_eval_with_non_existing_contract( ); assert_eq!( result.as_ref().unwrap_err(), - &Error::Unchecked(CheckErrors::NoSuchContract( + &VmExecutionError::Unchecked(CheckErrorKind::NoSuchContract( QualifiedContractIdentifier::local("absent") .unwrap() .to_string() @@ -1357,7 +1355,7 @@ fn test_contract_hash_type_check( .unwrap_err(); assert_eq!( err, - Error::Unchecked(CheckErrors::ExpectedContractPrincipalValue(Box::new( + VmExecutionError::Unchecked(CheckErrorKind::ExpectedContractPrincipalValue(Box::new( Value::UInt(123) ))) ); @@ -1411,6 +1409,8 @@ fn test_contract_hash_pre_clarity4( assert_eq!( err, - Error::Unchecked(CheckErrors::UndefinedFunction("contract-hash?".to_string())) + VmExecutionError::Unchecked(CheckErrorKind::UndefinedFunction( + "contract-hash?".to_string() + )) ); } diff --git a/clarity/src/vm/tests/conversions.rs b/clarity/src/vm/tests/conversions.rs index 44026e70be3..d26e4fd613a 100644 --- a/clarity/src/vm/tests/conversions.rs +++ b/clarity/src/vm/tests/conversions.rs @@ -18,7 +18,7 @@ use clarity_types::types::MAX_TO_ASCII_BUFFER_LEN; use proptest::prelude::*; use stacks_common::types::StacksEpochId; -pub use crate::vm::analysis::errors::CheckErrors; +pub use crate::vm::analysis::errors::CheckErrorKind; use crate::vm::tests::proptest_utils::{ contract_name_strategy, execute_versioned, standard_principal_strategy, to_ascii_buffer_snippet_strategy, utf8_string_ascii_only_snippet_strategy, @@ -54,14 +54,14 @@ fn test_simple_buff_to_int_le() { "(buff-to-int-le \"not-needed\" 0xfffffffffffffffffffffffffffffffe)"; assert_eq!( execute_v2(bad_wrong_number_test).unwrap_err(), - CheckErrors::IncorrectArgumentCount(1, 2).into() + CheckErrorKind::IncorrectArgumentCount(1, 2).into() ); // Right number of arguments, but wrong type. let bad_wrong_type_test = "(buff-to-int-le \"wrong-type\")"; assert_eq!( execute_v2(bad_wrong_type_test).unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap() ))), @@ -78,7 +78,7 @@ fn test_simple_buff_to_int_le() { let bad_too_large_test = "(buff-to-int-le 0x000102030405060708090a0b0c0d0e0f00)"; assert_eq!( execute_v2(bad_too_large_test).unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap() ))), @@ -112,14 +112,14 @@ fn test_simple_buff_to_uint_le() { "(buff-to-uint-le \"not-needed\" 0xfffffffffffffffffffffffffffffffe)"; assert_eq!( execute_v2(bad_wrong_number_test).unwrap_err(), - CheckErrors::IncorrectArgumentCount(1, 2).into() + CheckErrorKind::IncorrectArgumentCount(1, 2).into() ); // Right number of arguments, but wrong type. let bad_wrong_type_test = "(buff-to-uint-le \"wrong-type\")"; assert_eq!( execute_v2(bad_wrong_type_test).unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap() ))), @@ -136,7 +136,7 @@ fn test_simple_buff_to_uint_le() { let bad_too_large_test = "(buff-to-uint-le 0x000102030405060708090a0b0c0d0e0f00)"; assert_eq!( execute_v2(bad_too_large_test).unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap() ))), @@ -170,14 +170,14 @@ fn test_simple_buff_to_int_be() { "(buff-to-int-be \"not-needed\" 0xfffffffffffffffffffffffffffffffe)"; assert_eq!( execute_v2(bad_wrong_number_test).unwrap_err(), - CheckErrors::IncorrectArgumentCount(1, 2).into() + CheckErrorKind::IncorrectArgumentCount(1, 2).into() ); // Right number of arguments, but wrong type. let bad_wrong_type_test = "(buff-to-int-be \"wrong-type\")"; assert_eq!( execute_v2(bad_wrong_type_test).unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap() ))), @@ -194,7 +194,7 @@ fn test_simple_buff_to_int_be() { let bad_too_large_test = "(buff-to-int-be 0x000102030405060708090a0b0c0d0e0f00)"; assert_eq!( execute_v2(bad_too_large_test).unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap() ))), @@ -228,14 +228,14 @@ fn test_simple_buff_to_uint_be() { "(buff-to-uint-be \"not-needed\" 0xfffffffffffffffffffffffffffffffe)"; assert_eq!( execute_v2(bad_wrong_number_test).unwrap_err(), - CheckErrors::IncorrectArgumentCount(1, 2).into() + CheckErrorKind::IncorrectArgumentCount(1, 2).into() ); // Right number of arguments, but wrong type. let bad_wrong_type_test = "(buff-to-uint-be \"wrong-type\")"; assert_eq!( execute_v2(bad_wrong_type_test).unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap() ))), @@ -252,7 +252,7 @@ fn test_simple_buff_to_uint_be() { let bad_too_large_test = "(buff-to-uint-be 0x000102030405060708090a0b0c0d0e0f00)"; assert_eq!( execute_v2(bad_too_large_test).unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType( BufferLength::try_from(16_u32).unwrap() ))), @@ -312,13 +312,13 @@ fn test_simple_string_to_int() { let no_args_test = r#"(string-to-int?)"#; assert_eq!( execute_v2(no_args_test).unwrap_err(), - CheckErrors::IncorrectArgumentCount(1, 0).into() + CheckErrorKind::IncorrectArgumentCount(1, 0).into() ); let wrong_type_error_test = r#"(string-to-int? 1)"#; assert_eq!( execute_v2(wrong_type_error_test).unwrap_err(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::STRING_ASCII_MAX, TypeSignature::STRING_UTF8_MAX, @@ -377,13 +377,13 @@ fn test_simple_string_to_uint() { let no_args_test = r#"(string-to-uint?)"#; assert_eq!( execute_v2(no_args_test).unwrap_err(), - CheckErrors::IncorrectArgumentCount(1, 0).into() + CheckErrorKind::IncorrectArgumentCount(1, 0).into() ); let wrong_type_error_test = r#"(string-to-uint? 1)"#; assert_eq!( execute_v2(wrong_type_error_test).unwrap_err(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::STRING_ASCII_MAX, TypeSignature::STRING_UTF8_MAX, @@ -411,13 +411,13 @@ fn test_simple_int_to_ascii() { let no_args_test = r#"(int-to-ascii)"#; assert_eq!( execute_v2(no_args_test).unwrap_err(), - CheckErrors::IncorrectArgumentCount(1, 0).into() + CheckErrorKind::IncorrectArgumentCount(1, 0).into() ); let wrong_type_error_test = r#"(int-to-ascii "1")"#; assert_eq!( execute_v2(wrong_type_error_test).unwrap_err(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Sequence(SequenceData::String(CharType::ASCII( ASCIIData { @@ -446,13 +446,13 @@ fn test_simple_int_to_utf8() { let no_args_test = r#"(int-to-utf8)"#; assert_eq!( execute_v2(no_args_test).unwrap_err(), - CheckErrors::IncorrectArgumentCount(1, 0).into() + CheckErrorKind::IncorrectArgumentCount(1, 0).into() ); let wrong_type_error_test = r#"(int-to-utf8 "1")"#; assert_eq!( execute_v2(wrong_type_error_test).unwrap_err(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Sequence(SequenceData::String(CharType::ASCII( ASCIIData { diff --git a/clarity/src/vm/tests/crypto.rs b/clarity/src/vm/tests/crypto.rs index 9a16bc42360..05d94603208 100644 --- a/clarity/src/vm/tests/crypto.rs +++ b/clarity/src/vm/tests/crypto.rs @@ -1,3 +1,5 @@ +use clarity_types::errors::CheckErrorKind; +use clarity_types::VmExecutionError; use proptest::prelude::*; use stacks_common::types::chainstate::{StacksPrivateKey, StacksPublicKey}; use stacks_common::types::{PrivateKey, StacksEpochId}; @@ -5,7 +7,6 @@ use stacks_common::util::hash::{to_hex, Sha256Sum}; use stacks_common::util::secp256k1::MessageSignature as Secp256k1Signature; use stacks_common::util::secp256r1::{Secp256r1PrivateKey, Secp256r1PublicKey}; -use crate::vm::errors::{CheckErrors, Error}; use crate::vm::types::{ResponseData, TypeSignature, Value}; use crate::vm::{execute_with_parameters, ClarityVersion}; @@ -163,7 +164,7 @@ fn test_secp256r1_verify_signature_too_long_errors() { ) .unwrap_err(); match err { - Error::Unchecked(CheckErrors::TypeValueError(expected, _)) => { + VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(expected, _)) => { assert_eq!(*expected, TypeSignature::BUFFER_64); } _ => panic!("expected BUFFER_65 type error, found {err:?}"), @@ -313,7 +314,7 @@ fn test_secp256k1_verify_signature_too_long_errors() { ) .unwrap_err(); match err { - Error::Unchecked(CheckErrors::TypeValueError(expected, _)) => { + VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(expected, _)) => { assert_eq!(*expected, TypeSignature::BUFFER_65); } _ => panic!("expected BUFFER_65 type error, found {err:?}"), diff --git a/clarity/src/vm/tests/datamaps.rs b/clarity/src/vm/tests/datamaps.rs index 83fef9ab764..ae71745a30b 100644 --- a/clarity/src/vm/tests/datamaps.rs +++ b/clarity/src/vm/tests/datamaps.rs @@ -16,12 +16,12 @@ use crate::vm::types::{TupleData, Value}; #[cfg(test)] use crate::vm::{ - errors::{CheckErrors, ShortReturnType, SyntaxBindingError}, + errors::{CheckErrorKind, EarlyReturnError, SyntaxBindingError}, types::{ListData, SequenceData, TupleTypeSignature, TypeSignature}, }; -use crate::vm::{execute, ClarityName, Error}; +use crate::vm::{execute, ClarityName, VmExecutionError}; -fn assert_executes(expected: Result, input: &str) { +fn assert_executes(expected: Result, input: &str) { assert_eq!(expected.unwrap(), execute(input).unwrap().unwrap()); } @@ -296,7 +296,7 @@ fn test_set_response_variable() { "#; let contract_src = contract_src.to_string(); assert_eq!( - Err(ShortReturnType::ExpectedValue(Box::new(Value::Int(5))).into()), + Err(EarlyReturnError::UnwrapFailed(Box::new(Value::Int(5))).into()), execute(&contract_src) ); } @@ -474,7 +474,7 @@ fn datamap_errors() { for program in tests.iter() { assert_eq!( execute(program).unwrap_err(), - CheckErrors::NoSuchMap("non-existent".to_string()).into() + CheckErrorKind::NoSuchMap("non-existent".to_string()).into() ); } } @@ -495,7 +495,7 @@ fn lists_system_2() { matches!( execute(test), - Err(Error::Unchecked(CheckErrors::TypeError(_, _))) + Err(VmExecutionError::Unchecked(CheckErrorKind::TypeError(_, _))) ); } @@ -560,7 +560,10 @@ fn lists_system() { println!("{test:#?}"); assert!(matches!( test, - Err(Error::Unchecked(CheckErrors::TypeValueError(_, _))) + Err(VmExecutionError::Unchecked(CheckErrorKind::TypeValueError( + _, + _ + ))) )); } } @@ -623,7 +626,7 @@ fn tuples_system() { for test in type_error_tests.iter() { let expected_type_error = match execute(test) { - Err(Error::Unchecked(CheckErrors::TypeValueError(_, _))) => true, + Err(VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(_, _))) => true, _ => { println!("{:?}", execute(test)); false @@ -643,12 +646,12 @@ fn bad_define_maps() { "(define-map lists { name: int } contents 5)", "(define-map lists { name: int } { contents: (list 5 0 int) })", ]; - let expected: Vec = vec![ - CheckErrors::BadSyntaxBinding(SyntaxBindingError::tuple_cons_invalid_length(0)).into(), - CheckErrors::UnknownTypeName("contents".to_string()).into(), - CheckErrors::ExpectedName.into(), - CheckErrors::IncorrectArgumentCount(3, 4).into(), - CheckErrors::InvalidTypeDescription.into(), + let expected: Vec = vec![ + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::tuple_cons_invalid_length(0)).into(), + CheckErrorKind::UnknownTypeName("contents".to_string()).into(), + CheckErrorKind::ExpectedName.into(), + CheckErrorKind::IncorrectArgumentCount(3, 4).into(), + CheckErrorKind::InvalidTypeDescription.into(), ]; for (test, expected_err) in tests.iter().zip(expected.into_iter()) { @@ -668,15 +671,15 @@ fn bad_tuples() { "(get 1234 (tuple (name 1)))", ]; let expected = vec![ - CheckErrors::NameAlreadyUsed("name".into()), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::tuple_cons_not_list(0)), - CheckErrors::BadSyntaxBinding(SyntaxBindingError::tuple_cons_invalid_length(1)), - CheckErrors::NoSuchTupleField( + CheckErrorKind::NameAlreadyUsed("name".into()), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::tuple_cons_not_list(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::tuple_cons_invalid_length(1)), + CheckErrorKind::NoSuchTupleField( "value".into(), TupleTypeSignature::try_from(vec![("name".into(), TypeSignature::IntType)]).unwrap(), ), - CheckErrors::IncorrectArgumentCount(2, 3), - CheckErrors::ExpectedName, + CheckErrorKind::IncorrectArgumentCount(2, 3), + CheckErrorKind::ExpectedName, ]; for (test, expected_err) in tests.iter().zip(expected.into_iter()) { @@ -769,7 +772,7 @@ fn test_non_tuple_map_get_set() { for test in type_error_tests.iter() { let expected_type_error = match execute(test) { - Err(Error::Unchecked(CheckErrors::TypeValueError(_, _))) => true, + Err(VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(_, _))) => true, _ => { println!("{:?}", execute(test)); false diff --git a/clarity/src/vm/tests/defines.rs b/clarity/src/vm/tests/defines.rs index 2cd874f2c31..7ff718cae36 100644 --- a/clarity/src/vm/tests/defines.rs +++ b/clarity/src/vm/tests/defines.rs @@ -21,19 +21,19 @@ use rstest_reuse::{self, *}; #[cfg(test)] use stacks_common::types::StacksEpochId; -use crate::vm::errors::{CheckErrors, Error}; +use crate::vm::errors::{CheckErrorKind, VmExecutionError}; use crate::vm::tests::test_clarity_versions; #[cfg(test)] use crate::vm::{ analysis::errors::SyntaxBindingError, - ast::{build_ast, errors::ParseErrors}, - errors::RuntimeErrorType, + ast::{build_ast, errors::ParseErrorKind}, + errors::RuntimeError, types::{QualifiedContractIdentifier, TypeSignature, TypeSignatureExt as _, Value}, {execute, ClarityVersion}, }; -fn assert_eq_err(e1: CheckErrors, e2: Error) { - let e1: Error = e1.into(); +fn assert_eq_err(e1: CheckErrorKind, e2: VmExecutionError) { + let e1: VmExecutionError = e1.into(); assert_eq!(e1, e2) } @@ -51,7 +51,7 @@ fn test_defines() { assert_eq!( execute(tests).unwrap_err(), - CheckErrors::IncorrectArgumentCount(2, 3).into() + CheckErrorKind::IncorrectArgumentCount(2, 3).into() ); let tests = "1"; @@ -67,10 +67,10 @@ fn test_accept_options(#[case] version: ClarityVersion, #[case] epoch: StacksEpo format!("{defun} (f (some 1))"), format!("{defun} (f (some true))"), ]; - let expectations: &[Result<_, Error>] = &[ + let expectations: &[Result<_, VmExecutionError>] = &[ Ok(Some(Value::Int(0))), Ok(Some(Value::Int(10))), - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::from_string("(optional int)", version, epoch)), Box::new(Value::some(Value::Bool(true)).unwrap()), ) @@ -84,7 +84,7 @@ fn test_accept_options(#[case] version: ClarityVersion, #[case] epoch: StacksEpo let bad_defun = "(define-private (f (b (optional int int))) (* 10 (default-to 0 b)))"; assert_eq!( execute(bad_defun).unwrap_err(), - CheckErrors::InvalidTypeDescription.into() + CheckErrorKind::InvalidTypeDescription.into() ); } @@ -101,16 +101,16 @@ fn test_bad_define_names() { (+ foo foo)"; assert_eq_err( - CheckErrors::NameAlreadyUsed("tx-sender".to_string()), + CheckErrorKind::NameAlreadyUsed("tx-sender".to_string()), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::NameAlreadyUsed("*".to_string()), + CheckErrorKind::NameAlreadyUsed("*".to_string()), execute(test1).unwrap_err(), ); - assert_eq_err(CheckErrors::ExpectedName, execute(test2).unwrap_err()); + assert_eq_err(CheckErrorKind::ExpectedName, execute(test2).unwrap_err()); assert_eq_err( - CheckErrors::NameAlreadyUsed("foo".to_string()), + CheckErrorKind::NameAlreadyUsed("foo".to_string()), execute(test3).unwrap_err(), ); } @@ -126,20 +126,20 @@ fn test_unwrap_ret() { assert_eq!(Ok(Some(Value::Int(1))), execute(test0)); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 1), execute(test1).unwrap_err(), ); assert_eq_err( - CheckErrors::ExpectedOptionalOrResponseValue(Box::new(Value::Int(1))), + CheckErrorKind::ExpectedOptionalOrResponseValue(Box::new(Value::Int(1))), execute(test2).unwrap_err(), ); assert_eq_err( - CheckErrors::ExpectedResponseValue(Box::new(Value::Int(1))), + CheckErrorKind::ExpectedResponseValue(Box::new(Value::Int(1))), execute(test3).unwrap_err(), ); assert_eq!(Ok(Some(Value::Int(1))), execute(test4)); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 1), execute(test5).unwrap_err(), ); } @@ -155,15 +155,15 @@ fn test_define_read_only() { assert_eq!(Ok(Some(Value::Int(1))), execute(test0)); assert_eq_err( - CheckErrors::WriteAttemptedInReadOnly, + CheckErrorKind::WriteAttemptedInReadOnly, execute(test1).unwrap_err(), ); assert_eq_err( - CheckErrors::WriteAttemptedInReadOnly, + CheckErrorKind::WriteAttemptedInReadOnly, execute(test2).unwrap_err(), ); assert_eq_err( - CheckErrors::WriteAttemptedInReadOnly, + CheckErrorKind::WriteAttemptedInReadOnly, execute(test3).unwrap_err(), ); } @@ -187,7 +187,10 @@ fn test_stack_depth() { assert_eq!(Ok(Some(Value::Int(64))), execute(&test0)); assert!(matches!( execute(&test1), - Err(Error::Runtime(RuntimeErrorType::MaxStackDepthReached, _)) + Err(VmExecutionError::Runtime( + RuntimeError::MaxStackDepthReached, + _ + )) )) } @@ -207,25 +210,25 @@ fn test_recursive_panic(#[case] version: ClarityVersion, #[case] epoch: StacksEp epoch, ) .unwrap_err(); - assert!(matches!(*err.err, ParseErrors::CircularReference(_))); + assert!(matches!(*err.err, ParseErrorKind::CircularReference(_))); } #[test] fn test_bad_variables() { let test0 = "(+ a 1)"; - let expected = CheckErrors::UndefinedVariable("a".to_string()); + let expected = CheckErrorKind::UndefinedVariable("a".to_string()); assert_eq_err(expected, execute(test0).unwrap_err()); let test1 = "(foo 2 1)"; - let expected = CheckErrors::UndefinedFunction("foo".to_string()); + let expected = CheckErrorKind::UndefinedFunction("foo".to_string()); assert_eq_err(expected, execute(test1).unwrap_err()); let test2 = "((lambda (x y) 1) 2 1)"; - let expected = CheckErrors::BadFunctionName; + let expected = CheckErrorKind::BadFunctionName; assert_eq_err(expected, execute(test2).unwrap_err()); let test4 = "()"; - let expected = CheckErrors::NonFunctionApplication; + let expected = CheckErrorKind::NonFunctionApplication; assert_eq_err(expected, execute(test4).unwrap_err()); } @@ -249,19 +252,19 @@ fn test_variable_shadowing() { "#; assert_eq_err( - CheckErrors::NameAlreadyUsed("cursor".to_string()), + CheckErrorKind::NameAlreadyUsed("cursor".to_string()), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::NameAlreadyUsed("cursor".to_string()), + CheckErrorKind::NameAlreadyUsed("cursor".to_string()), execute(test1).unwrap_err(), ); assert_eq_err( - CheckErrors::NameAlreadyUsed("cursor".to_string()), + CheckErrorKind::NameAlreadyUsed("cursor".to_string()), execute(test2).unwrap_err(), ); assert_eq_err( - CheckErrors::NameAlreadyUsed("cursor".to_string()), + CheckErrorKind::NameAlreadyUsed("cursor".to_string()), execute(test3).unwrap_err(), ); } @@ -269,7 +272,7 @@ fn test_variable_shadowing() { #[test] fn test_define_parse_panic() { let tests = "(define-private () 1)"; - let expected = CheckErrors::DefineFunctionBadSignature; + let expected = CheckErrorKind::DefineFunctionBadSignature; assert_eq_err(expected, execute(tests).unwrap_err()); } @@ -277,7 +280,7 @@ fn test_define_parse_panic() { fn test_define_parse_panic_2() { let tests = "(define-private (a b (d)) 1)"; assert_eq_err( - CheckErrors::BadSyntaxBinding(SyntaxBindingError::eval_binding_not_list(0)), + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::eval_binding_not_list(0)), execute(tests).unwrap_err(), ); } @@ -290,16 +293,16 @@ fn test_define_constant_arg_count() { let test3 = "(define-constant foo u2 u3)"; assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 1), execute(test1).unwrap_err(), ); execute(test2).unwrap(); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), execute(test3).unwrap_err(), ); } @@ -312,16 +315,16 @@ fn test_define_private_arg_count() { let test3 = "(define-private (foo) u2 u3)"; assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 1), execute(test1).unwrap_err(), ); execute(test2).unwrap(); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), execute(test3).unwrap_err(), ); } @@ -334,16 +337,16 @@ fn test_define_public_arg_count() { let test3 = "(define-public (foo) (ok u2) u3)"; assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 1), execute(test1).unwrap_err(), ); execute(test2).unwrap(); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), execute(test3).unwrap_err(), ); } @@ -356,16 +359,16 @@ fn test_define_read_only_arg_count() { let test3 = "(define-read-only (foo) u2 u3)"; assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 1), execute(test1).unwrap_err(), ); execute(test2).unwrap(); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), execute(test3).unwrap_err(), ); } @@ -379,20 +382,20 @@ fn test_define_map_arg_count() { let test4 = "(define-map foo uint uint uint)"; assert_eq_err( - CheckErrors::IncorrectArgumentCount(3, 0), + CheckErrorKind::IncorrectArgumentCount(3, 0), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(3, 1), + CheckErrorKind::IncorrectArgumentCount(3, 1), execute(test1).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::IncorrectArgumentCount(3, 2), execute(test2).unwrap_err(), ); execute(test3).unwrap(); assert_eq_err( - CheckErrors::IncorrectArgumentCount(3, 4), + CheckErrorKind::IncorrectArgumentCount(3, 4), execute(test4).unwrap_err(), ); } @@ -406,20 +409,20 @@ fn test_define_data_var_arg_count() { let test4 = "(define-data-var foo uint u3 u4)"; assert_eq_err( - CheckErrors::IncorrectArgumentCount(3, 0), + CheckErrorKind::IncorrectArgumentCount(3, 0), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(3, 1), + CheckErrorKind::IncorrectArgumentCount(3, 1), execute(test1).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(3, 2), + CheckErrorKind::IncorrectArgumentCount(3, 2), execute(test2).unwrap_err(), ); execute(test3).unwrap(); assert_eq_err( - CheckErrors::IncorrectArgumentCount(3, 4), + CheckErrorKind::IncorrectArgumentCount(3, 4), execute(test4).unwrap_err(), ); } @@ -432,13 +435,13 @@ fn test_define_fungible_token_arg_count() { let test3 = "(define-fungible-token foo u2 u3)"; assert_eq_err( - CheckErrors::RequiresAtLeastArguments(1, 0), + CheckErrorKind::RequiresAtLeastArguments(1, 0), execute(test0).unwrap_err(), ); execute(test1).unwrap(); execute(test2).unwrap(); assert_eq_err( - CheckErrors::IncorrectArgumentCount(1, 3), + CheckErrorKind::IncorrectArgumentCount(1, 3), execute(test3).unwrap_err(), ); } @@ -451,16 +454,16 @@ fn test_define_non_fungible_token_arg_count() { let test3 = "(define-non-fungible-token foo uint uint)"; assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 0), + CheckErrorKind::IncorrectArgumentCount(2, 0), execute(test0).unwrap_err(), ); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 1), + CheckErrorKind::IncorrectArgumentCount(2, 1), execute(test1).unwrap_err(), ); execute(test2).unwrap(); assert_eq_err( - CheckErrors::IncorrectArgumentCount(2, 3), + CheckErrorKind::IncorrectArgumentCount(2, 3), execute(test3).unwrap_err(), ); } @@ -474,19 +477,19 @@ fn test_define_trait_arg_count() { // These errors are hit in the trait resolver, before reaching the type-checker match execute(test0).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) - if *parse_err.err == ParseErrors::DefineTraitBadSignature => {} + VmExecutionError::Runtime(RuntimeError::ASTError(parse_err), _) + if *parse_err.err == ParseErrorKind::DefineTraitBadSignature => {} e => panic!("{e:?}"), }; match execute(test1).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) - if *parse_err.err == ParseErrors::DefineTraitBadSignature => {} + VmExecutionError::Runtime(RuntimeError::ASTError(parse_err), _) + if *parse_err.err == ParseErrorKind::DefineTraitBadSignature => {} e => panic!("{e}"), }; execute(test2).unwrap(); match execute(test3).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) - if *parse_err.err == ParseErrors::DefineTraitBadSignature => {} + VmExecutionError::Runtime(RuntimeError::ASTError(parse_err), _) + if *parse_err.err == ParseErrorKind::DefineTraitBadSignature => {} e => panic!("{e}"), }; } @@ -500,19 +503,19 @@ fn test_use_trait_arg_count() { // These errors are hit in the trait resolver, before reaching the type-checker match execute(test0).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) - if *parse_err.err == ParseErrors::ImportTraitBadSignature => {} + VmExecutionError::Runtime(RuntimeError::ASTError(parse_err), _) + if *parse_err.err == ParseErrorKind::ImportTraitBadSignature => {} e => panic!("{e:?}"), }; match execute(test1).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) - if *parse_err.err == ParseErrors::ImportTraitBadSignature => {} + VmExecutionError::Runtime(RuntimeError::ASTError(parse_err), _) + if *parse_err.err == ParseErrorKind::ImportTraitBadSignature => {} e => panic!("{e}"), }; execute(test2).unwrap(); match execute(test3).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) - if *parse_err.err == ParseErrors::ImportTraitBadSignature => {} + VmExecutionError::Runtime(RuntimeError::ASTError(parse_err), _) + if *parse_err.err == ParseErrorKind::ImportTraitBadSignature => {} e => panic!("{e}"), }; } @@ -525,14 +528,14 @@ fn test_impl_trait_arg_count() { // These errors are hit in the trait resolver, before reaching the type-checker match execute(test0).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) - if *parse_err.err == ParseErrors::ImplTraitBadSignature => {} + VmExecutionError::Runtime(RuntimeError::ASTError(parse_err), _) + if *parse_err.err == ParseErrorKind::ImplTraitBadSignature => {} e => panic!("{e:?}"), }; execute(test1).unwrap(); match execute(test2).unwrap_err() { - Error::Runtime(RuntimeErrorType::ASTError(parse_err), _) - if *parse_err.err == ParseErrors::ImplTraitBadSignature => {} + VmExecutionError::Runtime(RuntimeError::ASTError(parse_err), _) + if *parse_err.err == ParseErrorKind::ImplTraitBadSignature => {} e => panic!("{e}"), }; } diff --git a/clarity/src/vm/tests/post_conditions.rs b/clarity/src/vm/tests/post_conditions.rs index 428edbf9426..b10943dbc63 100644 --- a/clarity/src/vm/tests/post_conditions.rs +++ b/clarity/src/vm/tests/post_conditions.rs @@ -19,7 +19,7 @@ use std::convert::TryFrom; -use clarity_types::errors::{Error as ClarityError, InterpreterResult, ShortReturnType}; +use clarity_types::errors::{EarlyReturnError, VmExecutionError}; use clarity_types::types::{ AssetIdentifier, PrincipalData, QualifiedContractIdentifier, StandardPrincipalData, }; @@ -724,7 +724,7 @@ fn test_as_contract_with_error_in_body() { )"#; let expected_err = Value::error(Value::UInt(200)).unwrap(); let short_return = - ClarityError::ShortReturn(ShortReturnType::ExpectedValue(expected_err.into())); + VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(expected_err.into())); assert_eq!(short_return, execute(snippet).unwrap_err()); } @@ -769,7 +769,7 @@ fn test_as_contract_good_transfer_with_short_return_in_body() { let sender = StandardPrincipalData::transient(); let expected_err = Value::error(Value::UInt(200)).unwrap(); let short_return = - ClarityError::ShortReturn(ShortReturnType::ExpectedValue(expected_err.into())); + VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(expected_err.into())); let res = execute(snippet).expect_err("execution passed unexpectedly"); assert_eq!(short_return, res); } @@ -778,7 +778,7 @@ fn test_as_contract_good_transfer_with_short_return_in_body() { /// `as-contract?` call, the post-condition check still checks the allowances /// and returns an error if violated. #[test] -fn test_as_contract_bad_transfer_with_short_return_ok_in_body() { +fn test_as_contract_bad_transfer_with_early_return_ok_in_body() { let snippet = r#" (let ((recipient 'SP000000000000000000002Q6VF78)) (as-contract? ((with-stx u100)) @@ -804,7 +804,7 @@ fn test_as_contract_bad_transfer_with_short_return_ok_in_body() { /// Test that when a short-return of an ok value occurs in the body of an /// `as-contract?` call, the ok value is returned. #[test] -fn test_as_contract_good_transfer_with_short_return_ok_in_body() { +fn test_as_contract_good_transfer_with_early_return_ok_in_body() { let snippet = r#" (as-contract? ((with-stx u100)) (try! (stx-transfer? u50 tx-sender 'SP000000000000000000002Q6VF78)) @@ -813,7 +813,7 @@ fn test_as_contract_good_transfer_with_short_return_ok_in_body() { )"#; let expected_err = Value::okay(Value::Bool(false)).unwrap(); let short_return = - ClarityError::ShortReturn(ShortReturnType::AssertionFailed(expected_err.into())); + VmExecutionError::EarlyReturn(EarlyReturnError::AssertionFailed(expected_err.into())); let err = execute(snippet).expect_err("execution passed unexpectedly"); assert_eq!(short_return, err); } @@ -1473,7 +1473,7 @@ fn test_restrict_assets_with_error_in_body() { )"#; let expected_err = Value::error(Value::UInt(200)).unwrap(); let short_return = - ClarityError::ShortReturn(ShortReturnType::ExpectedValue(expected_err.into())); + VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(expected_err.into())); assert_eq!(short_return, execute(snippet).unwrap_err()); } @@ -1559,7 +1559,7 @@ fn test_nested_inner_restrict_assets_with_stx_exceeds() { )"#; let expected_err = Value::error(Value::UInt(0)).unwrap(); let short_return = - ClarityError::ShortReturn(ShortReturnType::ExpectedValue(expected_err.into())); + VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(expected_err.into())); assert_eq!(short_return, execute(snippet).unwrap_err()); } @@ -1602,7 +1602,7 @@ fn test_restrict_assets_good_transfer_with_short_return_in_body() { let sender = StandardPrincipalData::transient(); let expected_err = Value::error(Value::UInt(200)).unwrap(); let short_return = - ClarityError::ShortReturn(ShortReturnType::ExpectedValue(expected_err.into())); + VmExecutionError::EarlyReturn(EarlyReturnError::UnwrapFailed(expected_err.into())); let res = execute(snippet).expect_err("execution passed unexpectedly"); assert_eq!(short_return, res); } @@ -1644,7 +1644,7 @@ fn test_restrict_assets_good_transfer_with_short_return_ok_in_body() { )"#; let expected_err = Value::okay(Value::Bool(false)).unwrap(); let short_return = - ClarityError::ShortReturn(ShortReturnType::AssertionFailed(expected_err.into())); + VmExecutionError::EarlyReturn(EarlyReturnError::AssertionFailed(expected_err.into())); let err = execute(snippet).expect_err("execution passed unexpectedly"); assert_eq!(short_return, err); } @@ -1655,7 +1655,7 @@ fn execute_with_assets_for_version( program: &str, version: ClarityVersion, sender: StandardPrincipalData, -) -> (InterpreterResult>, Option) { +) -> (Result, VmExecutionError>, Option) { let mut assets: Option = None; let result = execute_and_check_versioned(program, version, sender, |g| { diff --git a/clarity/src/vm/tests/principals.rs b/clarity/src/vm/tests/principals.rs index 86d3ad9643b..6b046250877 100644 --- a/clarity/src/vm/tests/principals.rs +++ b/clarity/src/vm/tests/principals.rs @@ -7,7 +7,7 @@ use crate::vm::types::{ }; #[cfg(test)] use crate::vm::{ - errors::CheckErrors, + errors::CheckErrorKind, functions::principals::PrincipalConstructErrorCode, types::TypeSignature::PrincipalType, types::{ResponseData, TypeSignature}, @@ -25,7 +25,7 @@ fn test_simple_is_standard_check_inputs() { true ) .unwrap_err(), - CheckErrors::TypeValueError(Box::new(PrincipalType), Box::new(Value::UInt(10)),).into() + CheckErrorKind::TypeValueError(Box::new(PrincipalType), Box::new(Value::UInt(10)),).into() ); } @@ -898,14 +898,14 @@ fn test_principal_construct_version_byte_future() { } #[test] -// Test cases where the wrong type should be a `CheckErrors` error, because it should have been +// Test cases where the wrong type should be a `CheckErrorKind` error, because it should have been // caught by the type checker. fn test_principal_construct_check_errors() { // The version bytes 0x5904934 are invalid. Should have been caught by type checker so use - // `CheckErrors`. + // `CheckErrorKind`. let input = r#"(principal-construct? 0x590493 0x0102030405060708091011121314151617181920)"#; assert_eq!( - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_1), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("590493").unwrap() @@ -921,10 +921,10 @@ fn test_principal_construct_check_errors() { ); // u22 is not a byte buffer, so is invalid. Should have been caught by type checker so use - // `CheckErrors`. + // `CheckErrorKind`. let input = r#"(principal-construct? u22 0x0102030405060708091011121314151617181920)"#; assert_eq!( - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_1), Box::new(Value::UInt(22)), ) @@ -937,7 +937,7 @@ fn test_principal_construct_check_errors() { ) ); - // Hash key part is too large, should have length 20. This is a `CheckErrors` error because it + // Hash key part is too large, should have length 20. This is a `CheckErrorKind` error because it // should have been caught by the type checker. let input = r#"(principal-construct? 0x16 0x010203040506070809101112131415161718192021)"#; assert_eq!( @@ -948,7 +948,7 @@ fn test_principal_construct_check_errors() { false ) .unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_20), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("010203040506070809101112131415161718192021").unwrap() @@ -960,7 +960,7 @@ fn test_principal_construct_check_errors() { // Name is too long, which should have been caught by the type-checker let input = r#"(principal-construct? 0x16 0x0102030405060708091011121314151617181920 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")"#; assert_eq!( - Err(CheckErrors::TypeValueError( + Err(CheckErrorKind::TypeValueError( Box::new(TypeSignature::CONTRACT_NAME_STRING_ASCII_MAX), Box::new(Value::Sequence(SequenceData::String(CharType::ASCII( ASCIIData { diff --git a/clarity/src/vm/tests/proptest_utils.rs b/clarity/src/vm/tests/proptest_utils.rs index f7eca62c14b..c4ccfee7876 100644 --- a/clarity/src/vm/tests/proptest_utils.rs +++ b/clarity/src/vm/tests/proptest_utils.rs @@ -19,7 +19,7 @@ use std::collections::BTreeSet; use std::result::Result; -use clarity_types::errors::InterpreterResult; +use clarity_types::errors::VmExecutionError; use clarity_types::types::{ CharType, PrincipalData, QualifiedContractIdentifier, SequenceData, StandardPrincipalData, TypeSignature, UTF8Data, MAX_TO_ASCII_BUFFER_LEN, MAX_UTF8_VALUE_SIZE, MAX_VALUE_SIZE, @@ -39,7 +39,6 @@ use crate::vm::analysis::type_checker::v2_1::natives::post_conditions::{ }; use crate::vm::contexts::GlobalContext; use crate::vm::database::STXBalance; -use crate::vm::errors::Error as VmError; use crate::vm::{execute_with_parameters_and_call_in_global_context, ClarityVersion}; const DEFAULT_EPOCH: StacksEpochId = StacksEpochId::Epoch33; @@ -51,7 +50,7 @@ const UTF8_SIMPLE_ESCAPES: [&str; 6] = ["\\\"", "\\\\", "\\n", "\\t", "\\r", "\\ fn initialize_balances( g: &mut GlobalContext, sender: &StandardPrincipalData, -) -> Result<(), VmError> { +) -> Result<(), VmExecutionError> { let sender_principal = PrincipalData::Standard(sender.clone()); let contract_principal = PrincipalData::Contract(QualifiedContractIdentifier::new( sender.clone(), @@ -81,7 +80,7 @@ fn initialize_balances( /// Execute a Clarity code snippet in a fresh global context with default /// parameters, setting up initial balances. -pub fn execute(snippet: &str) -> InterpreterResult> { +pub fn execute(snippet: &str) -> Result, VmExecutionError> { execute_versioned(snippet, DEFAULT_CLARITY_VERSION) } @@ -90,7 +89,7 @@ pub fn execute(snippet: &str) -> InterpreterResult> { pub fn execute_versioned( snippet: &str, version: ClarityVersion, -) -> InterpreterResult> { +) -> Result, VmExecutionError> { let sender_pk = StacksPrivateKey::random(); let sender: StandardPrincipalData = (&sender_pk).into(); let contract_id = QualifiedContractIdentifier::new(sender.clone(), "contract".into()); @@ -113,9 +112,9 @@ pub fn execute_and_check( snippet: &str, sender: StandardPrincipalData, check: F, -) -> InterpreterResult> +) -> Result, VmExecutionError> where - F: FnMut(&mut GlobalContext) -> InterpreterResult<()>, + F: FnMut(&mut GlobalContext) -> Result<(), VmExecutionError>, { execute_and_check_versioned(snippet, DEFAULT_CLARITY_VERSION, sender, check) } @@ -128,9 +127,9 @@ pub fn execute_and_check_versioned( version: ClarityVersion, sender: StandardPrincipalData, mut check: F, -) -> InterpreterResult> +) -> Result, VmExecutionError> where - F: FnMut(&mut GlobalContext) -> InterpreterResult<()>, + F: FnMut(&mut GlobalContext) -> Result<(), VmExecutionError>, { let sender_for_init = sender.clone(); execute_with_parameters_and_call_in_global_context( diff --git a/clarity/src/vm/tests/representations.rs b/clarity/src/vm/tests/representations.rs index bed3ba78496..e96db9ba73f 100644 --- a/clarity/src/vm/tests/representations.rs +++ b/clarity/src/vm/tests/representations.rs @@ -17,7 +17,7 @@ use proptest::prelude::*; use proptest::string::string_regex; use stacks_common::codec::StacksMessageCodec; -use crate::vm::errors::RuntimeErrorType; +use crate::vm::errors::RuntimeError; use crate::vm::representations::{ CLARITY_NAME_REGEX_STRING, CONTRACT_MAX_NAME_LENGTH, CONTRACT_MIN_NAME_LENGTH, CONTRACT_NAME_REGEX_STRING, MAX_STRING_LEN, @@ -164,7 +164,7 @@ fn prop_clarity_name_invalid_patterns() { prop_assert!(result.is_err(), "Expected invalid name '{}' to be rejected", name); prop_assert!(matches!( result.unwrap_err(), - RuntimeErrorType::BadNameValue(_, _) + RuntimeError::BadNameValue(_, _) ), "Expected BadNameValue error for invalid name '{}'", name); }); } @@ -302,7 +302,7 @@ fn prop_contract_name_invalid_patterns() { prop_assert!(result.is_err(), "Expected invalid contract name '{}' to be rejected", name); prop_assert!(matches!( result.unwrap_err(), - RuntimeErrorType::BadNameValue(_, _) + RuntimeError::BadNameValue(_, _) ), "Expected BadNameValue error for invalid contract name '{}'", name); }); } diff --git a/clarity/src/vm/tests/sequences.rs b/clarity/src/vm/tests/sequences.rs index 85675f0ad54..3fd92b6d055 100644 --- a/clarity/src/vm/tests/sequences.rs +++ b/clarity/src/vm/tests/sequences.rs @@ -22,7 +22,7 @@ use stacks_common::types::StacksEpochId; use crate::vm::tests::test_clarity_versions; #[cfg(test)] use crate::vm::{ - errors::{CheckErrors, Error, RuntimeErrorType}, + errors::{CheckErrorKind, RuntimeError, VmExecutionError}, execute, execute_v2, types::{ signatures::{ @@ -59,7 +59,7 @@ fn test_simple_list_admission() { ); let err = execute(&t3).unwrap_err(); assert!(match err { - Error::Unchecked(CheckErrors::TypeValueError(_, _)) => true, + VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(_, _)) => true, _ => { eprintln!("Expected TypeError, but found: {err:?}"); false @@ -112,16 +112,16 @@ fn test_index_of() { ]; let bad_expected = [ - CheckErrors::ExpectedSequence(Box::new(TypeSignature::IntType)), - CheckErrors::TypeValueError( + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::IntType)), + CheckErrorKind::TypeValueError( Box::new(TypeSignature::BUFFER_MIN), Box::new(execute("\"a\"").unwrap().unwrap()), ), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(TypeSignature::STRING_UTF8_MIN), Box::new(execute("\"a\"").unwrap().unwrap()), ), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(TypeSignature::STRING_ASCII_MIN), Box::new(execute("u\"a\"").unwrap().unwrap()), ), @@ -129,7 +129,7 @@ fn test_index_of() { for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { match execute(bad_test).unwrap_err() { - Error::Unchecked(check_error) => { + VmExecutionError::Unchecked(check_error) => { assert_eq!(&check_error, expected); } _ => unreachable!("Should have raised unchecked errors"), @@ -173,13 +173,13 @@ fn test_element_at() { let bad = ["(element-at 3 u1)", "(element-at (list 1 2 3) 1)"]; let bad_expected = [ - CheckErrors::ExpectedSequence(Box::new(TypeSignature::IntType)), - CheckErrors::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(Value::Int(1))), + CheckErrorKind::ExpectedSequence(Box::new(TypeSignature::IntType)), + CheckErrorKind::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(Value::Int(1))), ]; for (bad_test, expected) in bad.iter().zip(bad_expected.iter()) { match execute(bad_test).unwrap_err() { - Error::Unchecked(check_error) => { + VmExecutionError::Unchecked(check_error) => { assert_eq!(&check_error, expected); } _ => unreachable!("Should have raised unchecked errors"), @@ -451,7 +451,7 @@ fn test_simple_map_append() { assert_eq!( execute("(append (append (list) 1) u2)").unwrap_err(), - CheckErrors::TypeValueError(Box::new(IntType), Box::new(Value::UInt(2))).into() + CheckErrorKind::TypeValueError(Box::new(IntType), Box::new(Value::UInt(2))).into() ); } @@ -587,17 +587,17 @@ fn test_simple_list_concat() { assert_eq!( execute("(concat (list 1) (list u4 u8))").unwrap_err(), - CheckErrors::TypeError(Box::new(IntType), Box::new(UIntType)).into() + CheckErrorKind::TypeError(Box::new(IntType), Box::new(UIntType)).into() ); assert_eq!( execute("(concat (list 1) 3)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + RuntimeError::BadTypeConstruction.into() ); assert_eq!( execute("(concat (list 1) \"1\")").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + RuntimeError::BadTypeConstruction.into() ); } @@ -623,12 +623,12 @@ fn test_simple_buff_concat() { assert_eq!( execute("(concat 0x31 3)").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + RuntimeError::BadTypeConstruction.into() ); assert_eq!( execute("(concat 0x31 (list 1))").unwrap_err(), - RuntimeErrorType::BadTypeConstruction.into() + RuntimeError::BadTypeConstruction.into() ); } @@ -710,25 +710,26 @@ fn test_simple_list_replace_at() { // The sequence input has the wrong type assert_eq!( execute_v2("(replace-at? 0 u0 (list 0))").unwrap_err(), - CheckErrors::ExpectedSequence(Box::new(IntType)).into() + CheckErrorKind::ExpectedSequence(Box::new(IntType)).into() ); // The type of the index should be uint. assert_eq!( execute_v2("(replace-at? (list 1) 0 0)").unwrap_err(), - CheckErrors::TypeValueError(Box::new(UIntType), Box::new(Value::Int(0))).into() + CheckErrorKind::TypeValueError(Box::new(UIntType), Box::new(Value::Int(0))).into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at? (list 2 3) u0 true)").unwrap_err(), - CheckErrors::TypeValueError(Box::new(IntType), Box::new(Value::Bool(true))).into() + CheckErrorKind::TypeValueError(Box::new(IntType), Box::new(Value::Bool(true))).into() ); // The element input has the wrong type assert_eq!( execute_v2("(replace-at? (list 2 3) u0 0x00)").unwrap_err(), - CheckErrors::TypeValueError(Box::new(IntType), Box::new(Value::buff_from_byte(0))).into() + CheckErrorKind::TypeValueError(Box::new(IntType), Box::new(Value::buff_from_byte(0))) + .into() ); } @@ -768,20 +769,20 @@ fn test_simple_buff_replace_at() { // The sequence input has the wrong type assert_eq!( execute_v2("(replace-at? 33 u0 0x00)").unwrap_err(), - CheckErrors::ExpectedSequence(Box::new(IntType)).into() + CheckErrorKind::ExpectedSequence(Box::new(IntType)).into() ); // The type of the index should be uint. assert_eq!( execute_v2("(replace-at? 0x002244 0 0x99)").unwrap_err(), - CheckErrors::TypeValueError(Box::new(UIntType), Box::new(Value::Int(0))).into() + CheckErrorKind::TypeValueError(Box::new(UIntType), Box::new(Value::Int(0))).into() ); // The element input has the wrong type let buff_len = BufferLength::try_from(1u32).unwrap(); assert_eq!( execute_v2("(replace-at? 0x445522 u0 55)").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType(buff_len.clone()))), Box::new(Value::Int(55)) ) @@ -791,7 +792,7 @@ fn test_simple_buff_replace_at() { // The element input has the wrong type assert_eq!( execute_v2("(replace-at? 0x445522 u0 (list 5))").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType(buff_len.clone()))), Box::new(Value::list_from(vec![Value::Int(5)]).unwrap()) ) @@ -801,7 +802,7 @@ fn test_simple_buff_replace_at() { // The element input has the wrong type (not length 1) assert_eq!( execute_v2("(replace-at? 0x445522 u0 0x0044)").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(BufferType(buff_len))), Box::new(Value::buff_from(vec![0, 68]).unwrap()) ) @@ -845,20 +846,20 @@ fn test_simple_string_ascii_replace_at() { // The sequence input has the wrong type assert_eq!( execute_v2("(replace-at? 33 u0 \"c\")").unwrap_err(), - CheckErrors::ExpectedSequence(Box::new(IntType)).into() + CheckErrorKind::ExpectedSequence(Box::new(IntType)).into() ); // The type of the index should be uint. assert_eq!( execute_v2("(replace-at? \"abc\" 0 \"c\")").unwrap_err(), - CheckErrors::TypeValueError(Box::new(UIntType), Box::new(Value::Int(0))).into() + CheckErrorKind::TypeValueError(Box::new(UIntType), Box::new(Value::Int(0))).into() ); // The element input has the wrong type let buff_len = BufferLength::try_from(1u32).unwrap(); assert_eq!( execute_v2("(replace-at? \"abc\" u0 55)").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(StringType(ASCII(buff_len.clone())))), Box::new(Value::Int(55)) ) @@ -868,7 +869,7 @@ fn test_simple_string_ascii_replace_at() { // The element input has the wrong type assert_eq!( execute_v2("(replace-at? \"abc\" u0 0x00)").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(StringType(ASCII(buff_len.clone())))), Box::new(Value::buff_from_byte(0)) ) @@ -878,7 +879,7 @@ fn test_simple_string_ascii_replace_at() { // The element input has the wrong type assert_eq!( execute_v2("(replace-at? \"abc\" u0 \"de\")").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(SequenceType(StringType(ASCII(buff_len)))), Box::new(Value::string_ascii_from_bytes("de".into()).unwrap()) ) @@ -926,20 +927,20 @@ fn test_simple_string_utf8_replace_at() { // The sequence input has the wrong type assert_eq!( execute_v2("(replace-at? 33 u0 u\"c\")").unwrap_err(), - CheckErrors::ExpectedSequence(Box::new(IntType)).into() + CheckErrorKind::ExpectedSequence(Box::new(IntType)).into() ); // The type of the index should be uint. assert_eq!( execute_v2("(replace-at? u\"abc\" 0 u\"c\")").unwrap_err(), - CheckErrors::TypeValueError(Box::new(UIntType), Box::new(Value::Int(0))).into() + CheckErrorKind::TypeValueError(Box::new(UIntType), Box::new(Value::Int(0))).into() ); // The element input has the wrong type let str_len = StringUTF8Length::try_from(1u32).unwrap(); assert_eq!( execute_v2("(replace-at? u\"abc\" u0 55)").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(TypeSignature::SequenceType(StringType( StringSubtype::UTF8(str_len.clone()) ))), @@ -951,7 +952,7 @@ fn test_simple_string_utf8_replace_at() { // The element input has the wrong type assert_eq!( execute_v2("(replace-at? u\"abc\" u0 0x00)").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(TypeSignature::SequenceType(StringType( StringSubtype::UTF8(str_len.clone()) ))), @@ -963,7 +964,7 @@ fn test_simple_string_utf8_replace_at() { // The element input has the wrong type assert_eq!( execute_v2("(replace-at? u\"abc\" u0 u\"de\")").unwrap_err(), - CheckErrors::TypeValueError( + CheckErrorKind::TypeValueError( Box::new(TypeSignature::SequenceType(StringType( StringSubtype::UTF8(str_len) ))), @@ -993,22 +994,22 @@ fn test_simple_buff_assert_max_len() { assert_eq!( execute("(as-max-len? 0x313233)").unwrap_err(), - CheckErrors::IncorrectArgumentCount(2, 1).into() + CheckErrorKind::IncorrectArgumentCount(2, 1).into() ); assert_eq!( execute("(as-max-len? 0x313233 3)").unwrap_err(), - CheckErrors::TypeError(Box::new(UIntType), Box::new(IntType)).into() + CheckErrorKind::TypeError(Box::new(UIntType), Box::new(IntType)).into() ); assert_eq!( execute("(as-max-len? 1 u3)").unwrap_err(), - CheckErrors::ExpectedSequence(Box::new(IntType)).into() + CheckErrorKind::ExpectedSequence(Box::new(IntType)).into() ); assert_eq!( execute("(as-max-len? 0x313233 0x31)").unwrap_err(), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(UIntType), Box::new(SequenceType(SequenceSubtype::BufferType( 1_u32.try_into().unwrap() @@ -1175,14 +1176,14 @@ fn test_construct_bad_list(#[case] version: ClarityVersion, #[case] epoch: Stack let test1 = "(list 1 2 3 true)"; assert_eq!( execute(test1).unwrap_err(), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)).into() + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)).into() ); let test2 = "(define-private (bad-function (x int)) (if (is-eq x 1) true x)) (map bad-function (list 0 1 2 3))"; assert_eq!( execute(test2).unwrap_err(), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)).into() + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)).into() ); let bad_2d_list = "(list (list 1 2 3) (list true false true))"; @@ -1190,11 +1191,11 @@ fn test_construct_bad_list(#[case] version: ClarityVersion, #[case] epoch: Stack assert_eq!( execute(bad_2d_list).unwrap_err(), - CheckErrors::TypeError(Box::new(IntType), Box::new(BoolType)).into() + CheckErrorKind::TypeError(Box::new(IntType), Box::new(BoolType)).into() ); assert_eq!( execute(bad_high_order_list).unwrap_err(), - CheckErrors::TypeError( + CheckErrorKind::TypeError( Box::new(IntType), Box::new(TypeSignature::from_string("(list 3 int)", version, epoch)) ) @@ -1205,23 +1206,23 @@ fn test_construct_bad_list(#[case] version: ClarityVersion, #[case] epoch: Stack #[test] fn test_eval_func_arg_panic() { let test1 = "(fold (lambda (x y) (* x y)) (list 1 2 3 4) 1)"; - let e: Error = CheckErrors::ExpectedName.into(); + let e: VmExecutionError = CheckErrorKind::ExpectedName.into(); assert_eq!(e, execute(test1).unwrap_err()); let test2 = "(map (lambda (x) (* x x)) (list 1 2 3 4))"; - let e: Error = CheckErrors::ExpectedName.into(); + let e: VmExecutionError = CheckErrorKind::ExpectedName.into(); assert_eq!(e, execute(test2).unwrap_err()); let test3 = "(map square (list 1 2 3 4) 2)"; - let e: Error = CheckErrors::UndefinedFunction("square".to_string()).into(); + let e: VmExecutionError = CheckErrorKind::UndefinedFunction("square".to_string()).into(); assert_eq!(e, execute(test3).unwrap_err()); let test4 = "(define-private (multiply-all (x int) (acc int)) (* x acc)) (fold multiply-all (list 1 2 3 4))"; - let e: Error = CheckErrors::IncorrectArgumentCount(3, 2).into(); + let e: VmExecutionError = CheckErrorKind::IncorrectArgumentCount(3, 2).into(); assert_eq!(e, execute(test4).unwrap_err()); let test5 = "(map + (list 1 2 3 4) 2)"; - let e: Error = CheckErrors::ExpectedSequence(Box::new(IntType)).into(); + let e: VmExecutionError = CheckErrorKind::ExpectedSequence(Box::new(IntType)).into(); assert_eq!(e, execute(test5).unwrap_err()); } diff --git a/clarity/src/vm/tests/simple_apply_eval.rs b/clarity/src/vm/tests/simple_apply_eval.rs index 5ee0b6e8702..3a67aeae0dd 100644 --- a/clarity/src/vm/tests/simple_apply_eval.rs +++ b/clarity/src/vm/tests/simple_apply_eval.rs @@ -31,7 +31,7 @@ use crate::vm::callables::DefinedFunction; use crate::vm::contexts::OwnedEnvironment; use crate::vm::costs::LimitedCostTracker; use crate::vm::database::MemoryBackingStore; -use crate::vm::errors::{CheckErrors, Error, RuntimeErrorType, ShortReturnType}; +use crate::vm::errors::{CheckErrorKind, EarlyReturnError, RuntimeError, VmExecutionError}; use crate::vm::tests::{execute, test_clarity_versions}; use crate::vm::types::signatures::*; use crate::vm::types::{ @@ -55,7 +55,7 @@ fn test_doubly_defined_persisted_vars() { for p in tests.iter() { assert_eq!( vm_execute(p).unwrap_err(), - CheckErrors::NameAlreadyUsed("cursor".into()).into() + CheckErrorKind::NameAlreadyUsed("cursor".into()).into() ); } } @@ -576,19 +576,19 @@ fn test_secp256k1_errors() { "(principal-of?)", ]; - let expectations: &[Error] = &[ - CheckErrors::TypeValueError(Box::new(TypeSignature::BUFFER_32), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("de5b9eb9e7c5592930eb2e30a01369c36586d872082ed8181ee83d2a0ec20f").unwrap() })))).into(), - CheckErrors::TypeValueError(Box::new(TypeSignature::BUFFER_65), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("8738487ebe69b93d8e51583be8eee50bb4213fc49c767d329632730cc193b873554428fc936ca3569afc15f1c9365f6591d6251a89fee9c9ac661116824d3a130100").unwrap() })))).into(), - CheckErrors::IncorrectArgumentCount(2, 1).into(), - CheckErrors::IncorrectArgumentCount(2, 3).into(), + let expectations: &[VmExecutionError] = &[ + CheckErrorKind::TypeValueError(Box::new(TypeSignature::BUFFER_32), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("de5b9eb9e7c5592930eb2e30a01369c36586d872082ed8181ee83d2a0ec20f").unwrap() })))).into(), + CheckErrorKind::TypeValueError(Box::new(TypeSignature::BUFFER_65), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("8738487ebe69b93d8e51583be8eee50bb4213fc49c767d329632730cc193b873554428fc936ca3569afc15f1c9365f6591d6251a89fee9c9ac661116824d3a130100").unwrap() })))).into(), + CheckErrorKind::IncorrectArgumentCount(2, 1).into(), + CheckErrorKind::IncorrectArgumentCount(2, 3).into(), - CheckErrors::TypeValueError(Box::new(TypeSignature::BUFFER_32), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("de5b9eb9e7c5592930eb2e30a01369c36586d872082ed8181ee83d2a0ec20f").unwrap() })))).into(), - CheckErrors::TypeValueError(Box::new(TypeSignature::BUFFER_65), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("8738487ebe69b93d8e51583be8eee50bb4213fc49c767d329632730cc193b873554428fc936ca3569afc15f1c9365f6591d6251a89fee9c9ac661116824d3a130111").unwrap() })))).into(), - CheckErrors::TypeValueError(Box::new(TypeSignature::BUFFER_33), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("03adb8de4bfb65db2cfd6120d55c6526ae9c52e675db7e47308636534ba7").unwrap() })))).into(), - CheckErrors::IncorrectArgumentCount(3, 2).into(), + CheckErrorKind::TypeValueError(Box::new(TypeSignature::BUFFER_32), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("de5b9eb9e7c5592930eb2e30a01369c36586d872082ed8181ee83d2a0ec20f").unwrap() })))).into(), + CheckErrorKind::TypeValueError(Box::new(TypeSignature::BUFFER_65), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("8738487ebe69b93d8e51583be8eee50bb4213fc49c767d329632730cc193b873554428fc936ca3569afc15f1c9365f6591d6251a89fee9c9ac661116824d3a130111").unwrap() })))).into(), + CheckErrorKind::TypeValueError(Box::new(TypeSignature::BUFFER_33), Box::new(Value::Sequence(SequenceData::Buffer(BuffData { data: hex_bytes("03adb8de4bfb65db2cfd6120d55c6526ae9c52e675db7e47308636534ba7").unwrap() })))).into(), + CheckErrorKind::IncorrectArgumentCount(3, 2).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::IncorrectArgumentCount(1, 0).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::IncorrectArgumentCount(1, 0).into(), ]; for (program, expectation) in secp256k1_evals.iter().zip(expectations.iter()) { @@ -873,8 +873,8 @@ fn test_sequence_comparisons_clarity1() { "(>= \"baa\" \"aaa\")", "(<= \"baa\" \"aaa\")", ]; - let error_expectations: &[Error] = &[ - CheckErrors::UnionTypeValueError( + let error_expectations: &[VmExecutionError] = &[ + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Sequence(SequenceData::String(CharType::ASCII( ASCIIData { @@ -883,7 +883,7 @@ fn test_sequence_comparisons_clarity1() { )))), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Sequence(SequenceData::String(CharType::ASCII( ASCIIData { @@ -892,7 +892,7 @@ fn test_sequence_comparisons_clarity1() { )))), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Sequence(SequenceData::String(CharType::ASCII( ASCIIData { @@ -901,7 +901,7 @@ fn test_sequence_comparisons_clarity1() { )))), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Sequence(SequenceData::String(CharType::ASCII( ASCIIData { @@ -984,13 +984,13 @@ fn test_sequence_comparisons_clarity2() { fn test_sequence_comparisons_mismatched_types() { // Tests that comparing objects of different types results in an error in Clarity1. let error_tests = ["(> 0 u1)", "(< 0 u1)"]; - let v1_error_expectations: &[Error] = &[ - CheckErrors::UnionTypeValueError( + let v1_error_expectations: &[VmExecutionError] = &[ + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Int(0)), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::Int(0)), ) @@ -1005,8 +1005,8 @@ fn test_sequence_comparisons_mismatched_types() { assert_eq!(*expectation, vm_execute(program).unwrap_err()) }); - let v2_error_expectations: &[Error] = &[ - CheckErrors::UnionTypeValueError( + let v2_error_expectations: &[VmExecutionError] = &[ + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1017,7 +1017,7 @@ fn test_sequence_comparisons_mismatched_types() { Box::new(Value::Int(0)), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1039,8 +1039,8 @@ fn test_sequence_comparisons_mismatched_types() { // Tests that comparing objects of different types results in an error in Clarity2. let error_tests = ["(> \"baa\" u\"aaa\")", "(> \"baa\" 0x0001)"]; - let error_expectations: &[Error] = &[ - CheckErrors::UnionTypeValueError( + let error_expectations: &[VmExecutionError] = &[ + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1055,7 +1055,7 @@ fn test_sequence_comparisons_mismatched_types() { )))), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1108,39 +1108,35 @@ fn test_simple_arithmetic_errors(#[case] version: ClarityVersion, #[case] epoch: "(is-eq (some 1) (some true))", ]; - let expectations: &[Error] = &[ - CheckErrors::IncorrectArgumentCount(2, 1).into(), - CheckErrors::TypeValueError( + let expectations: &[VmExecutionError] = &[ + CheckErrorKind::IncorrectArgumentCount(2, 1).into(), + CheckErrorKind::TypeValueError( Box::new(TypeSignature::IntType), Box::new(Value::Bool(true)), ) .into(), - RuntimeErrorType::DivisionByZero.into(), - RuntimeErrorType::DivisionByZero.into(), - RuntimeErrorType::ArithmeticOverflow.into(), - RuntimeErrorType::ArithmeticOverflow.into(), - RuntimeErrorType::ArithmeticOverflow.into(), - RuntimeErrorType::ArithmeticUnderflow.into(), - CheckErrors::IncorrectArgumentCount(1, 0).into(), - CheckErrors::IncorrectArgumentCount(1, 0).into(), - CheckErrors::IncorrectArgumentCount(2, 1).into(), - CheckErrors::IncorrectArgumentCount(2, 1).into(), - CheckErrors::IncorrectArgumentCount(1, 0).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - RuntimeErrorType::Arithmetic("sqrti must be passed a positive integer".to_string()).into(), - CheckErrors::IncorrectArgumentCount(1, 0).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - RuntimeErrorType::Arithmetic("log2 must be passed a positive integer".to_string()).into(), - CheckErrors::IncorrectArgumentCount(2, 1).into(), - RuntimeErrorType::Arithmetic( - "Power argument to (pow ...) must be a u32 integer".to_string(), - ) - .into(), - RuntimeErrorType::Arithmetic( - "Power argument to (pow ...) must be a u32 integer".to_string(), - ) - .into(), - CheckErrors::TypeError( + RuntimeError::DivisionByZero.into(), + RuntimeError::DivisionByZero.into(), + RuntimeError::ArithmeticOverflow.into(), + RuntimeError::ArithmeticOverflow.into(), + RuntimeError::ArithmeticOverflow.into(), + RuntimeError::ArithmeticUnderflow.into(), + CheckErrorKind::IncorrectArgumentCount(1, 0).into(), + CheckErrorKind::IncorrectArgumentCount(1, 0).into(), + CheckErrorKind::IncorrectArgumentCount(2, 1).into(), + CheckErrorKind::IncorrectArgumentCount(2, 1).into(), + CheckErrorKind::IncorrectArgumentCount(1, 0).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + RuntimeError::Arithmetic("sqrti must be passed a positive integer".to_string()).into(), + CheckErrorKind::IncorrectArgumentCount(1, 0).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + RuntimeError::Arithmetic("log2 must be passed a positive integer".to_string()).into(), + CheckErrorKind::IncorrectArgumentCount(2, 1).into(), + RuntimeError::Arithmetic("Power argument to (pow ...) must be a u32 integer".to_string()) + .into(), + RuntimeError::Arithmetic("Power argument to (pow ...) must be a u32 integer".to_string()) + .into(), + CheckErrorKind::TypeError( Box::new(TypeSignature::from_string("bool", version, epoch)), Box::new(TypeSignature::from_string("int", version, epoch)), ) @@ -1163,18 +1159,18 @@ fn test_unsigned_arithmetic() { "(to-int (pow u2 u127))", ]; - let expectations: &[Error] = &[ - RuntimeErrorType::ArithmeticUnderflow.into(), - RuntimeErrorType::ArithmeticUnderflow.into(), - CheckErrors::UnionTypeValueError( + let expectations: &[VmExecutionError] = &[ + RuntimeError::ArithmeticUnderflow.into(), + RuntimeError::ArithmeticUnderflow.into(), + CheckErrorKind::UnionTypeValueError( vec![TypeSignature::IntType, TypeSignature::UIntType], Box::new(Value::UInt(10)), ) .into(), - CheckErrors::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(Value::Int(80))) + CheckErrorKind::TypeValueError(Box::new(TypeSignature::UIntType), Box::new(Value::Int(80))) .into(), - RuntimeErrorType::ArithmeticUnderflow.into(), - RuntimeErrorType::ArithmeticOverflow.into(), + RuntimeError::ArithmeticUnderflow.into(), + RuntimeError::ArithmeticOverflow.into(), ]; for (program, expectation) in tests.iter().zip(expectations.iter()) { @@ -1202,22 +1198,22 @@ fn test_options_errors() { "(get field-0 1)", ]; - let expectations: &[Error] = &[ - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::ExpectedOptionalValue(Box::new(Value::Bool(true))).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::ExpectedResponseValue(Box::new(Value::Bool(true))).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::ExpectedResponseValue(Box::new(Value::Bool(true))).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::ExpectedOptionalValue(Box::new(Value::Bool(true))).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::IncorrectArgumentCount(2, 3).into(), - CheckErrors::ExpectedOptionalValue(Box::new(Value::Bool(true))).into(), - CheckErrors::ExpectedTuple(Box::new(TypeSignature::IntType)).into(), - CheckErrors::ExpectedTuple(Box::new(TypeSignature::IntType)).into(), + let expectations: &[VmExecutionError] = &[ + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::ExpectedOptionalValue(Box::new(Value::Bool(true))).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::ExpectedResponseValue(Box::new(Value::Bool(true))).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::ExpectedResponseValue(Box::new(Value::Bool(true))).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::ExpectedOptionalValue(Box::new(Value::Bool(true))).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::IncorrectArgumentCount(2, 3).into(), + CheckErrorKind::ExpectedOptionalValue(Box::new(Value::Bool(true))).into(), + CheckErrorKind::ExpectedTuple(Box::new(TypeSignature::IntType)).into(), + CheckErrorKind::ExpectedTuple(Box::new(TypeSignature::IntType)).into(), ]; for (program, expectation) in tests.iter().zip(expectations.iter()) { @@ -1240,17 +1236,17 @@ fn test_stx_ops_errors() { "(stx-burn? 4 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR)", ]; - let expectations: &[Error] = &[ - CheckErrors::IncorrectArgumentCount(3, 2).into(), - CheckErrors::BadTransferSTXArguments.into(), - CheckErrors::BadTransferSTXArguments.into(), - CheckErrors::BadTransferSTXArguments.into(), - CheckErrors::IncorrectArgumentCount(4, 3).into(), - CheckErrors::BadTransferSTXArguments.into(), - CheckErrors::BadTransferSTXArguments.into(), - CheckErrors::BadTransferSTXArguments.into(), - CheckErrors::IncorrectArgumentCount(2, 1).into(), - CheckErrors::BadTransferSTXArguments.into(), + let expectations: &[VmExecutionError] = &[ + CheckErrorKind::IncorrectArgumentCount(3, 2).into(), + CheckErrorKind::BadTransferSTXArguments.into(), + CheckErrorKind::BadTransferSTXArguments.into(), + CheckErrorKind::BadTransferSTXArguments.into(), + CheckErrorKind::IncorrectArgumentCount(4, 3).into(), + CheckErrorKind::BadTransferSTXArguments.into(), + CheckErrorKind::BadTransferSTXArguments.into(), + CheckErrorKind::BadTransferSTXArguments.into(), + CheckErrorKind::IncorrectArgumentCount(2, 1).into(), + CheckErrorKind::BadTransferSTXArguments.into(), ]; for (program, expectation) in tests.iter().zip(expectations.iter()) { @@ -1313,7 +1309,7 @@ fn test_bitwise() { "(bit-shift-left -64 u121)", // -170141183460469231731687303715884105728 ]; - let expectations: &[Result] = &[ + let expectations: &[Result] = &[ Ok(Value::Int(16)), // (bit-and 24 16) Ok(Value::UInt(16)), // (bit-and u24 u16) Ok(Value::Int(28)), // (bit-xor 24 4)y @@ -1418,33 +1414,33 @@ fn test_option_destructs() { "(try! 1)", ]; - let expectations: &[Result] = &[ + let expectations: &[Result] = &[ Ok(Value::Int(1)), Ok(Value::Int(1)), Err( - CheckErrors::ExpectedResponseValue(Box::new(Value::some(Value::Int(2)).unwrap())) + CheckErrorKind::ExpectedResponseValue(Box::new(Value::some(Value::Int(2)).unwrap())) .into(), ), Ok(Value::Int(3)), - Err(ShortReturnType::ExpectedValue(Box::new(Value::Int(2))).into()), + Err(EarlyReturnError::UnwrapFailed(Box::new(Value::Int(2))).into()), Ok(Value::Int(3)), Ok(Value::Int(3)), Ok(Value::Int(3)), - Err(RuntimeErrorType::UnwrapFailure.into()), - Err(RuntimeErrorType::UnwrapFailure.into()), - Err(RuntimeErrorType::UnwrapFailure.into()), + Err(RuntimeError::UnwrapFailure.into()), + Err(RuntimeError::UnwrapFailure.into()), + Err(RuntimeError::UnwrapFailure.into()), Ok(Value::Int(2)), Ok(Value::Int(9)), Ok(Value::Int(2)), Ok(Value::Int(8)), - Err(CheckErrors::BadMatchInput(Box::new(TypeSignature::IntType)).into()), - Err(CheckErrors::BadMatchInput(Box::new(TypeSignature::IntType)).into()), - Err(ShortReturnType::ExpectedValue(Box::new(Value::error(Value::UInt(1)).unwrap())).into()), + Err(CheckErrorKind::BadMatchInput(Box::new(TypeSignature::IntType)).into()), + Err(CheckErrorKind::BadMatchInput(Box::new(TypeSignature::IntType)).into()), + Err(EarlyReturnError::UnwrapFailed(Box::new(Value::error(Value::UInt(1)).unwrap())).into()), Ok(Value::Int(3)), - Err(ShortReturnType::ExpectedValue(Box::new(Value::none())).into()), + Err(EarlyReturnError::UnwrapFailed(Box::new(Value::none())).into()), Ok(Value::Bool(true)), - Err(CheckErrors::IncorrectArgumentCount(1, 2).into()), - Err(CheckErrors::ExpectedOptionalOrResponseValue(Box::new(Value::Int(1))).into()), + Err(CheckErrorKind::IncorrectArgumentCount(1, 2).into()), + Err(CheckErrorKind::ExpectedOptionalOrResponseValue(Box::new(Value::Int(1))).into()), ]; for (program, expectation) in tests.iter().zip(expectations.iter()) { @@ -1467,11 +1463,11 @@ fn test_hash_errors() { "(sha512/256 1 2)", ]; - let expectations: &[Error] = &[ - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::UnionTypeValueError( + let expectations: &[VmExecutionError] = &[ + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1480,7 +1476,7 @@ fn test_hash_errors() { Box::new(Value::Bool(true)), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1489,7 +1485,7 @@ fn test_hash_errors() { Box::new(Value::Bool(true)), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1498,7 +1494,7 @@ fn test_hash_errors() { Box::new(Value::Bool(true)), ) .into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1507,8 +1503,8 @@ fn test_hash_errors() { Box::new(Value::Bool(true)), ) .into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), - CheckErrors::UnionTypeValueError( + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::UnionTypeValueError( vec![ TypeSignature::IntType, TypeSignature::UIntType, @@ -1517,7 +1513,7 @@ fn test_hash_errors() { Box::new(Value::Bool(true)), ) .into(), - CheckErrors::IncorrectArgumentCount(1, 2).into(), + CheckErrorKind::IncorrectArgumentCount(1, 2).into(), ]; for (program, expectation) in tests.iter().zip(expectations.iter()) { @@ -1568,13 +1564,13 @@ fn test_bad_lets() { "(let ((false 1)) false)", ]; - let expectations: &[Error] = &[ - CheckErrors::NameAlreadyUsed("tx-sender".to_string()).into(), - CheckErrors::NameAlreadyUsed("*".to_string()).into(), - CheckErrors::NameAlreadyUsed("a".to_string()).into(), - CheckErrors::NoSuchDataVariable("cursor".to_string()).into(), - CheckErrors::NameAlreadyUsed("true".to_string()).into(), - CheckErrors::NameAlreadyUsed("false".to_string()).into(), + let expectations: &[VmExecutionError] = &[ + CheckErrorKind::NameAlreadyUsed("tx-sender".to_string()).into(), + CheckErrorKind::NameAlreadyUsed("*".to_string()).into(), + CheckErrorKind::NameAlreadyUsed("a".to_string()).into(), + CheckErrorKind::NoSuchDataVariable("cursor".to_string()).into(), + CheckErrorKind::NameAlreadyUsed("true".to_string()).into(), + CheckErrorKind::NameAlreadyUsed("false".to_string()).into(), ]; tests @@ -1669,11 +1665,11 @@ fn test_asserts_short_circuit() { "(begin (asserts! (is-eq 1 1) (err 0)) (asserts! (is-eq 2 1) (err 1)) (ok 2))", ]; - let expectations: &[Error] = &[ - Error::ShortReturn(ShortReturnType::AssertionFailed(Box::new( + let expectations: &[VmExecutionError] = &[ + VmExecutionError::EarlyReturn(EarlyReturnError::AssertionFailed(Box::new( Value::error(Value::Int(0)).unwrap(), ))), - Error::ShortReturn(ShortReturnType::AssertionFailed(Box::new( + VmExecutionError::EarlyReturn(EarlyReturnError::AssertionFailed(Box::new( Value::error(Value::Int(1)).unwrap(), ))), ]; diff --git a/clarity/src/vm/tests/traits.rs b/clarity/src/vm/tests/traits.rs index a01fa11bf0a..bc612613144 100644 --- a/clarity/src/vm/tests/traits.rs +++ b/clarity/src/vm/tests/traits.rs @@ -21,7 +21,7 @@ use super::MemoryEnvironmentGenerator; use crate::vm::tests::{test_clarity_versions, test_epochs}; #[cfg(test)] use crate::vm::{ - errors::{CheckErrors, Error}, + errors::{CheckErrorKind, VmExecutionError}, tests::{env_factory, execute, symbols_from_values}, types::{PrincipalData, QualifiedContractIdentifier, Value}, version::ClarityVersion, @@ -242,7 +242,7 @@ fn test_dynamic_dispatch_intra_contract_call( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::CircularReference(_)) => {} + VmExecutionError::Unchecked(CheckErrorKind::CircularReference(_)) => {} _ => panic!("{err_result:?}"), } } @@ -557,7 +557,7 @@ fn test_dynamic_dispatch_mismatched_args( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::BadTraitImplementation(_, _)) => {} + VmExecutionError::Unchecked(CheckErrorKind::BadTraitImplementation(_, _)) => {} _ => panic!("{err_result:?}"), } } @@ -612,7 +612,7 @@ fn test_dynamic_dispatch_mismatched_returned( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::ReturnTypesMustMatch(_, _)) => {} + VmExecutionError::Unchecked(CheckErrorKind::ReturnTypesMustMatch(_, _)) => {} _ => panic!("{err_result:?}"), } } @@ -670,7 +670,7 @@ fn test_reentrant_dynamic_dispatch( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::CircularReference(_)) => {} + VmExecutionError::Unchecked(CheckErrorKind::CircularReference(_)) => {} _ => panic!("{err_result:?}"), } } @@ -725,7 +725,7 @@ fn test_readwrite_dynamic_dispatch( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::TraitBasedContractCallInReadOnly) => {} + VmExecutionError::Unchecked(CheckErrorKind::TraitBasedContractCallInReadOnly) => {} _ => panic!("{err_result:?}"), } } @@ -780,7 +780,7 @@ fn test_readwrite_violation_dynamic_dispatch( ) .unwrap_err(); match err_result { - Error::Unchecked(CheckErrors::TraitBasedContractCallInReadOnly) => {} + VmExecutionError::Unchecked(CheckErrorKind::TraitBasedContractCallInReadOnly) => {} _ => panic!("{err_result:?}"), } } diff --git a/clarity/src/vm/tests/variables.rs b/clarity/src/vm/tests/variables.rs index 852533a0012..af65c3e24c9 100644 --- a/clarity/src/vm/tests/variables.rs +++ b/clarity/src/vm/tests/variables.rs @@ -25,7 +25,7 @@ use crate::vm::{ analysis::type_checker::v2_1::tests::contracts::type_check_version, ast::parse, database::MemoryBackingStore, - errors::{CheckErrors, Error}, + errors::{CheckErrorKind, VmExecutionError}, tests::{tl_env_factory, TopLevelMemoryEnvironmentGenerator}, types::{PrincipalData, QualifiedContractIdentifier, Value}, ClarityVersion, ContractContext, @@ -54,7 +54,7 @@ fn test_block_height( if version >= ClarityVersion::Clarity3 { let err = analysis.unwrap_err(); assert_eq!( - CheckErrors::UndefinedVariable("block-height".to_string()), + CheckErrorKind::UndefinedVariable("block-height".to_string()), *err.err ); } else { @@ -80,7 +80,9 @@ fn test_block_height( if version >= ClarityVersion::Clarity3 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable("block-height".to_string(),)), + VmExecutionError::Unchecked(CheckErrorKind::UndefinedVariable( + "block-height".to_string(), + )), err ); } else { @@ -111,7 +113,7 @@ fn test_stacks_block_height( if version < ClarityVersion::Clarity3 { let err = analysis.unwrap_err(); assert_eq!( - CheckErrors::UndefinedVariable("stacks-block-height".to_string()), + CheckErrorKind::UndefinedVariable("stacks-block-height".to_string()), *err.err ); } else { @@ -137,7 +139,7 @@ fn test_stacks_block_height( if version < ClarityVersion::Clarity3 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable( + VmExecutionError::Unchecked(CheckErrorKind::UndefinedVariable( "stacks-block-height".to_string(), )), err @@ -170,7 +172,7 @@ fn test_tenure_height( if version < ClarityVersion::Clarity3 { let err = analysis.unwrap_err(); assert_eq!( - CheckErrors::UndefinedVariable("tenure-height".to_string()), + CheckErrorKind::UndefinedVariable("tenure-height".to_string()), *err.err ); } else { @@ -196,7 +198,9 @@ fn test_tenure_height( if version < ClarityVersion::Clarity3 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable("tenure-height".to_string(),)), + VmExecutionError::Unchecked(CheckErrorKind::UndefinedVariable( + "tenure-height".to_string(), + )), err ); } else { @@ -223,7 +227,7 @@ fn expect_contract_error( expected_errors: &[( WhenError, fn(ClarityVersion, StacksEpochId) -> bool, - CheckErrors, + CheckErrorKind, )], expected_success: Value, ) { @@ -269,7 +273,7 @@ fn expect_contract_error( for (when, err_condition, expected_error) in expected_errors { if *when == WhenError::Initialization && err_condition(version, epoch) { let err = init_result.unwrap_err(); - if let Error::Unchecked(inner_err) = &err { + if let VmExecutionError::Unchecked(inner_err) = &err { assert_eq!(expected_error, inner_err); } else { panic!("Expected an Unchecked error, but got a different error"); @@ -288,7 +292,7 @@ fn expect_contract_error( for (when, err_condition, expected_error) in expected_errors { if *when == WhenError::Runtime && err_condition(version, epoch) { let err = eval_result.unwrap_err(); - if let Error::Unchecked(inner_err) = &err { + if let VmExecutionError::Unchecked(inner_err) = &err { assert_eq!(expected_error, inner_err); } else { panic!("Expected an Unchecked error, but got a different error"); @@ -324,12 +328,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::UInt(1234), @@ -351,12 +355,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Bool(true), @@ -379,12 +383,12 @@ fn reuse_block_height( ( WhenError::Runtime, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Int(32), @@ -410,12 +414,12 @@ fn reuse_block_height( ( WhenError::Runtime, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Int(3), @@ -435,12 +439,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Bool(true), @@ -460,12 +464,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::UInt(1234), @@ -485,12 +489,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Bool(false), @@ -525,12 +529,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Bool(false), @@ -550,12 +554,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Bool(false), @@ -575,12 +579,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Bool(true), @@ -600,12 +604,12 @@ fn reuse_block_height( ( WhenError::Initialization, |version, _| version < ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("block-height".to_string()), ), ( WhenError::Analysis, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::ReservedWord("block-height".to_string()), + CheckErrorKind::ReservedWord("block-height".to_string()), ), ], Value::Bool(true), @@ -633,7 +637,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::UInt(1234), ); @@ -653,7 +657,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Bool(true), ); @@ -674,7 +678,7 @@ fn reuse_stacks_block_height( &[( WhenError::Runtime, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Int(32), ); @@ -698,7 +702,7 @@ fn reuse_stacks_block_height( &[( WhenError::Runtime, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Int(3), ); @@ -716,7 +720,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Bool(true), ); @@ -734,7 +738,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::UInt(1234), ); @@ -752,7 +756,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Bool(false), ); @@ -785,7 +789,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Bool(false), ); @@ -803,7 +807,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Bool(false), ); @@ -821,7 +825,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Bool(true), ); @@ -839,7 +843,7 @@ fn reuse_stacks_block_height( &[( WhenError::Initialization, |version, _| version >= ClarityVersion::Clarity3, - CheckErrors::NameAlreadyUsed("stacks-block-height".to_string()), + CheckErrorKind::NameAlreadyUsed("stacks-block-height".to_string()), )], Value::Bool(true), ); @@ -870,7 +874,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::UInt(1234), ); @@ -892,7 +896,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Bool(true), ); @@ -915,7 +919,7 @@ fn reuse_builtin_name( &[( WhenError::Runtime, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Int(32), ); @@ -941,7 +945,7 @@ fn reuse_builtin_name( &[( WhenError::Runtime, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Int(3), ); @@ -961,7 +965,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Bool(true), ); @@ -981,7 +985,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::UInt(1234), ); @@ -1001,7 +1005,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Bool(false), ); @@ -1038,7 +1042,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Bool(false), ); @@ -1058,7 +1062,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Bool(false), ); @@ -1078,7 +1082,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Bool(true), ); @@ -1098,7 +1102,7 @@ fn reuse_builtin_name( &[( WhenError::Initialization, version_check, - CheckErrors::NameAlreadyUsed(name.to_string()), + CheckErrorKind::NameAlreadyUsed(name.to_string()), )], Value::Bool(true), ); @@ -1129,7 +1133,7 @@ fn test_block_time( if version < ClarityVersion::Clarity4 { let err = analysis.unwrap_err(); assert_eq!( - CheckErrors::UndefinedVariable("stacks-block-time".to_string()), + CheckErrorKind::UndefinedVariable("stacks-block-time".to_string()), *err.err ); } else { @@ -1156,7 +1160,7 @@ fn test_block_time( if version < ClarityVersion::Clarity4 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable( + VmExecutionError::Unchecked(CheckErrorKind::UndefinedVariable( "stacks-block-time".to_string(), )), err @@ -1256,7 +1260,7 @@ fn test_current_contract( if version < ClarityVersion::Clarity4 { let err = analysis.unwrap_err(); assert_eq!( - CheckErrors::UndefinedVariable("current-contract".to_string()), + CheckErrorKind::UndefinedVariable("current-contract".to_string()), *err.err ); } else { @@ -1282,7 +1286,7 @@ fn test_current_contract( if version < ClarityVersion::Clarity4 { let err = eval_result.unwrap_err(); assert_eq!( - Error::Unchecked(CheckErrors::UndefinedVariable( + VmExecutionError::Unchecked(CheckErrorKind::UndefinedVariable( "current-contract".to_string(), )), err diff --git a/clarity/src/vm/tooling/mod.rs b/clarity/src/vm/tooling/mod.rs index bd5d0a0d79f..b400f67e034 100644 --- a/clarity/src/vm/tooling/mod.rs +++ b/clarity/src/vm/tooling/mod.rs @@ -3,7 +3,7 @@ use stacks_common::types::StacksEpochId; use super::analysis::ContractAnalysis; use super::types::TypeSignature; use super::ClarityVersion; -use crate::vm::analysis::{run_analysis, CheckError}; +use crate::vm::analysis::{run_analysis, StaticCheckError}; use crate::vm::ast::build_ast; use crate::vm::costs::LimitedCostTracker; use crate::vm::database::MemoryBackingStore; @@ -14,7 +14,7 @@ pub fn mem_type_check( snippet: &str, version: ClarityVersion, epoch: StacksEpochId, -) -> Result<(Option, ContractAnalysis), CheckError> { +) -> Result<(Option, ContractAnalysis), StaticCheckError> { let contract_identifier = QualifiedContractIdentifier::transient(); let contract = build_ast(&contract_identifier, snippet, &mut (), version, epoch) .unwrap() diff --git a/clarity/src/vm/types/mod.rs b/clarity/src/vm/types/mod.rs index 620d7f5d998..3ef4d04b739 100644 --- a/clarity/src/vm/types/mod.rs +++ b/clarity/src/vm/types/mod.rs @@ -28,7 +28,7 @@ pub use clarity_types::types::{ }; pub use self::std_principals::StandardPrincipalData; -use crate::vm::errors::CheckErrors; +use crate::vm::errors::CheckErrorKind; pub use crate::vm::types::signatures::{ parse_name_type_pairs, AssetIdentifier, BufferLength, FixedFunction, FunctionArg, FunctionSignature, FunctionType, ListTypeData, SequenceSubtype, StringSubtype, @@ -89,7 +89,7 @@ impl BlockInfoProperty { } impl BurnBlockInfoProperty { - pub fn type_result(&self) -> std::result::Result { + pub fn type_result(&self) -> std::result::Result { use self::BurnBlockInfoProperty::*; let result = match self { HeaderHash => TypeSignature::BUFFER_32, @@ -103,18 +103,20 @@ impl BurnBlockInfoProperty { ("hashbytes".into(), TypeSignature::BUFFER_32), ]) .map_err(|_| { - CheckErrors::Expects( + CheckErrorKind::Expects( "FATAL: bad type signature for pox addr".into(), ) })?, ), 2, ) - .map_err(|_| CheckErrors::Expects("FATAL: bad list type signature".into()))?, + .map_err(|_| { + CheckErrorKind::Expects("FATAL: bad list type signature".into()) + })?, ), ("payout".into(), TypeSignature::UIntType), ]) - .map_err(|_| CheckErrors::Expects("FATAL: bad type signature for pox addr".into()))? + .map_err(|_| CheckErrorKind::Expects("FATAL: bad type signature for pox addr".into()))? .into(), }; Ok(result) diff --git a/clarity/src/vm/types/serialization.rs b/clarity/src/vm/types/serialization.rs index 16e62f24099..e0d2cf8703b 100644 --- a/clarity/src/vm/types/serialization.rs +++ b/clarity/src/vm/types/serialization.rs @@ -22,7 +22,7 @@ pub use clarity_types::types::serialization::{ use stacks_common::util::hash::{hex_bytes, to_hex}; use crate::vm::database::{ClarityDeserializable, ClaritySerializable}; -use crate::vm::errors::{Error as ClarityError, InterpreterError}; +use crate::vm::errors::{VmExecutionError, VmInternalError}; impl ClaritySerializable for u32 { fn serialize(&self) -> String { @@ -31,13 +31,13 @@ impl ClaritySerializable for u32 { } impl ClarityDeserializable for u32 { - fn deserialize(input: &str) -> Result { + fn deserialize(input: &str) -> Result { let bytes = hex_bytes(input).map_err(|_| { - InterpreterError::Expect("u32 deserialization: failed decoding bytes.".into()) + VmInternalError::Expect("u32 deserialization: failed decoding bytes.".into()) })?; assert_eq!(bytes.len(), 4); Ok(u32::from_be_bytes(bytes[0..4].try_into().map_err( - |_| InterpreterError::Expect("u32 deserialization: failed reading.".into()), + |_| VmInternalError::Expect("u32 deserialization: failed reading.".into()), )?)) } } diff --git a/clarity/src/vm/types/signatures.rs b/clarity/src/vm/types/signatures.rs index f7854dfc75d..e2672a2b2cc 100644 --- a/clarity/src/vm/types/signatures.rs +++ b/clarity/src/vm/types/signatures.rs @@ -27,7 +27,7 @@ use stacks_common::types::StacksEpochId; use self::TypeSignature::SequenceType; use crate::vm::analysis::type_checker::v2_1::{MAX_FUNCTION_PARAMETERS, MAX_TRAIT_METHODS}; use crate::vm::costs::{runtime_cost, CostOverflowingMath}; -use crate::vm::errors::{CheckErrors, SyntaxBindingError, SyntaxBindingErrorType}; +use crate::vm::errors::{CheckErrorKind, SyntaxBindingError, SyntaxBindingErrorType}; use crate::vm::representations::{ ClarityName, SymbolicExpression, SymbolicExpressionType, TraitDefinition, }; @@ -163,58 +163,59 @@ impl From for FunctionSignature { /// This is not included in clarity-types because it requires the /// [`CostTracker`] trait. pub trait TypeSignatureExt { - fn parse_atom_type(typename: &str) -> Result; + fn parse_atom_type(typename: &str) -> Result; fn parse_list_type_repr( epoch: StacksEpochId, type_args: &[SymbolicExpression], accounting: &mut A, - ) -> Result; + ) -> Result; fn parse_tuple_type_repr( epoch: StacksEpochId, type_args: &[SymbolicExpression], accounting: &mut A, - ) -> Result; - fn parse_buff_type_repr(type_args: &[SymbolicExpression]) - -> Result; + ) -> Result; + fn parse_buff_type_repr( + type_args: &[SymbolicExpression], + ) -> Result; fn parse_string_utf8_type_repr( type_args: &[SymbolicExpression], - ) -> Result; + ) -> Result; fn parse_string_ascii_type_repr( type_args: &[SymbolicExpression], - ) -> Result; + ) -> Result; fn parse_optional_type_repr( epoch: StacksEpochId, type_args: &[SymbolicExpression], accounting: &mut A, - ) -> Result; + ) -> Result; fn parse_response_type_repr( epoch: StacksEpochId, type_args: &[SymbolicExpression], accounting: &mut A, - ) -> Result; + ) -> Result; fn parse_type_repr( epoch: StacksEpochId, x: &SymbolicExpression, accounting: &mut A, - ) -> Result; + ) -> Result; fn parse_trait_type_repr( type_args: &[SymbolicExpression], accounting: &mut A, epoch: StacksEpochId, clarity_version: ClarityVersion, - ) -> Result, CheckErrors>; + ) -> Result, CheckErrorKind>; #[cfg(test)] fn from_string(val: &str, version: ClarityVersion, epoch: StacksEpochId) -> Self; } impl TypeSignatureExt for TypeSignature { - fn parse_atom_type(typename: &str) -> Result { + fn parse_atom_type(typename: &str) -> Result { match typename { "int" => Ok(TypeSignature::IntType), "uint" => Ok(TypeSignature::UIntType), "bool" => Ok(TypeSignature::BoolType), "principal" => Ok(TypeSignature::PrincipalType), - _ => Err(CheckErrors::UnknownTypeName(typename.into())), + _ => Err(CheckErrorKind::UnknownTypeName(typename.into())), } } @@ -224,18 +225,18 @@ impl TypeSignatureExt for TypeSignature { epoch: StacksEpochId, type_args: &[SymbolicExpression], accounting: &mut A, - ) -> Result { + ) -> Result { if type_args.len() != 2 { - return Err(CheckErrors::InvalidTypeDescription); + return Err(CheckErrorKind::InvalidTypeDescription); } if let SymbolicExpressionType::LiteralValue(Value::Int(max_len)) = &type_args[0].expr { let atomic_type_arg = &type_args[type_args.len() - 1]; let entry_type = TypeSignature::parse_type_repr(epoch, atomic_type_arg, accounting)?; - let max_len = u32::try_from(*max_len).map_err(|_| CheckErrors::ValueTooLarge)?; + let max_len = u32::try_from(*max_len).map_err(|_| CheckErrorKind::ValueTooLarge)?; ListTypeData::new_list(entry_type, max_len).map(|x| x.into()) } else { - Err(CheckErrors::InvalidTypeDescription) + Err(CheckErrorKind::InvalidTypeDescription) } } @@ -245,8 +246,8 @@ impl TypeSignatureExt for TypeSignature { epoch: StacksEpochId, type_args: &[SymbolicExpression], accounting: &mut A, - ) -> Result { - let mapped_key_types = parse_name_type_pairs::<_, CheckErrors>( + ) -> Result { + let mapped_key_types = parse_name_type_pairs::<_, CheckErrorKind>( epoch, type_args, SyntaxBindingErrorType::TupleCons, @@ -260,15 +261,15 @@ impl TypeSignatureExt for TypeSignature { // (buff 10) fn parse_buff_type_repr( type_args: &[SymbolicExpression], - ) -> Result { + ) -> Result { if type_args.len() != 1 { - return Err(CheckErrors::InvalidTypeDescription); + return Err(CheckErrorKind::InvalidTypeDescription); } if let SymbolicExpressionType::LiteralValue(Value::Int(buff_len)) = &type_args[0].expr { BufferLength::try_from(*buff_len) .map(|buff_len| SequenceType(SequenceSubtype::BufferType(buff_len))) } else { - Err(CheckErrors::InvalidTypeDescription) + Err(CheckErrorKind::InvalidTypeDescription) } } @@ -276,16 +277,16 @@ impl TypeSignatureExt for TypeSignature { // (string-utf8 10) fn parse_string_utf8_type_repr( type_args: &[SymbolicExpression], - ) -> Result { + ) -> Result { if type_args.len() != 1 { - return Err(CheckErrors::InvalidTypeDescription); + return Err(CheckErrorKind::InvalidTypeDescription); } if let SymbolicExpressionType::LiteralValue(Value::Int(utf8_len)) = &type_args[0].expr { StringUTF8Length::try_from(*utf8_len).map(|utf8_len| { SequenceType(SequenceSubtype::StringType(StringSubtype::UTF8(utf8_len))) }) } else { - Err(CheckErrors::InvalidTypeDescription) + Err(CheckErrorKind::InvalidTypeDescription) } } @@ -293,16 +294,16 @@ impl TypeSignatureExt for TypeSignature { // (string-ascii 10) fn parse_string_ascii_type_repr( type_args: &[SymbolicExpression], - ) -> Result { + ) -> Result { if type_args.len() != 1 { - return Err(CheckErrors::InvalidTypeDescription); + return Err(CheckErrorKind::InvalidTypeDescription); } if let SymbolicExpressionType::LiteralValue(Value::Int(buff_len)) = &type_args[0].expr { BufferLength::try_from(*buff_len).map(|buff_len| { SequenceType(SequenceSubtype::StringType(StringSubtype::ASCII(buff_len))) }) } else { - Err(CheckErrors::InvalidTypeDescription) + Err(CheckErrorKind::InvalidTypeDescription) } } @@ -310,9 +311,9 @@ impl TypeSignatureExt for TypeSignature { epoch: StacksEpochId, type_args: &[SymbolicExpression], accounting: &mut A, - ) -> Result { + ) -> Result { if type_args.len() != 1 { - return Err(CheckErrors::InvalidTypeDescription); + return Err(CheckErrorKind::InvalidTypeDescription); } let inner_type = TypeSignature::parse_type_repr(epoch, &type_args[0], accounting)?; @@ -323,9 +324,9 @@ impl TypeSignatureExt for TypeSignature { epoch: StacksEpochId, type_args: &[SymbolicExpression], accounting: &mut A, - ) -> Result { + ) -> Result { if type_args.len() != 2 { - return Err(CheckErrors::InvalidTypeDescription); + return Err(CheckErrorKind::InvalidTypeDescription); } let ok_type = TypeSignature::parse_type_repr(epoch, &type_args[0], accounting)?; let err_type = TypeSignature::parse_type_repr(epoch, &type_args[1], accounting)?; @@ -336,7 +337,7 @@ impl TypeSignatureExt for TypeSignature { epoch: StacksEpochId, x: &SymbolicExpression, accounting: &mut A, - ) -> Result { + ) -> Result { runtime_cost(ClarityCostFunction::TypeParseStep, accounting, 0)?; match x.expr { @@ -347,7 +348,7 @@ impl TypeSignatureExt for TypeSignature { SymbolicExpressionType::List(ref list_contents) => { let (compound_type, rest) = list_contents .split_first() - .ok_or(CheckErrors::InvalidTypeDescription)?; + .ok_or(CheckErrorKind::InvalidTypeDescription)?; if let SymbolicExpressionType::Atom(ref compound_type) = compound_type.expr { match compound_type.as_ref() { "list" => TypeSignature::parse_list_type_repr(epoch, rest, accounting), @@ -361,10 +362,10 @@ impl TypeSignatureExt for TypeSignature { "response" => { TypeSignature::parse_response_type_repr(epoch, rest, accounting) } - _ => Err(CheckErrors::InvalidTypeDescription), + _ => Err(CheckErrorKind::InvalidTypeDescription), } } else { - Err(CheckErrors::InvalidTypeDescription) + Err(CheckErrorKind::InvalidTypeDescription) } } SymbolicExpressionType::TraitReference(_, ref trait_definition) @@ -389,7 +390,7 @@ impl TypeSignatureExt for TypeSignature { )), } } - _ => Err(CheckErrors::InvalidTypeDescription), + _ => Err(CheckErrorKind::InvalidTypeDescription), } } @@ -398,17 +399,25 @@ impl TypeSignatureExt for TypeSignature { accounting: &mut A, epoch: StacksEpochId, clarity_version: ClarityVersion, - ) -> Result, CheckErrors> { + ) -> Result, CheckErrorKind> { let mut trait_signature: BTreeMap = BTreeMap::new(); let functions_types = type_args .first() - .ok_or_else(|| CheckErrors::InvalidTypeDescription)? + .ok_or_else(|| CheckErrorKind::InvalidTypeDescription)? .match_list() - .ok_or(CheckErrors::DefineTraitBadSignature)?; + .ok_or(CheckErrorKind::DefineTraitBadSignature)?; + + // Check the method count against the maximum allowed + if epoch.limits_parameter_and_method_count() && functions_types.len() > MAX_TRAIT_METHODS { + return Err(CheckErrorKind::TraitTooManyMethods( + functions_types.len(), + MAX_TRAIT_METHODS, + )); + } // Check the method count against the maximum allowed if epoch.limits_parameter_and_method_count() && functions_types.len() > MAX_TRAIT_METHODS { - return Err(CheckErrors::TraitTooManyMethods( + return Err(CheckErrorKind::TraitTooManyMethods( functions_types.len(), MAX_TRAIT_METHODS, )); @@ -417,26 +426,26 @@ impl TypeSignatureExt for TypeSignature { for function_type in functions_types.iter() { let args = function_type .match_list() - .ok_or(CheckErrors::DefineTraitBadSignature)?; + .ok_or(CheckErrorKind::DefineTraitBadSignature)?; if args.len() != 3 { - return Err(CheckErrors::InvalidTypeDescription); + return Err(CheckErrorKind::InvalidTypeDescription); } // Extract function's name let fn_name = args[0] .match_atom() - .ok_or(CheckErrors::DefineTraitBadSignature)?; + .ok_or(CheckErrorKind::DefineTraitBadSignature)?; // Extract function's arguments let fn_args_exprs = args[1] .match_list() - .ok_or(CheckErrors::DefineTraitBadSignature)?; + .ok_or(CheckErrorKind::DefineTraitBadSignature)?; // Check the argument count against the maximum allowed if epoch.limits_parameter_and_method_count() && fn_args_exprs.len() > MAX_FUNCTION_PARAMETERS { - return Err(CheckErrors::TooManyFunctionParameters( + return Err(CheckErrorKind::TooManyFunctionParameters( fn_args_exprs.len(), MAX_FUNCTION_PARAMETERS, )); @@ -445,15 +454,15 @@ impl TypeSignatureExt for TypeSignature { let fn_args = fn_args_exprs .iter() .map(|arg_type| TypeSignature::parse_type_repr(epoch, arg_type, accounting)) - .collect::>()?; + .collect::>()?; // Extract function's type return - must be a response let fn_return = match TypeSignature::parse_type_repr(epoch, &args[2], accounting) { Ok(response) => match response { TypeSignature::ResponseType(_) => Ok(response), - _ => Err(CheckErrors::DefineTraitBadSignature), + _ => Err(CheckErrorKind::DefineTraitBadSignature), }, - _ => Err(CheckErrors::DefineTraitBadSignature), + _ => Err(CheckErrorKind::DefineTraitBadSignature), }?; if trait_signature @@ -467,7 +476,9 @@ impl TypeSignatureExt for TypeSignature { .is_some() && clarity_version >= ClarityVersion::Clarity2 { - return Err(CheckErrors::DefineTraitDuplicateMethod(fn_name.to_string())); + return Err(CheckErrorKind::DefineTraitDuplicateMethod( + fn_name.to_string(), + )); } } Ok(trait_signature) @@ -490,7 +501,7 @@ impl TypeSignatureExt for TypeSignature { } impl FixedFunction { - pub fn total_type_size(&self) -> Result { + pub fn total_type_size(&self) -> Result { let mut function_type_size = u64::from(self.returns.type_size()?); for arg in self.args.iter() { function_type_size = @@ -501,7 +512,7 @@ impl FixedFunction { } impl FunctionSignature { - pub fn total_type_size(&self) -> Result { + pub fn total_type_size(&self) -> Result { let mut function_type_size = u64::from(self.returns.type_size()?); for arg in self.args.iter() { function_type_size = @@ -514,7 +525,7 @@ impl FunctionSignature { &self, epoch: &StacksEpochId, args: Vec, - ) -> Result { + ) -> Result { if args.len() != self.args.len() { return Ok(false); } @@ -563,7 +574,7 @@ pub fn parse_name_type_pairs( accounting: &mut A, ) -> Result, E> where - E: for<'a> From<(CheckErrors, &'a SymbolicExpression)>, + E: for<'a> From<(CheckErrorKind, &'a SymbolicExpression)>, { // this is a pretty deep nesting here, but what we're trying to do is pick out the values of // the form: @@ -572,14 +583,14 @@ where use crate::vm::representations::SymbolicExpressionType::List; // step 1: parse it into a vec of symbolicexpression pairs. - let as_pairs: Result, (CheckErrors, &SymbolicExpression)> = name_type_pairs + let as_pairs: Result, (CheckErrorKind, &SymbolicExpression)> = name_type_pairs .iter() .enumerate() .map(|(i, key_type_pair)| { if let List(ref as_vec) = key_type_pair.expr { if as_vec.len() != 2 { Err(( - CheckErrors::BadSyntaxBinding(SyntaxBindingError::InvalidLength( + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::InvalidLength( binding_error_type, i, )), @@ -598,7 +609,7 @@ where .collect(); // step 2: turn into a vec of (name, typesignature) pairs. - let key_types: Result, (CheckErrors, &SymbolicExpression)> = (as_pairs?) + let key_types: Result, (CheckErrorKind, &SymbolicExpression)> = (as_pairs?) .iter() .enumerate() .map(|(i, (name_symbol, type_symbol))| { @@ -606,7 +617,7 @@ where .match_atom() .ok_or_else(|| { ( - CheckErrors::BadSyntaxBinding(SyntaxBindingError::NotAtom( + CheckErrorKind::BadSyntaxBinding(SyntaxBindingError::NotAtom( binding_error_type, i, )), @@ -637,13 +648,13 @@ mod test { use rstest_reuse::{self, *}; use stacks_common::types::StacksEpochId; - use super::CheckErrors::*; + use super::CheckErrorKind::*; use super::*; use crate::vm::tests::test_clarity_versions; use crate::vm::types::QualifiedContractIdentifier; use crate::vm::{execute, ClarityVersion}; - fn fail_parse(val: &str, version: ClarityVersion, epoch: StacksEpochId) -> CheckErrors { + fn fail_parse(val: &str, version: ClarityVersion, epoch: StacksEpochId) -> CheckErrorKind { use crate::vm::ast::parse; let expr = &parse( &QualifiedContractIdentifier::transient(), diff --git a/clarity/src/vm/variables.rs b/clarity/src/vm/variables.rs index d84be69215f..b450bd9c157 100644 --- a/clarity/src/vm/variables.rs +++ b/clarity/src/vm/variables.rs @@ -17,11 +17,11 @@ use clarity_types::types::PrincipalData; use stacks_common::types::StacksEpochId; -use super::errors::InterpreterError; +use super::errors::VmInternalError; use crate::vm::contexts::{Environment, LocalContext}; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::costs::runtime_cost; -use crate::vm::errors::{InterpreterResult as Result, RuntimeErrorType}; +use crate::vm::errors::{RuntimeError, VmExecutionError}; use crate::vm::types::Value; use crate::vm::ClarityVersion; @@ -52,30 +52,24 @@ pub fn lookup_reserved_variable( name: &str, _context: &LocalContext, env: &mut Environment, -) -> Result> { +) -> Result, VmExecutionError> { if let Some(variable) = NativeVariables::lookup_by_name_at_version(name, env.contract_context.get_clarity_version()) { match variable { NativeVariables::TxSender => { - let sender = env - .sender - .clone() - .ok_or(RuntimeErrorType::NoSenderInContext)?; + let sender = env.sender.clone().ok_or(RuntimeError::NoSenderInContext)?; Ok(Some(Value::Principal(sender))) } NativeVariables::ContractCaller => { - let caller = env - .caller - .clone() - .ok_or(RuntimeErrorType::NoCallerInContext)?; + let caller = env.caller.clone().ok_or(RuntimeError::NoCallerInContext)?; Ok(Some(Value::Principal(caller))) } NativeVariables::TxSponsor => { let sponsor = match env.sponsor.clone() { None => Value::none(), Some(p) => Value::some(Value::Principal(p)).map_err(|_| { - InterpreterError::Expect( + VmInternalError::Expect( "ERROR: principal should be a valid Clarity object".into(), ) })?, diff --git a/clarity/src/vm/version.rs b/clarity/src/vm/version.rs index 445a957d2d2..8b38563c41d 100644 --- a/clarity/src/vm/version.rs +++ b/clarity/src/vm/version.rs @@ -3,8 +3,6 @@ use std::str::FromStr; use stacks_common::types::StacksEpochId; -use crate::vm::errors::{Error, RuntimeErrorType}; - #[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, PartialOrd)] pub enum ClarityVersion { Clarity1, @@ -58,9 +56,9 @@ impl ClarityVersion { } impl FromStr for ClarityVersion { - type Err = Error; + type Err = &'static str; - fn from_str(version: &str) -> Result { + fn from_str(version: &str) -> Result { let s = version.to_string().to_lowercase(); if s == "clarity1" { Ok(ClarityVersion::Clarity1) @@ -71,11 +69,7 @@ impl FromStr for ClarityVersion { } else if s == "clarity4" { Ok(ClarityVersion::Clarity4) } else { - Err(RuntimeErrorType::ParseError( - "Invalid clarity version. Valid versions are: Clarity1, Clarity2, Clarity3." - .to_string(), - ) - .into()) + Err("Invalid clarity version. Valid versions are: Clarity1, Clarity2, Clarity3, Clarity4.") } } } diff --git a/contrib/clarity-cli/Cargo.toml b/contrib/clarity-cli/Cargo.toml new file mode 100644 index 00000000000..1075c774d00 --- /dev/null +++ b/contrib/clarity-cli/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "clarity-cli" +version = "0.1.0" +edition = "2024" + +[dependencies] +clarity = { path = "../../clarity", default-features = false } +stackslib = { package = "stackslib", path = "../../stackslib", default-features = false } +stacks-common = { path = "../../stacks-common", default-features = false } +slog = { version = "2.5.2", features = [ "max_level_trace" ] } +lazy_static = { version = "1.4.0", default-features = false } +serde = { version = "1" } +serde_derive = "1" +serde_json = { workspace = true } +rand = { workspace = true } +rusqlite = { workspace = true } + +[dev-dependencies] +stacks-common = { path = "../../stacks-common", default-features = false, features = ["testing"] } diff --git a/contrib/clarity-cli/README.md b/contrib/clarity-cli/README.md new file mode 100644 index 00000000000..32ed0a6690a --- /dev/null +++ b/contrib/clarity-cli/README.md @@ -0,0 +1,15 @@ +# clarity-cli + +A thin wrapper executable for the Clarity CLI exposed by `blockstack_lib::clarity_cli`. It forwards argv to the library, prints JSON output, and exits with the underlying status code. + +Build: +```bash +cargo build -p clarity-cli +``` + +Usage: +```bash +./target/debug/clarity-cli --help +``` + +For advanced usage and subcommands, see the upstream Clarity CLI documentation or run with `--help`. diff --git a/stackslib/src/clarity_cli.rs b/contrib/clarity-cli/src/lib.rs similarity index 84% rename from stackslib/src/clarity_cli.rs rename to contrib/clarity-cli/src/lib.rs index 4bb303bda76..b029bb03bd2 100644 --- a/stackslib/src/clarity_cli.rs +++ b/contrib/clarity-cli/src/lib.rs @@ -14,7 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::ffi::OsStr; +#[macro_use] +extern crate serde_derive; + use std::io::{Read, Write}; use std::path::PathBuf; use std::{fs, io}; @@ -27,42 +29,42 @@ use serde::Serialize; use serde_json::json; use stacks_common::address::c32::c32_address; use stacks_common::consts::{CHAIN_ID_MAINNET, CHAIN_ID_TESTNET}; +use stacks_common::debug; use stacks_common::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, ConsensusHash, StacksAddress, StacksBlockId, VRFSeed, }; use stacks_common::types::sqlite::NO_PARAMS; use stacks_common::util::get_epoch_time_ms; -use stacks_common::util::hash::{bytes_to_hex, Hash160, Sha512Trunc256Sum}; - -use crate::burnchains::{PoxConstants, Txid}; -use crate::chainstate::stacks::boot::{ - BOOT_CODE_BNS, BOOT_CODE_COSTS, BOOT_CODE_COSTS_2, BOOT_CODE_COSTS_2_TESTNET, - BOOT_CODE_COSTS_3, BOOT_CODE_COSTS_4, BOOT_CODE_COST_VOTING_MAINNET, - BOOT_CODE_COST_VOTING_TESTNET, BOOT_CODE_GENESIS, BOOT_CODE_LOCKUP, BOOT_CODE_POX_MAINNET, - BOOT_CODE_POX_TESTNET, POX_2_MAINNET_CODE, POX_2_TESTNET_CODE, +use stacks_common::util::hash::{Hash160, Sha512Trunc256Sum, bytes_to_hex}; +use stackslib::burnchains::{PoxConstants, Txid}; +use stackslib::chainstate::stacks::boot::{ + BOOT_CODE_BNS, BOOT_CODE_COST_VOTING_MAINNET, BOOT_CODE_COST_VOTING_TESTNET, BOOT_CODE_COSTS, + BOOT_CODE_COSTS_2, BOOT_CODE_COSTS_2_TESTNET, BOOT_CODE_COSTS_3, BOOT_CODE_COSTS_4, + BOOT_CODE_GENESIS, BOOT_CODE_LOCKUP, BOOT_CODE_POX_MAINNET, BOOT_CODE_POX_TESTNET, + POX_2_MAINNET_CODE, POX_2_TESTNET_CODE, }; -use crate::chainstate::stacks::index::ClarityMarfTrieId; -use crate::clarity::vm::analysis::contract_interface_builder::build_contract_interface; -use crate::clarity::vm::analysis::errors::CheckError; -use crate::clarity::vm::analysis::{AnalysisDatabase, ContractAnalysis}; -use crate::clarity::vm::ast::build_ast; -use crate::clarity::vm::contexts::{AssetMap, GlobalContext, OwnedEnvironment}; -use crate::clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; -use crate::clarity::vm::database::{ - BurnStateDB, ClarityDatabase, HeadersDB, STXBalance, NULL_BURN_STATE_DB, +use stackslib::chainstate::stacks::index::ClarityMarfTrieId; +use stackslib::clarity::vm::analysis::contract_interface_builder::build_contract_interface; +use stackslib::clarity::vm::analysis::errors::StaticCheckError; +use stackslib::clarity::vm::analysis::{AnalysisDatabase, ContractAnalysis}; +use stackslib::clarity::vm::ast::build_ast; +use stackslib::clarity::vm::contexts::{AssetMap, GlobalContext, OwnedEnvironment}; +use stackslib::clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; +use stackslib::clarity::vm::database::{ + BurnStateDB, ClarityDatabase, HeadersDB, NULL_BURN_STATE_DB, STXBalance, }; -use crate::clarity::vm::errors::{Error, InterpreterResult, RuntimeErrorType}; -use crate::clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; -use crate::clarity::vm::{ - analysis, ast, eval_all, ClarityVersion, ContractContext, ContractName, SymbolicExpression, - Value, +use stackslib::clarity::vm::errors::{RuntimeError, VmExecutionError}; +use stackslib::clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; +use stackslib::clarity::vm::{ + ClarityVersion, ContractContext, ContractName, SymbolicExpression, Value, analysis, ast, + eval_all, }; -use crate::clarity_vm::clarity::{ClarityMarfStore, ClarityMarfStoreTransaction}; -use crate::clarity_vm::database::marf::{MarfedKV, PersistentWritableMarfStore}; -use crate::clarity_vm::database::MemoryBackingStore; -use crate::core::{StacksEpochId, BLOCK_LIMIT_MAINNET_205, HELIUM_BLOCK_LIMIT_20}; -use crate::util_lib::boot::{boot_code_addr, boot_code_id}; -use crate::util_lib::db::{sqlite_open, FromColumn}; +use stackslib::clarity_vm::clarity::{ClarityMarfStore, ClarityMarfStoreTransaction}; +use stackslib::clarity_vm::database::MemoryBackingStore; +use stackslib::clarity_vm::database::marf::{MarfedKV, PersistentWritableMarfStore}; +use stackslib::core::{BLOCK_LIMIT_MAINNET_205, HELIUM_BLOCK_LIMIT_20, StacksEpochId}; +use stackslib::util_lib::boot::{boot_code_addr, boot_code_id}; +use stackslib::util_lib::db::{FromColumn, sqlite_open}; lazy_static! { pub static ref STACKS_BOOT_CODE_MAINNET_2_1: [(&'static str, &'static str); 10] = [ @@ -106,7 +108,7 @@ macro_rules! panic_test { fn print_usage(invoked_by: &str) { eprintln!( - "Usage: {} [command] + "Usage: {invoked_by} [command] where command is one of: initialize to initialize a local VM state database. @@ -116,26 +118,25 @@ where command is one of: eval_at_chaintip like `eval`, but does not advance to a new block. eval_at_block like `eval_at_chaintip`, but accepts a index-block-hash to evaluate at, must be passed eval string via stdin. - eval_raw to typecheck and evaluate an expression without a contract or database context. + eval_raw to typecheck and evaluate an expression without a contract or database context from stdin. repl to typecheck and evaluate expressions in a stdin/stdout loop. execute to execute a public function of a defined contract. generate_address to generate a random Stacks public address for testing purposes. -", - invoked_by +" ); panic_test!() } fn friendly_expect(input: Result, msg: &str) -> A { input.unwrap_or_else(|e| { - eprintln!("{}\nCaused by: {}", msg, e); + eprintln!("{msg}\nCaused by: {e}"); panic_test!(); }) } fn friendly_expect_opt(input: Option, msg: &str) -> A { input.unwrap_or_else(|| { - eprintln!("{}", msg); + eprintln!("{msg}"); panic_test!(); }) } @@ -143,6 +144,7 @@ fn friendly_expect_opt(input: Option, msg: &str) -> A { pub const DEFAULT_CLI_EPOCH: StacksEpochId = StacksEpochId::Epoch33; struct EvalInput { + #[allow(dead_code)] marf_kv: MarfedKV, contract_identifier: QualifiedContractIdentifier, content: String, @@ -152,15 +154,16 @@ fn parse( contract_identifier: &QualifiedContractIdentifier, source_code: &str, clarity_version: ClarityVersion, -) -> Result, Error> { + epoch: StacksEpochId, +) -> Result, VmExecutionError> { let ast = build_ast( contract_identifier, source_code, &mut (), clarity_version, - DEFAULT_CLI_EPOCH, + epoch, ) - .map_err(|e| RuntimeErrorType::ASTError(Box::new(e)))?; + .map_err(|e| RuntimeError::ASTError(Box::new(e)))?; Ok(ast.expressions) } @@ -207,14 +210,15 @@ fn run_analysis_free( marf_kv: &mut C, save_contract: bool, clarity_version: ClarityVersion, -) -> Result> { + epoch: StacksEpochId, +) -> Result> { analysis::run_analysis( contract_identifier, expressions, &mut marf_kv.get_analysis_db(), save_contract, LimitedCostTracker::new_free(), - DEFAULT_CLI_EPOCH, + epoch, clarity_version, // no type map data is used in the clarity_cli false, @@ -228,7 +232,8 @@ fn run_analysis( marf_kv: &mut C, save_contract: bool, clarity_version: ClarityVersion, -) -> Result> { + epoch: StacksEpochId, +) -> Result> { let mainnet = header_db.is_mainnet(); let cost_track = LimitedCostTracker::new( mainnet, @@ -239,7 +244,7 @@ fn run_analysis( HELIUM_BLOCK_LIMIT_20 }, &mut marf_kv.get_clarity_db(header_db, &NULL_BURN_STATE_DB), - DEFAULT_CLI_EPOCH, + epoch, ) .unwrap(); analysis::run_analysis( @@ -248,7 +253,7 @@ fn run_analysis( &mut marf_kv.get_analysis_db(), save_contract, cost_track, - DEFAULT_CLI_EPOCH, + epoch, clarity_version, // no type map data is used in the clarity_cli false, @@ -271,7 +276,7 @@ fn create_or_open_db(path: &String) -> Connection { } OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE } else { - panic!("FATAL: could not stat {}", path); + panic!("FATAL: could not stat {path}"); } } Ok(_md) => { @@ -281,11 +286,10 @@ fn create_or_open_db(path: &String) -> Connection { } }; - let conn = friendly_expect( + friendly_expect( sqlite_open(path, open_flags, false), - &format!("FATAL: failed to open '{}'", path), - ); - conn + &format!("FATAL: failed to open '{path}'"), + ) } fn get_cli_chain_tip(conn: &Connection) -> StacksBlockId { @@ -313,16 +317,11 @@ fn get_cli_block_height(conn: &Connection, block_id: &StacksBlockId) -> Option String { @@ -332,11 +331,11 @@ fn get_cli_db_path(db_path: &str) -> String { let mut cli_db_path_buf = PathBuf::from(db_path); cli_db_path_buf.push("cli.sqlite"); - let cli_db_path = cli_db_path_buf + + cli_db_path_buf .to_str() - .unwrap_or_else(|| panic!("FATAL: failed to convert '{}' to a string", db_path)) - .to_string(); - cli_db_path + .unwrap_or_else(|| panic!("FATAL: failed to convert '{db_path}' to a string")) + .to_string() } // This function is pretty weird! But it helps cut down on @@ -399,16 +398,16 @@ where } fn default_chain_id(mainnet: bool) -> u32 { - let chain_id = if mainnet { + if mainnet { CHAIN_ID_MAINNET } else { CHAIN_ID_TESTNET - }; - chain_id + } } fn with_env_costs( mainnet: bool, + epoch: StacksEpochId, header_db: &CLIHeadersDB, marf: &mut PersistentWritableMarfStore, coverage: Option<&mut CoverageReporter>, @@ -427,7 +426,7 @@ where HELIUM_BLOCK_LIMIT_20 }, &mut db, - DEFAULT_CLI_EPOCH, + epoch, ) .unwrap(); let mut vm_env = OwnedEnvironment::new_cost_limited( @@ -435,7 +434,7 @@ where default_chain_id(mainnet), db, cost_track, - DEFAULT_CLI_EPOCH, + epoch, ); if let Some(coverage) = coverage { vm_env.add_eval_hook(coverage); @@ -447,7 +446,36 @@ where /// Execute program in a transient environment. To be used only by CLI tools /// for program evaluation, not by consensus critical code. -pub fn vm_execute(program: &str, clarity_version: ClarityVersion) -> Result, Error> { +pub fn vm_execute_in_epoch( + program: &str, + clarity_version: ClarityVersion, + epoch: StacksEpochId, +) -> Result, VmExecutionError> { + let contract_id = QualifiedContractIdentifier::transient(); + let mut contract_context = ContractContext::new(contract_id.clone(), clarity_version); + let mut marf = MemoryBackingStore::new(); + let conn = marf.as_clarity_db(); + let mut global_context = GlobalContext::new( + false, + default_chain_id(false), + conn, + LimitedCostTracker::new_free(), + epoch, + ); + global_context.execute(|g| { + let parsed = + ast::build_ast(&contract_id, program, &mut (), clarity_version, epoch)?.expressions; + eval_all(&parsed, &mut contract_context, g, None) + }) +} + +/// Execute program in a transient environment in the latest epoch. +/// To be used only by CLI tools for program evaluation, not by consensus +/// critical code. +pub fn vm_execute( + program: &str, + clarity_version: ClarityVersion, +) -> Result, VmExecutionError> { let contract_id = QualifiedContractIdentifier::transient(); let mut contract_context = ContractContext::new(contract_id.clone(), clarity_version); let mut marf = MemoryBackingStore::new(); @@ -457,7 +485,7 @@ pub fn vm_execute(program: &str, clarity_version: ClarityVersion) -> Result Result { let mut coverage_file = PathBuf::from(coverage_folder); - coverage_file.push(&format!("{}_{}", prefix, get_epoch_time_ms())); + coverage_file.push(format!("{prefix}_{}", get_epoch_time_ms())); coverage_file.set_extension("clarcov"); coverage @@ -503,7 +531,7 @@ impl CLIHeadersDB { let cli_db_path = self.get_cli_db_path(); let tx = friendly_expect( self.conn.transaction(), - &format!("FATAL: failed to begin transaction on '{}'", cli_db_path), + &format!("FATAL: failed to begin transaction on '{cli_db_path}'"), ); friendly_expect( @@ -524,7 +552,7 @@ impl CLIHeadersDB { if !mainnet { friendly_expect( - tx.execute("INSERT INTO cli_config (testnet) VALUES (?1)", &[&true]), + tx.execute("INSERT INTO cli_config (testnet) VALUES (?1)", [&true]), "FATAL: failed to set testnet flag", ); } @@ -537,7 +565,7 @@ impl CLIHeadersDB { /// Create or open a new CLI DB at db_path. If it already exists, then this method is a no-op. pub fn new(db_path: &str, mainnet: bool) -> CLIHeadersDB { - let instantiate = db_path == ":memory:" || fs::metadata(&db_path).is_err(); + let instantiate = db_path == ":memory:" || fs::metadata(db_path).is_err(); let cli_db_path = get_cli_db_path(db_path); let conn = create_or_open_db(&cli_db_path); @@ -571,8 +599,7 @@ impl CLIHeadersDB { /// Make a new CLI DB in memory. pub fn new_memory(mainnet: bool) -> CLIHeadersDB { - let db = CLIHeadersDB::new(":memory:", mainnet); - db + CLIHeadersDB::new(":memory:", mainnet) } fn get_cli_db_path(&self) -> String { @@ -605,7 +632,7 @@ impl CLIHeadersDB { let parent_block_hash = get_cli_chain_tip(&tx); - let random_bytes = rand::thread_rng().gen::<[u8; 32]>(); + let random_bytes = rand::thread_rng().r#gen::<[u8; 32]>(); let next_block_hash = friendly_expect_opt( StacksBlockId::from_bytes(&random_bytes), "Failed to generate random block header.", @@ -614,7 +641,7 @@ impl CLIHeadersDB { friendly_expect( tx.execute( "INSERT INTO cli_chain_tips (block_hash) VALUES (?1)", - &[&next_block_hash], + [&next_block_hash], ), &format!( "FATAL: failed to store next block hash in '{}'", @@ -703,29 +730,17 @@ impl HeadersDB for CLIHeadersDB { _epoch: Option<&StacksEpochId>, ) -> Option { let conn = self.conn(); - if let Some(height) = get_cli_block_height(conn, id_bhh) { - Some(height * 600 + 1231006505) - } else { - None - } + get_cli_block_height(conn, id_bhh).map(|height| height * 600 + 1231006505) } fn get_stacks_block_time_for_block(&self, id_bhh: &StacksBlockId) -> Option { let conn = self.conn(); - if let Some(height) = get_cli_block_height(conn, id_bhh) { - Some(height * 10 + 1713799973) - } else { - None - } + get_cli_block_height(conn, id_bhh).map(|height| height * 10 + 1713799973) } fn get_burn_block_height_for_block(&self, id_bhh: &StacksBlockId) -> Option { let conn = self.conn(); - if let Some(height) = get_cli_block_height(conn, id_bhh) { - Some(height as u32) - } else { - None - } + get_cli_block_height(conn, id_bhh).map(|height| height as u32) } fn get_miner_address( @@ -775,8 +790,8 @@ impl HeadersDB for CLIHeadersDB { fn get_eval_input(invoked_by: &str, args: &[String]) -> EvalInput { if args.len() < 3 || args.len() > 4 { eprintln!( - "Usage: {} {} [--costs] [contract-identifier] (program.clar) [vm-state.db]", - invoked_by, args[0] + "Usage: {invoked_by} {} [--costs] [--epoch E] [--clarity_version N] [contract-identifier] (program.clar) [vm-state.db]", + args[0] ); panic_test!(); } @@ -809,11 +824,11 @@ fn get_eval_input(invoked_by: &str, args: &[String]) -> EvalInput { "Failed to open VM database.", ); // return (marf_kv, contract_identifier, vm_filename, content); - return EvalInput { + EvalInput { marf_kv, contract_identifier, content, - }; + } } #[derive(Serialize, Deserialize)] @@ -829,7 +844,7 @@ fn consume_arg( ) -> Result, String> { if let Some(ref switch) = args .iter() - .find(|ref arg| argnames.iter().find(|ref argname| argname == arg).is_some()) + .find(|ref arg| argnames.iter().any(|ref argname| argname == arg)) { let idx = args .iter() @@ -861,7 +876,11 @@ fn consume_arg( } /// This function uses Clarity1 to parse the boot code. -fn install_boot_code(header_db: &CLIHeadersDB, marf: &mut C) { +fn install_boot_code( + header_db: &CLIHeadersDB, + marf: &mut C, + epoch: StacksEpochId, +) { let mainnet = header_db.is_mainnet(); let boot_code = if mainnet { *STACKS_BOOT_CODE_MAINNET_2_1 @@ -871,18 +890,15 @@ fn install_boot_code(header_db: &CLIHeadersDB, marf: &mut C) { let db = marf.get_clarity_db(header_db, &NULL_BURN_STATE_DB); - let mut vm_env = - OwnedEnvironment::new_free(mainnet, default_chain_id(mainnet), db, DEFAULT_CLI_EPOCH); + let mut vm_env = OwnedEnvironment::new_free(mainnet, default_chain_id(mainnet), db, epoch); vm_env .execute_in_env( QualifiedContractIdentifier::transient().issuer.into(), None, None, |env| { - let res: InterpreterResult<_> = Ok(env - .global_context - .database - .set_clarity_epoch_version(DEFAULT_CLI_EPOCH)); + let res: Result<_, VmExecutionError> = + Ok(env.global_context.database.set_clarity_epoch_version(epoch)); res }, ) @@ -899,8 +915,7 @@ fn install_boot_code(header_db: &CLIHeadersDB, marf: &mut C) let contract_content = *boot_code_contract; debug!( - "Instantiate boot code contract '{}' ({} bytes)...", - &contract_identifier, + "Instantiate boot code contract '{contract_identifier}' ({} bytes)...", boot_code_contract.len() ); @@ -909,6 +924,7 @@ fn install_boot_code(header_db: &CLIHeadersDB, marf: &mut C) &contract_identifier, contract_content, ClarityVersion::Clarity1, + epoch, ), "Failed to parse program.", ); @@ -919,16 +935,13 @@ fn install_boot_code(header_db: &CLIHeadersDB, marf: &mut C) marf, true, ClarityVersion::Clarity2, + epoch, ); match analysis_result { Ok(_) => { let db = marf.get_clarity_db(header_db, &NULL_BURN_STATE_DB); - let mut vm_env = OwnedEnvironment::new_free( - mainnet, - default_chain_id(mainnet), - db, - DEFAULT_CLI_EPOCH, - ); + let mut vm_env = + OwnedEnvironment::new_free(mainnet, default_chain_id(mainnet), db, epoch); vm_env .initialize_versioned_contract( contract_identifier, @@ -961,8 +974,7 @@ fn install_boot_code(header_db: &CLIHeadersDB, marf: &mut C) ]; let db = marf.get_clarity_db(header_db, &NULL_BURN_STATE_DB); - let mut vm_env = - OwnedEnvironment::new_free(mainnet, default_chain_id(mainnet), db, DEFAULT_CLI_EPOCH); + let mut vm_env = OwnedEnvironment::new_free(mainnet, default_chain_id(mainnet), db, epoch); vm_env .execute_transaction( sender, @@ -994,19 +1006,24 @@ pub fn add_serialized_output(result: &mut serde_json::Value, value: Value) { result["output_serialized"] = serde_json::to_value(result_raw.as_str()).unwrap(); } -/// Parse --clarity_version flag. Defaults to version for DEFAULT_CLI_EPOCH. -fn parse_clarity_version_flag(argv: &mut Vec) -> ClarityVersion { - if let Ok(optarg) = consume_arg(argv, &["--clarity_version"], true) { - if let Some(s) = optarg { - friendly_expect( - s.parse::(), - &format!("Invalid clarity version: {}", s), - ) - } else { - ClarityVersion::default_for_epoch(DEFAULT_CLI_EPOCH) - } +/// Parse --clarity_version flag. Defaults to version for epoch. +fn parse_clarity_version_flag(argv: &mut Vec, epoch: StacksEpochId) -> ClarityVersion { + if let Ok(Some(s)) = consume_arg(argv, &["--clarity_version"], true) { + friendly_expect( + s.parse::(), + &format!("Invalid clarity version: {s}"), + ) + } else { + ClarityVersion::default_for_epoch(epoch) + } +} + +/// Parse --epoch flag. Defaults to DEFAULT_CLI_EPOCH. +fn parse_epoch_flag(argv: &mut Vec) -> StacksEpochId { + if let Ok(Some(s)) = consume_arg(argv, &["--epoch"], true) { + friendly_expect(s.parse::(), &format!("Invalid epoch: {s}")) } else { - ClarityVersion::default_for_epoch(DEFAULT_CLI_EPOCH) + DEFAULT_CLI_EPOCH } } @@ -1021,6 +1038,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option { let mut argv = args.to_vec(); + let epoch = parse_epoch_flag(&mut argv); let mainnet = !matches!(consume_arg(&mut argv, &["--testnet"], false), Ok(Some(_))); let (db_name, allocations) = if argv.len() == 3 { @@ -1035,7 +1053,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option = @@ -1059,12 +1077,16 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option (i32, Option { + if args.len() != 1 { + eprintln!("Usage: {} {}", invoked_by, args[0]); + panic_test!(); + } // random 20 bytes - let random_bytes = rand::thread_rng().gen::<[u8; 20]>(); + let random_bytes = rand::thread_rng().r#gen::<[u8; 20]>(); // version = 22 let addr = friendly_expect(c32_address(22, &random_bytes), "Failed to generate address"); - (0, Some(json!({ "address": format!("{}", addr) }))) + (0, Some(json!({ "address": format!("{addr}") }))) } "check" => { if args.len() < 2 { eprintln!( - "Usage: {} {} [program-file.clar] [--contract_id CONTRACT_ID] [--output_analysis] [--costs] [--testnet] [--clarity_version N] (vm-state.db)", - invoked_by, args[0] + "Usage: {invoked_by} {} [program-file.clar] [--contract_id CONTRACT_ID] [--output_analysis] [--costs] [--testnet] [--clarity_version N] [--epoch E] (vm-state.db)", + args[0] ); panic_test!(); } let mut argv = args.to_vec(); - let clarity_version = parse_clarity_version_flag(&mut argv); + let epoch = parse_epoch_flag(&mut argv); + let clarity_version = parse_clarity_version_flag(&mut argv, epoch); let contract_id = if let Ok(optarg) = consume_arg(&mut argv, &["--contract_id"], true) { optarg .map(|optarg_str| { friendly_expect( QualifiedContractIdentifier::parse(&optarg_str), - &format!("Error parsing contract identifier '{}", &optarg_str), + &format!("Error parsing contract identifier '{optarg_str}"), ) }) .unwrap_or(QualifiedContractIdentifier::transient()) @@ -1190,7 +1217,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option= 3 { // use a persisted marf if testnet_given { - eprintln!("WARN: ignoring --testnet in favor of DB state in {:?}. Re-instantiate the DB to change.", &argv[2]); + eprintln!( + "WARN: ignoring --testnet in favor of DB state in {:?}. Re-instantiate the DB to change.", + &argv[2] + ); } let vm_filename = &argv[2]; @@ -1209,7 +1239,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option (i32, Option { let mut argv = args.to_vec(); - let clarity_version = parse_clarity_version_flag(&mut argv); + let epoch = parse_epoch_flag(&mut argv); + let clarity_version = parse_clarity_version_flag(&mut argv, epoch); let mainnet = !matches!(consume_arg(&mut argv, &["--testnet"], false), Ok(Some(_))); + + if argv.len() != 1 { + eprintln!( + "Usage: {} {} [--testnet] [--epoch E] [--clarity_version N]", + invoked_by, args[0] + ); + panic_test!(); + } + let mut marf = MemoryBackingStore::new(); let mut vm_env = OwnedEnvironment::new_free( mainnet, default_chain_id(mainnet), marf.as_clarity_db(), - DEFAULT_CLI_EPOCH, + epoch, ); let placeholder_context = ContractContext::new(QualifiedContractIdentifier::transient(), clarity_version); @@ -1292,7 +1333,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option ").unwrap_or_else(|e| { + stdout.write_all(b"> ").unwrap_or_else(|e| { panic!("Failed to write stdout prompt string:\n{e}"); }); stdout.flush().unwrap_or_else(|e| { @@ -1307,7 +1348,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option val, Err(error) => { println!("Parse error:\n{error}"); @@ -1321,6 +1362,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (), Err(boxed) => { @@ -1338,12 +1380,25 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option { let mut argv = args.to_vec(); - let clarity_version = parse_clarity_version_flag(&mut argv); + let epoch = parse_epoch_flag(&mut argv); + let clarity_version = parse_clarity_version_flag(&mut argv, epoch); + + if argv.len() != 1 { + eprintln!( + "Usage: {} {} [--epoch E] [--clarity_version N]", + invoked_by, args[0] + ); + eprintln!(" Examples:"); + eprintln!(" echo \"(+ 1 2)\" | {} {}", invoked_by, args[0]); + eprintln!(" {} {} < input.clar", invoked_by, args[0]); + panic_test!(); + } + let content: String = { let mut buffer = String::new(); friendly_expect( @@ -1359,7 +1414,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option { let result = vm_env @@ -1392,7 +1448,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option { let mut argv = args.to_vec(); - let clarity_version = parse_clarity_version_flag(&mut argv); + let epoch = parse_epoch_flag(&mut argv); + let clarity_version = parse_clarity_version_flag(&mut argv, epoch); let costs = matches!(consume_arg(&mut argv, &["--costs"], false), Ok(Some(_))); - let evalInput = get_eval_input(invoked_by, &argv); + let eval_input = get_eval_input(invoked_by, &argv); let vm_filename = if argv.len() == 3 { &argv[2] } else { &argv[3] }; let header_db = friendly_expect(CLIHeadersDB::resume(vm_filename), "Failed to open CLI DB"); @@ -1431,10 +1488,10 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option { let mut result_json = json!({ "error": { - "runtime": serde_json::to_value(&format!("{}", error)).unwrap() + "runtime": serde_json::to_value(format!("{error}")).unwrap() }, "success": false, }); @@ -1467,12 +1524,13 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option { let mut argv = args.to_vec(); - let clarity_version = parse_clarity_version_flag(&mut argv); + let epoch = parse_epoch_flag(&mut argv); + let clarity_version = parse_clarity_version_flag(&mut argv, epoch); let costs = matches!(consume_arg(&mut argv, &["--costs"], false), Ok(Some(_))); let coverage_folder = consume_arg(&mut argv, &["--c"], true).unwrap_or(None); - let evalInput = get_eval_input(invoked_by, &argv); + let eval_input = get_eval_input(invoked_by, &argv); let vm_filename = if argv.len() == 3 { &argv[2].clone() } else { @@ -1496,13 +1554,14 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option { let mut argv = args.to_vec(); - let clarity_version = parse_clarity_version_flag(&mut argv); + let epoch = parse_epoch_flag(&mut argv); + let clarity_version = parse_clarity_version_flag(&mut argv, epoch); let costs = matches!(consume_arg(&mut argv, &["--costs"], false), Ok(Some(_))); if argv.len() != 4 { eprintln!( - "Usage: {} {} [--costs] [index-block-hash] [contract-identifier] [--clarity_version N] [vm/clarity dir]", - invoked_by, &argv[0] + "Usage: {invoked_by} {} [--costs] [--epoch E] [index-block-hash] [contract-identifier] [--clarity_version N] [vm/clarity dir]", + &argv[0] ); panic_test!(); } @@ -1577,7 +1637,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option { let mut result_json = json!({ "error": { - "runtime": serde_json::to_value(&format!("{}", error)).unwrap() + "runtime": serde_json::to_value(format!("{error}")).unwrap() }, "success": false, }); @@ -1613,7 +1673,8 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option { let mut argv = args.to_vec(); - let clarity_version = parse_clarity_version_flag(&mut argv); + let epoch = parse_epoch_flag(&mut argv); + let clarity_version = parse_clarity_version_flag(&mut argv, epoch); let coverage_folder = consume_arg(&mut argv, &["--c"], true).unwrap_or(None); let costs = matches!(consume_arg(&mut argv, &["--costs"], false), Ok(Some(_))); @@ -1625,8 +1686,8 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option (header_db, marf, Err(e)), Ok(analysis) => { let result_and_cost = with_env_costs( mainnet, + epoch, &header_db, &mut marf, coverage.as_mut(), @@ -1722,7 +1790,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option (i32, Option { let mut argv = args.to_vec(); - let clarity_version = parse_clarity_version_flag(&mut argv); + let epoch = parse_epoch_flag(&mut argv); + let clarity_version = parse_clarity_version_flag(&mut argv, epoch); let coverage_folder = consume_arg(&mut argv, &["--c"], true).unwrap_or(None); let costs = matches!(consume_arg(&mut argv, &["--costs"], false), Ok(Some(_))); let assets = matches!(consume_arg(&mut argv, &["--assets"], false), Ok(Some(_))); if argv.len() < 5 { - eprintln!("Usage: {} {} [--costs] [--assets] [--clarity_version N] [vm-state.db] [contract-identifier] [public-function-name] [sender-address] [args...]", invoked_by, argv[0]); + eprintln!( + "Usage: {invoked_by} {} [--costs] [--assets] [--clarity_version N] [--epoch E] [vm-state.db] [contract-identifier] [public-function-name] [sender-address] [args...]", + argv[0] + ); panic_test!(); } @@ -1789,7 +1861,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option (i32, Option (i32, Option (i32, Option { - let mut register_files = vec![]; - let mut coverage_files = vec![]; - let coverage_folder = &args[1]; - let lcov_output_file = &args[2]; - for folder_entry in - fs::read_dir(coverage_folder).expect("Failed to read the coverage folder") - { - let folder_entry = - folder_entry.expect("Failed to read entry in the coverage folder"); - let entry_path = folder_entry.path(); - if entry_path.is_file() { - if entry_path.extension() == Some(OsStr::new("clarcovref")) { - register_files.push(entry_path) - } else if entry_path.extension() == Some(OsStr::new("clarcov")) { - coverage_files.push(entry_path) - } - } - } - CoverageReporter::produce_lcov(lcov_output_file, ®ister_files, &coverage_files) - .expect("Failed to produce an lcov output"); - (0, None) - } _ => { print_usage(invoked_by); (1, None) @@ -1934,9 +1984,9 @@ mod test { #[test] fn test_initial_alloc() { - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); - let json_name = format!("/tmp/test-alloc_{}.json", rand::thread_rng().gen::()); - let clar_name = format!("/tmp/test-alloc_{}.clar", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); + let json_name = format!("/tmp/test-alloc_{}.json", rand::thread_rng().r#gen::()); + let clar_name = format!("/tmp/test-alloc_{}.clar", rand::thread_rng().r#gen::()); fs::write( &json_name, @@ -1974,14 +2024,14 @@ mod test { ], ); let exit = invoked.0; - let result = invoked.1.unwrap(); + let _ = invoked.1.unwrap(); assert_eq!(exit, 0); } #[test] fn test_init_mainnet() { - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); let invoked = invoke_command("test", &["initialize".to_string(), db_name.clone()]); let exit = invoked.0; @@ -1996,7 +2046,7 @@ mod test { #[test] fn test_init_testnet() { - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); let invoked = invoke_command( "test", &[ @@ -2025,7 +2075,7 @@ mod test { #[test] fn test_samples() { - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); eprintln!("initialize"); invoke_command("test", &["initialize".to_string(), db_name.clone()]); @@ -2306,7 +2356,7 @@ mod test { #[test] fn test_assets() { - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); eprintln!("initialize"); invoke_command("test", &["initialize".to_string(), db_name.clone()]); @@ -2346,8 +2396,7 @@ mod test { assert_eq!(exit, 0); assert!(!result["message"].as_str().unwrap().is_empty()); assert!( - result["assets"]["tokens"]["S1G2081040G2081040G2081040G208105NK8PE5"] - ["S1G2081040G2081040G2081040G208105NK8PE5.tokens-ft::tokens"] + result["assets"]["tokens"]["S1G2081040G2081040G2081040G208105NK8PE5"]["S1G2081040G2081040G2081040G208105NK8PE5.tokens-ft::tokens"] == "10300" ); assert!(result["events"].as_array().unwrap().len() == 3); @@ -2402,7 +2451,7 @@ mod test { // Arrange let clar_path = format!( "/tmp/version-flag-c3-allow-{}.clar", - rand::thread_rng().gen::() + rand::thread_rng().r#gen::() ); fs::write( &clar_path, @@ -2446,7 +2495,7 @@ mod test { // Arrange let clar_path = format!( "/tmp/version-flag-c2-reject-{}.clar", - rand::thread_rng().gen::() + rand::thread_rng().r#gen::() ); fs::write( &clar_path, @@ -2486,15 +2535,60 @@ mod test { assert!(result_json["error"]["analysis"] != json!(null)); } + #[test] + fn test_check_clarity3_contract_fails_with_epoch21_flag() { + // Arrange + let clar_path = format!( + "/tmp/version-flag-c2-reject-{}.clar", + rand::thread_rng().r#gen::() + ); + fs::write( + &clar_path, + // Valid only in Clarity 3, should fail in epoch 2.1 which defaults to Clarity 2. + r#" +(define-read-only (get-tenure-info (h uint)) + (ok + { + tenure-time: (get-tenure-info? time h), + tenure-miner-address: (get-tenure-info? miner-address h), + }) +) +"#, + ) + .unwrap(); + + // Act + let invoked = invoke_command( + "test", + &[ + "check".to_string(), + clar_path, + "--epoch".to_string(), + "2.1".to_string(), + ], + ); + + // Assert + let exit_code = invoked.0; + let result_json = invoked.1.unwrap(); + assert_eq!( + exit_code, 1, + "expected check to fail under Clarity 2, got: {}", + result_json + ); + assert_eq!(result_json["message"], "Checks failed."); + assert!(result_json["error"]["analysis"] != json!(null)); + } + #[test] fn test_launch_clarity3_contract_passes_with_clarity3_flag() { // Arrange - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); invoke_command("test", &["initialize".to_string(), db_name.clone()]); let clar_path = format!( "/tmp/version-flag-launch-c3-{}.clar", - rand::thread_rng().gen::() + rand::thread_rng().r#gen::() ); fs::write( &clar_path, @@ -2538,12 +2632,12 @@ mod test { #[test] fn test_launch_clarity3_contract_fails_with_clarity2_flag() { // Arrange - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); invoke_command("test", &["initialize".to_string(), db_name.clone()]); let clar_path = format!( "/tmp/version-flag-launch-c2-{}.clar", - rand::thread_rng().gen::() + rand::thread_rng().r#gen::() ); fs::write( &clar_path, @@ -2587,13 +2681,13 @@ mod test { #[test] fn test_eval_clarity3_contract_passes_with_clarity3_flag() { // Arrange - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); invoke_command("test", &["initialize".to_string(), db_name.clone()]); // Launch minimal contract at target for eval context. let launch_src = format!( "/tmp/version-flag-eval-launch-{}.clar", - rand::thread_rng().gen::() + rand::thread_rng().r#gen::() ); fs::write(&launch_src, "(define-read-only (dummy) true)").unwrap(); let _ = invoke_command( @@ -2609,7 +2703,7 @@ mod test { // Use a Clarity3-only native expression. let clar_path = format!( "/tmp/version-flag-eval-c3-{}.clar", - rand::thread_rng().gen::() + rand::thread_rng().r#gen::() ); fs::write(&clar_path, "(get-tenure-info? time u1)").unwrap(); @@ -2640,13 +2734,13 @@ mod test { #[test] fn test_eval_clarity3_contract_fails_with_clarity2_flag() { // Arrange - let db_name = format!("/tmp/db_{}", rand::thread_rng().gen::()); + let db_name = format!("/tmp/db_{}", rand::thread_rng().r#gen::()); invoke_command("test", &["initialize".to_string(), db_name.clone()]); // Launch minimal contract at target for eval context. let launch_src = format!( "/tmp/version-flag-eval-launch-{}.clar", - rand::thread_rng().gen::() + rand::thread_rng().r#gen::() ); fs::write(&launch_src, "(define-read-only (dummy) true)").unwrap(); let _ = invoke_command( @@ -2664,7 +2758,7 @@ mod test { // Use a Clarity3-only native expression. let clar_path = format!( "/tmp/version-flag-eval-c2-{}.clar", - rand::thread_rng().gen::() + rand::thread_rng().r#gen::() ); fs::write(&clar_path, "(get-tenure-info? time u1)").unwrap(); diff --git a/stackslib/src/clarity_cli_main.rs b/contrib/clarity-cli/src/main.rs similarity index 82% rename from stackslib/src/clarity_cli_main.rs rename to contrib/clarity-cli/src/main.rs index b7690ac6650..f6d9d480c74 100644 --- a/stackslib/src/clarity_cli_main.rs +++ b/contrib/clarity-cli/src/main.rs @@ -14,23 +14,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#![allow(dead_code)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] - -extern crate blockstack_lib; extern crate serde_json; use std::{env, process}; -use blockstack_lib::clarity_cli as clarity; +use clarity_cli::invoke_command; #[allow(clippy::indexing_slicing)] fn main() { let argv: Vec = env::args().collect(); - let result = clarity::invoke_command(&argv[0], &argv[1..]); + let result = invoke_command(&argv[0], &argv[1..]); match result { (exit_code, Some(output)) => { println!("{}", &serde_json::to_string(&output).unwrap()); diff --git a/contrib/nix/flake.lock b/contrib/nix/flake.lock index 8cb7bfe5b9e..a139d210485 100644 --- a/contrib/nix/flake.lock +++ b/contrib/nix/flake.lock @@ -2,11 +2,11 @@ "nodes": { "crane": { "locked": { - "lastModified": 1759691647, - "narHash": "sha256-OnyPw3KaXL909I+FNyD6jfkAP/gdL/K0iitMHxo7ieM=", + "lastModified": 1759893430, + "narHash": "sha256-yAy4otLYm9iZ+NtQwTMEbqHwswSFUbhn7x826RR6djw=", "owner": "ipetkov", "repo": "crane", - "rev": "1e7905b1eb1b551aade75169940557b6c51ed920", + "rev": "1979a2524cb8c801520bd94c38bb3d5692419d93", "type": "github" }, "original": { @@ -37,11 +37,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1759632233, - "narHash": "sha256-krgZxGAIIIKFJS+UB0l8do3sYUDWJc75M72tepmVMzE=", + "lastModified": 1760349414, + "narHash": "sha256-W4Ri1ZwYuNcBzqQQa7NnWfrv0wHMo7rduTWjIeU9dZk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "d7f52a7a640bc54c7bb414cca603835bf8dd4b10", + "rev": "c12c63cd6c5eb34c7b4c3076c6a99e00fcab86ec", "type": "github" }, "original": { @@ -67,11 +67,11 @@ ] }, "locked": { - "lastModified": 1759804383, - "narHash": "sha256-jPz0K8xsT2eNSratkw8bfPwSlTuOXGeUvz+bd9wq/vY=", + "lastModified": 1760409263, + "narHash": "sha256-GvcdHmY3nZnU6GnUkEG1a7pDZPgFcuN+zGv3OgvfPH0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "dec08d5dfeca099b0058f0cc61264b04f33db42c", + "rev": "5694018463c2134e2369996b38deed41b1b9afc1", "type": "github" }, "original": { diff --git a/contrib/nix/flake.nix b/contrib/nix/flake.nix index b8eff4ae689..e117fcd9145 100644 --- a/contrib/nix/flake.nix +++ b/contrib/nix/flake.nix @@ -98,6 +98,7 @@ ../tools/config-docs-generator) (craneLib.fileset.commonCargoSources ../../contrib/stacks-inspect) (craneLib.fileset.commonCargoSources ../../contrib/stacks-cli) + (craneLib.fileset.commonCargoSources ../../contrib/clarity-cli) (craneLib.fileset.commonCargoSources ../../stacks-signer) ]; }; @@ -135,6 +136,13 @@ src = fileSetForCrate ../../contrib/stacks-cli; }); + clarity-cli = craneLib.buildPackage (individualCrateArgs // rec { + inherit version; + pname = "clarity-cli"; + cargoExtraArgs = "-p ${pname}"; + src = fileSetForCrate ../../contrib/clarity-cli; + }); + stacks-node-app = { type = "app"; program = "${stacks-core}/bin/stacks-node"; @@ -158,7 +166,7 @@ }; in with pkgs; { packages = { - inherit stacks-signer stacks-core stacks-cli stacks-inspect; + inherit stacks-signer stacks-core stacks-cli clarity-cli stacks-inspect; default = stacks-core; }; diff --git a/contrib/stacks-cli/Cargo.toml b/contrib/stacks-cli/Cargo.toml index a3db6d6e0ff..a942aa50c33 100644 --- a/contrib/stacks-cli/Cargo.toml +++ b/contrib/stacks-cli/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] stackslib = { package = "stackslib", path = "../../stackslib", default-features = false } clarity = { path = "../../clarity", default-features = false } +clarity-cli = { path = "../clarity-cli", default-features = false } stacks-common = { path = "../../stacks-common", default-features = false } serde_json = { workspace = true } diff --git a/contrib/stacks-cli/src/main.rs b/contrib/stacks-cli/src/main.rs index 34561c0659b..2014be553fe 100644 --- a/contrib/stacks-cli/src/main.rs +++ b/contrib/stacks-cli/src/main.rs @@ -22,9 +22,10 @@ use std::io::Read; use std::io::prelude::*; use std::{env, fs, io}; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError}; use clarity::vm::types::PrincipalData; use clarity::vm::{ClarityName, ClarityVersion, ContractName, Value}; +use clarity_cli::vm_execute; use stacks_common::address::{AddressHashMode, b58}; use stacks_common::codec::{Error as CodecError, StacksMessageCodec}; use stacks_common::types::chainstate::StacksAddress; @@ -41,7 +42,6 @@ use stackslib::chainstate::stacks::{ TransactionContractCall, TransactionPayload, TransactionPostConditionMode, TransactionSmartContract, TransactionSpendingCondition, TransactionVersion, }; -use stackslib::clarity_cli::vm_execute; use stackslib::core::{CHAIN_ID_MAINNET, CHAIN_ID_TESTNET}; use stackslib::net::Error as NetError; use stackslib::util_lib::strings::StacksString; @@ -184,8 +184,8 @@ block's sqlite database."; #[derive(Debug)] enum CliError { - ClarityRuntimeError(RuntimeErrorType), - ClarityGeneralError(ClarityError), + ClarityRuntimeError(RuntimeError), + ClarityGeneralError(VmExecutionError), Message(String), Usage, InvalidChainId(std::num::ParseIntError), @@ -219,14 +219,14 @@ impl From<&str> for CliError { } } -impl From for CliError { - fn from(value: RuntimeErrorType) -> Self { +impl From for CliError { + fn from(value: RuntimeError) -> Self { CliError::ClarityRuntimeError(value) } } -impl From for CliError { - fn from(value: ClarityError) -> Self { +impl From for CliError { + fn from(value: VmExecutionError) -> Self { CliError::ClarityGeneralError(value) } } diff --git a/contrib/stacks-inspect/Cargo.toml b/contrib/stacks-inspect/Cargo.toml index 785b9993981..8de68317534 100644 --- a/contrib/stacks-inspect/Cargo.toml +++ b/contrib/stacks-inspect/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] stackslib = { package = "stackslib", path = "../../stackslib", default-features = false } clarity = { path = "../../clarity", default-features = false } +clarity-cli = { path = "../clarity-cli", default-features = false } libstackerdb = { path = "../../libstackerdb", default-features = false } stacks-common = { path = "../../stacks-common", default-features = false } regex = { version = "1", default-features = false } diff --git a/contrib/stacks-inspect/src/lib.rs b/contrib/stacks-inspect/src/lib.rs index cbe99473873..13026508aca 100644 --- a/contrib/stacks-inspect/src/lib.rs +++ b/contrib/stacks-inspect/src/lib.rs @@ -393,7 +393,7 @@ pub fn command_try_mine(argv: &[String], conf: Option<&Config>) { let print_help_and_exit = || { let n = &argv[0]; eprintln!("Usage: {n} [min-fee [max-time]]"); - eprintln!(""); + eprintln!(); eprintln!( "Given a , try to ''mine'' an anchored block. This invokes the miner block" ); @@ -731,6 +731,7 @@ fn replay_mock_mined_block(db_path: &str, block: AssembledAnchorBlock, conf: Opt } /// Validate a block against chainstate +#[allow(clippy::too_many_arguments)] fn replay_block( mut sort_tx: IndexDBTx, mut chainstate_tx: ChainstateTx, @@ -901,6 +902,7 @@ fn replay_naka_staging_block(db_path: &str, index_block_hash_hex: &str, conf: &C replay_block_nakamoto(&mut sortdb, &mut chainstate, &block, block_size).unwrap(); } +#[allow(clippy::result_large_err)] fn replay_block_nakamoto( sort_db: &mut SortitionDB, stacks_chain_state: &mut StacksChainState, @@ -1140,7 +1142,7 @@ fn replay_block_nakamoto( &mut chainstate_tx, clarity_instance, &mut burn_view_handle, - &burnchain_view, + burnchain_view, &pox_constants, &parent_header_info, &next_ready_block_snapshot.burn_header_hash, diff --git a/contrib/stacks-inspect/src/main.rs b/contrib/stacks-inspect/src/main.rs index e225149bb97..032eee97941 100644 --- a/contrib/stacks-inspect/src/main.rs +++ b/contrib/stacks-inspect/src/main.rs @@ -85,7 +85,6 @@ use stackslib::chainstate::stacks::index::marf::{MARF, MARFOpenOpts, MarfConnect use stackslib::clarity::vm::ClarityVersion; use stackslib::clarity::vm::costs::ExecutionCost; use stackslib::clarity::vm::types::StacksAddressExtensions; -use stackslib::clarity_cli; use stackslib::core::MemPoolDB; use stackslib::cost_estimates::UnitEstimator; use stackslib::cost_estimates::metrics::UnitMetric; diff --git a/docs/rpc/components/examples/block-replay.example.json b/docs/rpc/components/examples/block-replay.example.json index b6c79c99f2d..e01fa2fbe60 100644 --- a/docs/rpc/components/examples/block-replay.example.json +++ b/docs/rpc/components/examples/block-replay.example.json @@ -98,6 +98,8 @@ } } }, + "result_hex": "0x0703", + "post_condition_aborted": false, "stx_burned": 0, "tx_index": 0, "txid": "f14dd7dec56405fd7dac69c3080fb569fae4c49c591f9ad0e5cf5c797add9005" diff --git a/docs/rpc/components/schemas/block-replay.schema.yaml b/docs/rpc/components/schemas/block-replay.schema.yaml index 627367243e4..df4ea165350 100644 --- a/docs/rpc/components/schemas/block-replay.schema.yaml +++ b/docs/rpc/components/schemas/block-replay.schema.yaml @@ -36,7 +36,7 @@ properties: state_index_root: type: string pattern: "^[0-9a-f]{64}$" - description: block state index root computed from the MARF (got from the original block) + description: block state index root computed from the MARF (got from the original block) timestamp: type: integer tx_merkle_root: @@ -67,6 +67,12 @@ properties: result: type: object description: Clarity value representing the transaction result + result_hex: + type: string + description: The transaction's result, encoded as a Clarity hex string + post_condition_aborted: + type: boolean + description: Whether the transaction was aborted by a post-condition stx_burned: type: integer description: number of burned stx diff --git a/docs/rpc/components/schemas/pox-info.schema.yaml b/docs/rpc/components/schemas/pox-info.schema.yaml index 0d72158f827..ea9abc2cb85 100644 --- a/docs/rpc/components/schemas/pox-info.schema.yaml +++ b/docs/rpc/components/schemas/pox-info.schema.yaml @@ -15,6 +15,7 @@ required: - reward_cycle_length - contract_versions - epochs + - current_epoch properties: contract_id: type: string @@ -27,6 +28,10 @@ properties: type: integer minimum: 0 description: The latest Bitcoin chain block height + current_epoch: + type: string + pattern: "^Epoch[0-9]+(_[0-9]+)?$" + description: The ID of the Stacks Epoch that the node is currently in. pox_activation_threshold_ustx: type: integer description: diff --git a/docs/rpc/openapi.yaml b/docs/rpc/openapi.yaml index b24645c8de7..d70875a00ec 100644 --- a/docs/rpc/openapi.yaml +++ b/docs/rpc/openapi.yaml @@ -43,7 +43,8 @@ components: name: authorization description: | Plain-text secret value that must exactly equal the node's - configured password. + configured password, which is set as `connection_options.auth_token` + in the node's configuration file. responses: Unauthorized: description: Unauthorized. Invalid or missing authentication token. @@ -449,6 +450,8 @@ paths: externalValue: "./components/examples/read-only-function-failure.example.json" "400": $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "408": @@ -2205,7 +2208,8 @@ paths: summary: Replay mining of a block and returns its content tags: - Blocks - security: [] + security: + - rpcAuth: [] operationId: blockReplay description: | Replay the mining of a block (no data is written in the MARF) and returns its content. @@ -2228,6 +2232,8 @@ paths: $ref: "./components/examples/block-replay.example.json" "400": $ref: "#/components/responses/BadRequest" + "401": + $ref: "#/components/responses/Unauthorized" "404": $ref: "#/components/responses/NotFound" "500": diff --git a/libsigner/src/v0/messages.rs b/libsigner/src/v0/messages.rs index b83fc2aceb4..36a5dd05a6f 100644 --- a/libsigner/src/v0/messages.rs +++ b/libsigner/src/v0/messages.rs @@ -1199,15 +1199,17 @@ impl BlockResponse { pub fn accepted( signer_signature_hash: Sha512Trunc256Sum, signature: MessageSignature, - tenure_extend_timestamp: u64, + full_extend_ts: u64, + read_count_extend_ts: u64, ) -> Self { Self::Accepted(BlockAccepted { signer_signature_hash, signature, metadata: SignerMessageMetadata::default(), response_data: BlockResponseData::new( - tenure_extend_timestamp, + full_extend_ts, RejectReason::NotRejected, + read_count_extend_ts, ), }) } @@ -1218,14 +1220,16 @@ impl BlockResponse { reject_reason: RejectReason, private_key: &StacksPrivateKey, mainnet: bool, - timestamp: u64, + full_extend_ts: u64, + read_count_extend_ts: u64, ) -> Self { Self::Rejected(BlockRejection::new( hash, reject_reason, private_key, mainnet, - timestamp, + full_extend_ts, + read_count_extend_ts, )) } @@ -1353,17 +1357,22 @@ impl SignerMessageMetadata { } /// The latest version of the block response data -pub const BLOCK_RESPONSE_DATA_VERSION: u8 = 3; +pub const BLOCK_RESPONSE_DATA_VERSION: u8 = 4; +/// The first version of the block response data that added the tenure read count extend +/// timestamp. +pub const FIRST_RESPONSE_DATA_VERSION_WITH_READ_COUNT: u8 = 4; /// Versioned, backwards-compatible struct for block response data #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct BlockResponseData { /// The version of the block response data pub version: u8, - /// The block response data + /// Timestamp for when this signer would accept a full time-based TenureExtend pub tenure_extend_timestamp: u64, /// Block rejection reason pub reject_reason: RejectReason, + /// Timestamp for when this signer would accept a read-count only TenureExtend + pub tenure_extend_read_count_timestamp: u64, /// When deserializing future versions, /// there may be extra bytes that we don't know about pub unknown_bytes: Vec, @@ -1371,24 +1380,30 @@ pub struct BlockResponseData { impl BlockResponseData { /// Create a new BlockResponseData for the provided tenure extend timestamp and unknown bytes - pub fn new(tenure_extend_timestamp: u64, reject_reason: RejectReason) -> Self { + pub fn new( + tenure_extend_timestamp: u64, + reject_reason: RejectReason, + tenure_extend_read_count_timestamp: u64, + ) -> Self { Self { version: BLOCK_RESPONSE_DATA_VERSION, tenure_extend_timestamp, reject_reason, + tenure_extend_read_count_timestamp, unknown_bytes: vec![], } } /// Create an empty BlockResponseData pub fn empty() -> Self { - Self::new(u64::MAX, RejectReason::NotRejected) + Self::new(u64::MAX, RejectReason::NotRejected, u64::MAX) } /// Serialize the "inner" block response data. Used to determine the bytes length of the serialized block response data fn inner_consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &self.tenure_extend_timestamp)?; write_next(fd, &self.reject_reason)?; + write_next(fd, &self.tenure_extend_read_count_timestamp)?; fd.write_all(&self.unknown_bytes) .map_err(CodecError::WriteError)?; Ok(()) @@ -1421,10 +1436,17 @@ impl StacksMessageCodec for BlockResponseData { let mut inner_reader = inner_bytes.as_slice(); let tenure_extend_timestamp = read_next(&mut inner_reader)?; let reject_reason = read_next::(&mut inner_reader)?; + let tenure_extend_read_count_timestamp = + if version < FIRST_RESPONSE_DATA_VERSION_WITH_READ_COUNT { + u64::MAX + } else { + read_next(&mut inner_reader)? + }; Ok(Self { version, tenure_extend_timestamp, reject_reason, + tenure_extend_read_count_timestamp, unknown_bytes: inner_reader.to_vec(), }) } @@ -1471,15 +1493,17 @@ impl BlockAccepted { pub fn new( signer_signature_hash: Sha512Trunc256Sum, signature: MessageSignature, - tenure_extend_timestamp: u64, + full_extend_ts: u64, + read_count_extend_ts: u64, ) -> Self { Self { signer_signature_hash, signature, metadata: SignerMessageMetadata::default(), response_data: BlockResponseData::new( - tenure_extend_timestamp, + full_extend_ts, RejectReason::NotRejected, + read_count_extend_ts, ), } } @@ -1511,7 +1535,8 @@ impl BlockRejection { reject_reason: RejectReason, private_key: &StacksPrivateKey, mainnet: bool, - timestamp: u64, + full_extend_ts: u64, + read_count_extend_ts: u64, ) -> Self { let chain_id = if mainnet { CHAIN_ID_MAINNET @@ -1525,7 +1550,11 @@ impl BlockRejection { signature: MessageSignature::empty(), chain_id, metadata: SignerMessageMetadata::default(), - response_data: BlockResponseData::new(timestamp, reject_reason), + response_data: BlockResponseData::new( + full_extend_ts, + reject_reason, + read_count_extend_ts, + ), }; rejection .sign(private_key) @@ -1538,7 +1567,8 @@ impl BlockRejection { reject: BlockValidateReject, private_key: &StacksPrivateKey, mainnet: bool, - timestamp: u64, + full_extend_ts: u64, + read_count_extend_ts: u64, ) -> Self { let chain_id = if mainnet { CHAIN_ID_MAINNET @@ -1553,7 +1583,11 @@ impl BlockRejection { chain_id, signature: MessageSignature::empty(), metadata: SignerMessageMetadata::default(), - response_data: BlockResponseData::new(timestamp, (&reject_code).into()), + response_data: BlockResponseData::new( + full_extend_ts, + (&reject_code).into(), + read_count_extend_ts, + ), }; rejection .sign(private_key) @@ -1924,6 +1958,7 @@ mod test { &StacksPrivateKey::random(), thread_rng().gen_bool(0.5), thread_rng().next_u64(), + thread_rng().next_u64(), ); let serialized_rejection = rejection.serialize_to_vec(); let deserialized_rejection = read_next::(&mut &serialized_rejection[..]) @@ -1936,6 +1971,7 @@ mod test { &StacksPrivateKey::random(), thread_rng().gen_bool(0.5), thread_rng().next_u64(), + thread_rng().next_u64(), ); let serialized_rejection = rejection.serialize_to_vec(); let deserialized_rejection = read_next::(&mut &serialized_rejection[..]) @@ -1952,6 +1988,7 @@ mod test { response_data: BlockResponseData::new( thread_rng().next_u64(), RejectReason::NotRejected, + thread_rng().next_u64(), ), }; let response = BlockResponse::Accepted(accepted); @@ -1966,6 +2003,7 @@ mod test { &StacksPrivateKey::random(), thread_rng().gen_bool(0.5), thread_rng().next_u64(), + thread_rng().next_u64(), )); let serialized_response = response.serialize_to_vec(); let deserialized_response = read_next::(&mut &serialized_response[..]) @@ -1982,6 +2020,7 @@ mod test { response_data: BlockResponseData::new( thread_rng().next_u64(), RejectReason::NotRejected, + thread_rng().next_u64(), ), }; let signer_message = SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)); @@ -2149,7 +2188,7 @@ mod test { chain_id: CHAIN_ID_TESTNET, signature: MessageSignature::from_hex("006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df3").unwrap(), metadata: SignerMessageMetadata::empty(), - response_data: BlockResponseData::new(u64::MAX, RejectReason::NotRejected), + response_data: BlockResponseData::new(u64::MAX, RejectReason::NotRejected, u64::MAX), })) ); @@ -2162,13 +2201,13 @@ mod test { .unwrap(), metadata: SignerMessageMetadata::empty(), signature: MessageSignature::from_hex("001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e8").unwrap(), - response_data: BlockResponseData::new(u64::MAX, RejectReason::NotRejected), + response_data: BlockResponseData::new(u64::MAX, RejectReason::NotRejected, u64::MAX), })) ); } #[test] - fn test_block_response_metadata() { + fn v2_block_response_metadata() { let block_rejected_hex = "010100000050426c6f636b206973206e6f7420612074656e7572652d737461727420626c6f636b2c20616e642068617320616e20756e7265636f676e697a65642074656e75726520636f6e73656e7375732068617368000691f95f84b7045f7dce7757052caa986ef042cb58f7df5031a3b5b5d0e3dda63e80000000006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df30000000b48656c6c6f20776f726c64"; let block_rejected_bytes = hex_bytes(block_rejected_hex).unwrap(); let block_accepted_hex = "010011717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e80000000b48656c6c6f20776f726c64"; @@ -2189,7 +2228,7 @@ mod test { metadata: SignerMessageMetadata { server_version: "Hello world".to_string(), }, - response_data: BlockResponseData::new(u64::MAX, RejectReason::NotRejected), + response_data: BlockResponseData::new(u64::MAX, RejectReason::NotRejected, u64::MAX), })) ); @@ -2220,22 +2259,23 @@ mod test { #[test] fn block_response_data_serialization() { - let mut response_data = BlockResponseData::new(2, RejectReason::ReorgNotAllowed); + let mut response_data = BlockResponseData::new(2, RejectReason::ReorgNotAllowed, 3); response_data.unknown_bytes = vec![1, 2, 3, 4]; let mut bytes = vec![]; response_data.consensus_serialize(&mut bytes).unwrap(); // 1 byte version + 4 bytes (bytes_len) + 8 bytes tenure_extend_timestamp - // + 1 byte reject code + 4 bytes unknown_bytes - assert_eq!(bytes.len(), 18); + // + 1 byte reject code + 8 bytes read_count_timestamp + 4 bytes unknown_bytes + assert_eq!(bytes.len(), 26); let deserialized_data = read_next::(&mut &bytes[..]) .expect("Failed to deserialize BlockResponseData"); assert_eq!(response_data, deserialized_data); - let response_data = BlockResponseData::new(2, RejectReason::NotRejected); + let response_data = BlockResponseData::new(2, RejectReason::NotRejected, 3); let mut bytes = vec![]; response_data.consensus_serialize(&mut bytes).unwrap(); - // 1 byte version + 4 bytes (bytes_len) + 8 bytes tenure_extend_timestamp + 0 bytes unknown_bytes - assert_eq!(bytes.len(), 14); + // 1 byte version + 4 bytes (bytes_len) + 8 bytes tenure_extend_timestamp + // + 8 bytes read_count_timestamp + 0 bytes unknown_bytes + assert_eq!(bytes.len(), 22); let deserialized_data = read_next::(&mut &bytes[..]) .expect("Failed to deserialize BlockResponseData"); assert_eq!(response_data, deserialized_data); @@ -2246,6 +2286,7 @@ mod test { pub version: u8, pub tenure_extend_timestamp: u64, pub reject_reason: RejectReason, + pub read_count_timestamp: u64, pub some_other_field: u64, pub yet_another_field: u64, } @@ -2254,6 +2295,7 @@ mod test { pub fn inner_consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &self.tenure_extend_timestamp)?; write_next(fd, &self.reject_reason)?; + write_next(fd, &self.read_count_timestamp)?; write_next(fd, &self.some_other_field)?; write_next(fd, &self.yet_another_field)?; Ok(()) @@ -2278,6 +2320,7 @@ mod test { reject_reason: RejectReason::ReorgNotAllowed, some_other_field: 3, yet_another_field: 4, + read_count_timestamp: 3, }; let mut bytes = vec![]; @@ -2342,7 +2385,7 @@ mod test { signer_signature_hash: Sha512Trunc256Sum::from_hex("11717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19").unwrap(), metadata: SignerMessageMetadata::default(), signature: MessageSignature::from_hex("001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e8").unwrap(), - response_data: BlockResponseData::new(u64::MAX, RejectReason::NotRejected), + response_data: BlockResponseData::new(u64::MAX, RejectReason::NotRejected, u64::MAX), }; let mut bytes = vec![]; @@ -2373,6 +2416,10 @@ mod test { accepted.response_data.reject_reason, RejectReason::Unknown(RejectReasonPrefix::Unknown as u8) ); + assert_eq!( + accepted.response_data.tenure_extend_read_count_timestamp, + u64::MAX + ); } #[test] @@ -2641,4 +2688,77 @@ mod test { .expect("Failed to deserialize pre-commit"); assert_eq!(pre_commit, deserialized_pre_commit); } + + #[test] + /// Tests that messages created by version 3 of the response data + /// can be deserialized by the current version. + /// + /// * When deserialized by V4 of the library, these messages will set the + /// `tenure_extend_read_count_timestamp` field to u64::MAX. + fn v3_block_response_deserialization() { + let test_vectors = [ + ( + SignerMessage::BlockResponse(BlockResponse::Rejected(BlockRejection { + reason_code: RejectCode::ValidationFailed(ValidateRejectCode::NoSuchTenure), + reason: "Block is not a tenure-start block, and has an unrecognized tenure consensus hash".to_string(), + signer_signature_hash: Sha512Trunc256Sum::from_hex("91f95f84b7045f7dce7757052caa986ef042cb58f7df5031a3b5b5d0e3dda63e").unwrap(), + chain_id: CHAIN_ID_TESTNET, + signature: MessageSignature::from_hex("006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df3").unwrap(), + metadata: SignerMessageMetadata { + server_version: "Hello world".to_string(), + }, + response_data: BlockResponseData { + version: 3, + tenure_extend_timestamp: 11, + reject_reason: RejectReason::InvalidParentBlock, + tenure_extend_read_count_timestamp: u64::MAX, + unknown_bytes: vec![], + }, + })), + "010100000050426c6f636b206973206e6f7420612074656e7572652d737461727420626c6f636b2c20616e642068617320616e20756e7265636f676e697a65642074656e75726520636f6e73656e7375732068617368000691f95f84b7045f7dce7757052caa986ef042cb58f7df5031a3b5b5d0e3dda63e80000000006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df30000000b48656c6c6f20776f726c640300000009000000000000000b0b", + ), + ( + SignerMessage::BlockResponse(BlockResponse::Accepted(BlockAccepted { + signer_signature_hash: Sha512Trunc256Sum::from_hex( + "11717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19" + ) + .unwrap(), + metadata: SignerMessageMetadata { + server_version: "Hello world".to_string(), + }, + signature: MessageSignature::from_hex("001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e8").unwrap(), + response_data: BlockResponseData { + version: 3, + tenure_extend_timestamp: 21, + reject_reason: RejectReason::NotRejected, + tenure_extend_read_count_timestamp: u64::MAX, + unknown_bytes: vec![], + }, + })), + "010011717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e80000000b48656c6c6f20776f726c6403000000090000000000000015ff", + ) + ]; + + for (expected_out, input_hex) in test_vectors.into_iter() { + let input_bytes = hex_bytes(input_hex).unwrap(); + let actual_out = + SignerMessage::consensus_deserialize(&mut input_bytes.as_slice()).unwrap(); + assert_eq!(actual_out, expected_out); + let SignerMessage::BlockResponse(expected_out) = expected_out else { + panic!("Expected block response"); + }; + let SignerMessage::BlockResponse(actual_out) = actual_out else { + panic!("Expected block response"); + }; + let expected_data = expected_out.get_response_data(); + let resp_data = actual_out.get_response_data(); + assert_eq!( + resp_data.tenure_extend_read_count_timestamp, + expected_data.tenure_extend_read_count_timestamp + ); + assert_eq!(resp_data.unknown_bytes, expected_data.unknown_bytes); + assert_eq!(resp_data.version, expected_data.version); + assert_eq!(resp_data, expected_data); + } + } } diff --git a/pox-locking/src/events.rs b/pox-locking/src/events.rs index 3fc16954bf2..cc4fc8f539e 100644 --- a/pox-locking/src/events.rs +++ b/pox-locking/src/events.rs @@ -16,7 +16,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::LimitedCostTracker; -use clarity::vm::errors::Error as ClarityError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, ResponseData, TupleData}; use clarity::vm::Value; #[cfg(any(test, feature = "testing"))] @@ -565,7 +565,7 @@ pub fn synthesize_pox_event_info( function_name: &str, args: &[Value], response: &ResponseData, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // the first thing we do is check the current epoch. In Epochs <= 2.4, // synthesizing PoX events was an assessed cost, so event generation // must remain identical. @@ -610,7 +610,7 @@ fn inner_synthesize_pox_event_info( function_name: &str, args: &[Value], response: &ResponseData, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { let sender = match sender_opt { Some(sender) => sender, None => { @@ -687,7 +687,7 @@ fn inner_synthesize_pox_event_info( Ok(Value::Tuple(event_tuple)) }, ) - .map_err(|e: ClarityError| { + .map_err(|e: VmExecutionError| { error!("Failed to synthesize PoX event: {:?}", &e); e })?; diff --git a/pox-locking/src/events_24.rs b/pox-locking/src/events_24.rs index a23726b46e7..0a7e2b4397b 100644 --- a/pox-locking/src/events_24.rs +++ b/pox-locking/src/events_24.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use clarity::vm::contexts::GlobalContext; -use clarity::vm::errors::Error as ClarityError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, TupleData}; use clarity::vm::Value; #[cfg(any(test, feature = "testing"))] @@ -343,7 +343,7 @@ pub fn synthesize_pox_2_or_3_event_info( sender_opt: Option<&PrincipalData>, function_name: &str, args: &[Value], -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { let sender = match sender_opt { Some(sender) => sender, None => { @@ -419,7 +419,7 @@ pub fn synthesize_pox_2_or_3_event_info( Ok(Value::Tuple(event_tuple)) }, ) - .map_err(|e: ClarityError| { + .map_err(|e: VmExecutionError| { error!("Failed to synthesize PoX event: {:?}", &e); e })?; diff --git a/pox-locking/src/lib.rs b/pox-locking/src/lib.rs index 16c11c8af26..ee67990caab 100644 --- a/pox-locking/src/lib.rs +++ b/pox-locking/src/lib.rs @@ -26,7 +26,7 @@ //! invoked. If so, it updates the PoX lock. use clarity::boot_util::boot_code_id; use clarity::vm::contexts::GlobalContext; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::Value; use stacks_common::types::StacksEpochId; @@ -48,11 +48,11 @@ pub enum LockingError { PoxExtendNotLocked, PoxIncreaseOnV1, PoxInvalidIncrease, - Clarity(ClarityError), + Clarity(VmExecutionError), } -impl From for LockingError { - fn from(e: ClarityError) -> LockingError { +impl From for LockingError { + fn from(e: VmExecutionError) -> LockingError { LockingError::Clarity(e) } } @@ -71,7 +71,7 @@ pub fn handle_contract_call_special_cases( function_name: &str, args: &[Value], result: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { if *contract_id == boot_code_id(POX_1_NAME, global_context.mainnet) { if !pox_1::is_read_only(function_name) && global_context.database.get_v1_unlock_height() @@ -86,8 +86,8 @@ pub fn handle_contract_call_special_cases( "function_name" => function_name, "contract_id" => %contract_id ); - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } @@ -101,8 +101,8 @@ pub fn handle_contract_call_special_cases( "function_name" => function_name, "contract_id" => %contract_id ); - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } @@ -124,8 +124,8 @@ pub fn handle_contract_call_special_cases( "function_name" => function_name, "contract_id" => %contract_id ); - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } diff --git a/pox-locking/src/pox_1.rs b/pox-locking/src/pox_1.rs index 4cc7ffe0ea5..f4860554c10 100644 --- a/pox-locking/src/pox_1.rs +++ b/pox-locking/src/pox_1.rs @@ -19,7 +19,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::runtime_cost; use clarity::vm::database::ClarityDatabase; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError}; use clarity::vm::events::{STXEventType, STXLockEventData, StacksTransactionEvent}; use clarity::vm::types::PrincipalData; use clarity::vm::Value; @@ -131,7 +131,7 @@ pub fn handle_contract_call( _sender_opt: Option<&PrincipalData>, function_name: &str, value: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { if !(function_name == "stack-stx" || function_name == "delegate-stack-stx") { // only have work to do if the function is `stack-stx` or `delegate-stack-stx` return Ok(()); @@ -168,7 +168,7 @@ pub fn handle_contract_call( unlock_height, ) { Ok(_) => { - if let Some(batch) = global_context.event_batches.last_mut() { + if let Some((batch, _)) = global_context.event_batches.last_mut() { batch.events.push(StacksTransactionEvent::STXEvent( STXEventType::STXLockEvent(STXLockEventData { locked_amount, @@ -181,15 +181,15 @@ pub fn handle_contract_call( return Ok(()); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } Err(LockingError::PoxAlreadyLocked) => { // the caller tried to lock tokens into both pox-1 and pox-2 - return Err(ClarityError::Runtime( - RuntimeErrorType::PoxAlreadyLocked, + return Err(VmExecutionError::Runtime( + RuntimeError::PoxAlreadyLocked, None, )); } diff --git a/pox-locking/src/pox_2.rs b/pox-locking/src/pox_2.rs index 1cbb1cd7724..d1eb35fe552 100644 --- a/pox-locking/src/pox_2.rs +++ b/pox-locking/src/pox_2.rs @@ -19,7 +19,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::runtime_cost; use clarity::vm::database::{ClarityDatabase, STXBalance}; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError}; use clarity::vm::events::{STXEventType, STXLockEventData, StacksTransactionEvent}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::{Environment, Value}; @@ -295,7 +295,7 @@ fn handle_stack_lockup_pox_v2( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { debug!( "Handle special-case contract-call to {:?} {} (which returned {:?})", "PoX-2 contract", function_name, value @@ -332,15 +332,15 @@ fn handle_stack_lockup_pox_v2( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } Err(LockingError::PoxAlreadyLocked) => { // the caller tried to lock tokens into both pox-1 and pox-2 - return Err(ClarityError::Runtime( - RuntimeErrorType::PoxAlreadyLocked, + return Err(VmExecutionError::Runtime( + RuntimeError::PoxAlreadyLocked, None, )); } @@ -360,7 +360,7 @@ fn handle_stack_lockup_extension_pox_v2( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-2 contract has stored the extension information // and performed the extension checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -400,8 +400,8 @@ fn handle_stack_lockup_extension_pox_v2( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } @@ -424,7 +424,7 @@ fn handle_stack_lockup_increase_pox_v2( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-2 contract has stored the increase information // and performed the increase checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -463,8 +463,8 @@ fn handle_stack_lockup_increase_pox_v2( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } @@ -488,7 +488,7 @@ pub fn handle_contract_call( function_name: &str, args: &[Value], value: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { // Generate a synthetic print event for all functions that alter stacking state let print_event_opt = if let Value::Response(response) = value { if response.committed { @@ -539,7 +539,7 @@ pub fn handle_contract_call( }; // append the lockup event, so it looks as if the print event happened before the lock-up - if let Some(batch) = global_context.event_batches.last_mut() { + if let Some((batch, _)) = global_context.event_batches.last_mut() { if let Some(print_event) = print_event_opt { batch.events.push(print_event); } diff --git a/pox-locking/src/pox_3.rs b/pox-locking/src/pox_3.rs index 265ec592088..a8aadcd1555 100644 --- a/pox-locking/src/pox_3.rs +++ b/pox-locking/src/pox_3.rs @@ -19,7 +19,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::runtime_cost; use clarity::vm::database::{ClarityDatabase, STXBalance}; -use clarity::vm::errors::{Error as ClarityError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError}; use clarity::vm::events::{STXEventType, STXLockEventData, StacksTransactionEvent}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::{Environment, Value}; @@ -184,7 +184,7 @@ fn handle_stack_lockup_pox_v3( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { debug!( "Handle special-case contract-call to {:?} {} (which returned {:?})", boot_code_id(POX_3_NAME, global_context.mainnet), @@ -223,15 +223,15 @@ fn handle_stack_lockup_pox_v3( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } Err(LockingError::PoxAlreadyLocked) => { // the caller tried to lock tokens into multiple pox contracts - return Err(ClarityError::Runtime( - RuntimeErrorType::PoxAlreadyLocked, + return Err(VmExecutionError::Runtime( + RuntimeError::PoxAlreadyLocked, None, )); } @@ -251,7 +251,7 @@ fn handle_stack_lockup_extension_pox_v3( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-3 contract has stored the extension information // and performed the extension checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -291,8 +291,8 @@ fn handle_stack_lockup_extension_pox_v3( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } @@ -315,7 +315,7 @@ fn handle_stack_lockup_increase_pox_v3( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-3 contract has stored the increase information // and performed the increase checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -353,8 +353,8 @@ fn handle_stack_lockup_increase_pox_v3( return Ok(Some(event)); } Err(LockingError::DefunctPoxContract) => { - return Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + return Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )); } @@ -378,7 +378,7 @@ pub fn handle_contract_call( function_name: &str, args: &[Value], value: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { // Generate a synthetic print event for all functions that alter stacking state let print_event_opt = if let Value::Response(response) = value { if response.committed { @@ -429,7 +429,7 @@ pub fn handle_contract_call( }; // append the lockup event, so it looks as if the print event happened before the lock-up - if let Some(batch) = global_context.event_batches.last_mut() { + if let Some((batch, _)) = global_context.event_batches.last_mut() { if let Some(print_event) = print_event_opt { batch.events.push(print_event); } diff --git a/pox-locking/src/pox_4.rs b/pox-locking/src/pox_4.rs index 141299a1676..abd4e47f54c 100644 --- a/pox-locking/src/pox_4.rs +++ b/pox-locking/src/pox_4.rs @@ -19,7 +19,7 @@ use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::runtime_cost; use clarity::vm::database::{ClarityDatabase, STXBalance}; -use clarity::vm::errors::{Error as ClarityError, InterpreterError, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError, VmInternalError}; use clarity::vm::events::{STXEventType, STXLockEventData, StacksTransactionEvent}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::{Environment, Value}; @@ -154,7 +154,7 @@ fn handle_stack_lockup_pox_v4( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { debug!( "Handle special-case contract-call to {:?} {function_name} (which returned {value:?})", boot_code_id(POX_4_NAME, global_context.mainnet) @@ -195,14 +195,14 @@ fn handle_stack_lockup_pox_v4( })); Ok(Some(event)) } - Err(LockingError::DefunctPoxContract) => Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + Err(LockingError::DefunctPoxContract) => Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )), Err(LockingError::PoxAlreadyLocked) => { // the caller tried to lock tokens into multiple pox contracts - Err(ClarityError::Runtime( - RuntimeErrorType::PoxAlreadyLocked, + Err(VmExecutionError::Runtime( + RuntimeError::PoxAlreadyLocked, None, )) } @@ -220,7 +220,7 @@ fn handle_stack_lockup_extension_pox_v4( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-4 contract has stored the extension information // and performed the extension checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -262,8 +262,8 @@ fn handle_stack_lockup_extension_pox_v4( })); Ok(Some(event)) } - Err(LockingError::DefunctPoxContract) => Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + Err(LockingError::DefunctPoxContract) => Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )), Err(e) => { @@ -281,7 +281,7 @@ fn handle_stack_lockup_increase_pox_v4( global_context: &mut GlobalContext, function_name: &str, value: &Value, -) -> Result, ClarityError> { +) -> Result, VmExecutionError> { // in this branch case, the PoX-4 contract has stored the increase information // and performed the increase checks. Now, the VM needs to update the account locks // (because the locks cannot be applied directly from the Clarity code itself) @@ -323,8 +323,8 @@ fn handle_stack_lockup_increase_pox_v4( Ok(Some(event)) } - Err(LockingError::DefunctPoxContract) => Err(ClarityError::Runtime( - RuntimeErrorType::DefunctPoxContract, + Err(LockingError::DefunctPoxContract) => Err(VmExecutionError::Runtime( + RuntimeError::DefunctPoxContract, None, )), Err(e) => { @@ -344,7 +344,7 @@ pub fn handle_contract_call( function_name: &str, args: &[Value], value: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { // Generate a synthetic print event for all functions that alter stacking state let print_event_opt = if let Value::Response(response) = value { if response.committed { @@ -408,7 +408,7 @@ pub fn handle_contract_call( "sender" => ?sender_opt, "arg0" => ?args.first(), ); - return Err(ClarityError::Interpreter(InterpreterError::Expect( + return Err(VmExecutionError::Internal(VmInternalError::Expect( msg.into(), ))); } @@ -416,7 +416,7 @@ pub fn handle_contract_call( } // append the lockup event, so it looks as if the print event happened before the lock-up - if let Some(batch) = global_context.event_batches.last_mut() { + if let Some((batch, _)) = global_context.event_batches.last_mut() { if let Some(print_event) = print_event_opt { batch.events.push(print_event); } diff --git a/stacks-common/src/types/mod.rs b/stacks-common/src/types/mod.rs index fafe84a6c32..3544646dd2b 100644 --- a/stacks-common/src/types/mod.rs +++ b/stacks-common/src/types/mod.rs @@ -17,6 +17,7 @@ use std::cmp::Ordering; use std::fmt; use std::ops::{Deref, DerefMut, Index, IndexMut}; +use std::str::FromStr; use std::sync::LazyLock; #[cfg(feature = "rusqlite")] @@ -28,7 +29,12 @@ use crate::address::{ C32_ADDRESS_VERSION_MAINNET_MULTISIG, C32_ADDRESS_VERSION_MAINNET_SINGLESIG, C32_ADDRESS_VERSION_TESTNET_MULTISIG, C32_ADDRESS_VERSION_TESTNET_SINGLESIG, }; -use crate::consts::MICROSTACKS_PER_STACKS; +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, +}; use crate::types::chainstate::{StacksAddress, StacksPublicKey}; use crate::util::hash::Hash160; use crate::util::secp256k1::{MessageSignature, Secp256k1PublicKey}; @@ -95,9 +101,23 @@ pub const MINING_COMMITMENT_WINDOW: u8 = 6; // Only relevant for Nakamoto (epoch 3.x) pub const MINING_COMMITMENT_FREQUENCY_NAKAMOTO: u8 = 3; -#[repr(u32)] -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Copy, Serialize, Deserialize)] -pub enum StacksEpochId { +macro_rules! define_stacks_epochs { + ($($variant:ident = $value:expr),* $(,)?) => { + #[repr(u32)] + #[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)] + pub enum StacksEpochId { + $($variant = $value),* + } + + impl StacksEpochId { + pub const ALL: &'static [StacksEpochId] = &[ + $(StacksEpochId::$variant),* + ]; + } + }; +} + +define_stacks_epochs! { Epoch10 = 0x01000, Epoch20 = 0x02000, Epoch2_05 = 0x02005, @@ -112,6 +132,26 @@ pub enum StacksEpochId { Epoch33 = 0x03003, } +impl StacksEpochId { + /// Return the network epoch associated with the StacksEpochId + pub fn network_epoch(epoch: StacksEpochId) -> u8 { + match epoch { + StacksEpochId::Epoch10 => PEER_VERSION_EPOCH_1_0, + StacksEpochId::Epoch20 => PEER_VERSION_EPOCH_2_0, + StacksEpochId::Epoch2_05 => PEER_VERSION_EPOCH_2_05, + StacksEpochId::Epoch21 => PEER_VERSION_EPOCH_2_1, + StacksEpochId::Epoch22 => PEER_VERSION_EPOCH_2_2, + StacksEpochId::Epoch23 => PEER_VERSION_EPOCH_2_3, + StacksEpochId::Epoch24 => PEER_VERSION_EPOCH_2_4, + StacksEpochId::Epoch25 => PEER_VERSION_EPOCH_2_5, + StacksEpochId::Epoch30 => PEER_VERSION_EPOCH_3_0, + StacksEpochId::Epoch31 => PEER_VERSION_EPOCH_3_1, + StacksEpochId::Epoch32 => PEER_VERSION_EPOCH_3_2, + StacksEpochId::Epoch33 => PEER_VERSION_EPOCH_3_3, + } + } +} + #[derive(Debug)] pub enum MempoolCollectionBehavior { ByStacksHeight, @@ -447,13 +487,6 @@ impl StacksEpochId { StacksEpochId::Epoch33 } - pub const ALL_GTE_30: &'static [StacksEpochId] = &[ - StacksEpochId::Epoch30, - StacksEpochId::Epoch31, - StacksEpochId::Epoch32, - StacksEpochId::Epoch33, - ]; - /// In this epoch, how should the mempool perform garbage collection? pub fn mempool_garbage_behavior(&self) -> MempoolCollectionBehavior { match self { @@ -867,6 +900,28 @@ impl std::fmt::Display for StacksEpochId { } } +impl FromStr for StacksEpochId { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s { + "1.0" => Ok(StacksEpochId::Epoch10), + "2.0" => Ok(StacksEpochId::Epoch20), + "2.05" => Ok(StacksEpochId::Epoch2_05), + "2.1" => Ok(StacksEpochId::Epoch21), + "2.2" => Ok(StacksEpochId::Epoch22), + "2.3" => Ok(StacksEpochId::Epoch23), + "2.4" => Ok(StacksEpochId::Epoch24), + "2.5" => Ok(StacksEpochId::Epoch25), + "3.0" => Ok(StacksEpochId::Epoch30), + "3.1" => Ok(StacksEpochId::Epoch31), + "3.2" => Ok(StacksEpochId::Epoch32), + "3.3" => Ok(StacksEpochId::Epoch33), + _ => Err("Invalid epoch string"), + } + } +} + impl TryFrom for StacksEpochId { type Error = &'static str; diff --git a/stacks-common/src/util/hash.rs b/stacks-common/src/util/hash.rs index 87e2ae018ba..05149684591 100644 --- a/stacks-common/src/util/hash.rs +++ b/stacks-common/src/util/hash.rs @@ -619,13 +619,35 @@ pub fn bin_bytes(s: &str) -> Result, HexError> { Ok(v) } +/// Precomputed hex characters for optimized conversion +const HEX_CHARS: [u8; 16] = *b"0123456789abcdef"; + +/// Convert a slice of u8 to a hex string, with optional "0x" prefix +pub fn to_hex_prefixed(s: &[u8], prefix: bool) -> String { + let prefix_len = if prefix { 2 } else { 0 }; + let mut bytes = Vec::with_capacity(s.len() * 2 + prefix_len); + + if prefix { + bytes.push(b'0'); + bytes.push(b'x'); + } + + for &b in s.iter() { + // get the first hex digit by shifting right 4 bits + bytes.push(HEX_CHARS[(b >> 4) as usize]); + + // get the second hex digit by masking the lower 4 bits + bytes.push(HEX_CHARS[(b & 0x0f) as usize]); + } + + // SAFETY: HEX_CHARS only contains valid ASCII characters, so this expect is safe + #[allow(clippy::expect_used)] + String::from_utf8(bytes).expect("Only valid UTF-8 characters (ASCII hex) should be present") +} + /// Convert a slice of u8 to a hex string pub fn to_hex(s: &[u8]) -> String { - let mut r = String::with_capacity(s.len() * 2); - for b in s.iter() { - write!(r, "{b:02x}").unwrap(); - } - r + to_hex_prefixed(s, false) } /// Convert a slice of u8 into a binary string diff --git a/stacks-node/Cargo.toml b/stacks-node/Cargo.toml index 615fe9571de..a43393aa622 100644 --- a/stacks-node/Cargo.toml +++ b/stacks-node/Cargo.toml @@ -33,10 +33,10 @@ http-types = { version = "2.12", default-features = false, optional = true } thiserror = { workspace = true } # This dependency is used for the multiversion integration tests which live behind the build-v3-1-0-0-13 feature flag -signer_v3_1_0_0_13 = { package = "stacks-signer", git = "https://github.com/stacks-network/stacks-core.git", rev="8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2", optional = true, features = ["testing", "default"]} -libsigner_v3_1_0_0_13 = { package = "libsigner", git = "https://github.com/stacks-network/stacks-core.git", rev="8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2", optional = true} -stacks_v3_1_00_13 = { package = "stackslib", git = "https://github.com/stacks-network/stacks-core.git", rev="8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2", optional = true, features = ["testing", "default"]} -stacks_common_v3_1_00_13 = { package = "stacks-common", git = "https://github.com/stacks-network/stacks-core.git", rev="8a79aaa7df0f13dfc5ab0d0d0bcb8201c90bcba2", optional = true, features = ["testing", "default"]} +signer_v3_3_0_0_1 = { package = "stacks-signer", git = "https://github.com/stacks-network/stacks-core.git", rev="b3efa588571e168d2d154790e1c57d9e3e64adc5", optional = true, features = ["testing", "default"]} +libsigner_v3_3_0_0_1 = { package = "libsigner", git = "https://github.com/stacks-network/stacks-core.git", rev="b3efa588571e168d2d154790e1c57d9e3e64adc5", optional = true} +stacks_v3_3_0_0_1 = { package = "stackslib", git = "https://github.com/stacks-network/stacks-core.git", rev="b3efa588571e168d2d154790e1c57d9e3e64adc5", optional = true, features = ["testing", "default"]} +stacks_common_v3_3_0_0_1 = { package = "stacks-common", git = "https://github.com/stacks-network/stacks-core.git", rev="b3efa588571e168d2d154790e1c57d9e3e64adc5", optional = true, features = ["testing", "default"]} [target.'cfg(not(any(target_os = "macos", target_os="windows", target_arch = "arm")))'.dependencies] tikv-jemallocator = {workspace = true} @@ -68,7 +68,7 @@ slog_json = ["stacks/slog_json", "stacks-common/slog_json", "clarity/slog_json"] prod-genesis-chainstate = [] default = [] testing = ["stacks-common/testing", "stacks/testing", "clarity/testing"] -build-signer-v3-1-0-0-13 = ["signer_v3_1_0_0_13", "libsigner_v3_1_0_0_13", "stacks_v3_1_00_13", "stacks_common_v3_1_00_13"] +build-signer-v3-3-0-0-1 = ["signer_v3_3_0_0_1", "libsigner_v3_3_0_0_1", "stacks_v3_3_0_0_1", "stacks_common_v3_3_0_0_1"] [package.metadata.pinny] allowed = ["bitcoind", "flaky", "slow"] diff --git a/stacks-node/src/burnchains/bitcoin_regtest_controller.rs b/stacks-node/src/burnchains/bitcoin_regtest_controller.rs index 506a75d2d67..276f9bf5fb7 100644 --- a/stacks-node/src/burnchains/bitcoin_regtest_controller.rs +++ b/stacks-node/src/burnchains/bitcoin_regtest_controller.rs @@ -3567,6 +3567,7 @@ mod tests { let mut config = utils::create_miner_config(); config.burnchain.local_mining_public_key = Some(miner_pubkey.to_hex()); + config.burnchain.pox_reward_length = Some(11); let mut btcd_controller = BitcoinCoreController::from_stx_config(&config); btcd_controller @@ -3626,6 +3627,7 @@ mod tests { let mut config = utils::create_miner_config(); config.burnchain.local_mining_public_key = Some(miner_pubkey.to_hex()); + config.burnchain.pox_reward_length = Some(11); let mut btcd_controller = BitcoinCoreController::from_stx_config(&config); btcd_controller @@ -3675,6 +3677,7 @@ mod tests { let mut config = utils::create_miner_config(); config.burnchain.local_mining_public_key = Some(miner_pubkey.to_hex()); + config.burnchain.pox_reward_length = Some(11); let mut btcd_controller = BitcoinCoreController::from_stx_config(&config); btcd_controller @@ -3726,6 +3729,7 @@ mod tests { let mut config = utils::create_miner_config(); config.burnchain.local_mining_public_key = Some(miner_pubkey.to_hex()); + config.burnchain.pox_reward_length = Some(11); let mut btcd_controller = BitcoinCoreController::from_stx_config(&config); btcd_controller @@ -3809,6 +3813,7 @@ mod tests { let mut config = utils::create_miner_config(); config.burnchain.local_mining_public_key = Some(miner_pubkey.to_hex()); + config.burnchain.pox_reward_length = Some(11); let mut btcd_controller = BitcoinCoreController::from_stx_config(&config); btcd_controller @@ -3882,6 +3887,7 @@ mod tests { let mut config = utils::create_miner_config(); config.burnchain.local_mining_public_key = Some(miner_pubkey.to_hex()); + config.burnchain.pox_reward_length = Some(11); let mut btcd_controller = BitcoinCoreController::from_stx_config(&config); btcd_controller @@ -3927,6 +3933,7 @@ mod tests { let mut config = utils::create_miner_config(); config.burnchain.local_mining_public_key = Some(miner_pubkey.to_hex()); + config.burnchain.pox_reward_length = Some(11); let mut btcd_controller = BitcoinCoreController::from_stx_config(&config); btcd_controller @@ -4063,6 +4070,7 @@ mod tests { let mut config = utils::create_miner_config(); config.burnchain.local_mining_public_key = Some(miner_pubkey.to_hex()); + config.burnchain.pox_reward_length = Some(11); let mut btcd_controller = BitcoinCoreController::from_stx_config(&config); btcd_controller diff --git a/stacks-node/src/event_dispatcher.rs b/stacks-node/src/event_dispatcher.rs index 87bac42019c..87fea966a87 100644 --- a/stacks-node/src/event_dispatcher.rs +++ b/stacks-node/src/event_dispatcher.rs @@ -68,7 +68,7 @@ use stacks::net::atlas::{Attachment, AttachmentInstance}; use stacks::net::http::HttpRequestContents; use stacks::net::httpcore::{send_http_request, StacksHttpRequest}; use stacks::net::stackerdb::StackerDBEventDispatcher; -use stacks::util::hash::to_hex; +use stacks::util::hash::{to_hex, to_hex_prefixed}; #[cfg(any(test, feature = "testing"))] use stacks::util::tests::TestFlag; use stacks::util_lib::db::Error as db_error; @@ -76,7 +76,7 @@ use stacks_common::bitvec::BitVec; use stacks_common::codec::StacksMessageCodec; use stacks_common::types::chainstate::{BlockHeaderHash, BurnchainHeaderHash, StacksBlockId}; use stacks_common::types::net::PeerHost; -use stacks_common::util::hash::{bytes_to_hex, Sha512Trunc256Sum}; +use stacks_common::util::hash::Sha512Trunc256Sum; use stacks_common::util::secp256k1::MessageSignature; use stacks_common::util::serde_serializers::{ prefix_hex, prefix_hex_codec, prefix_opt_hex, prefix_string_0x, @@ -374,17 +374,59 @@ pub struct TransactionEventPayload<'a> { static TEST_EVENT_OBSERVER_SKIP_RETRY: LazyLock> = LazyLock::new(TestFlag::default); impl EventObserver { + fn get_payload_column_type(conn: &Connection) -> Result, db_error> { + let mut stmt = conn.prepare("PRAGMA table_info(pending_payloads)")?; + let rows = stmt.query_map([], |row| { + let name: String = row.get(1)?; + let col_type: String = row.get(2)?; + Ok((name, col_type)) + })?; + + for row in rows { + let (name, col_type) = row?; + if name == "payload" { + return Ok(Some(col_type)); + } + } + + Ok(None) + } + + fn migrate_payload_column_to_blob(conn: &mut Connection) -> Result<(), db_error> { + let tx = conn.transaction()?; + tx.execute( + "ALTER TABLE pending_payloads RENAME TO pending_payloads_old", + [], + )?; + tx.execute( + "CREATE TABLE pending_payloads ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + url TEXT NOT NULL, + payload BLOB NOT NULL, + timeout INTEGER NOT NULL + )", + [], + )?; + tx.execute( + "INSERT INTO pending_payloads (id, url, payload, timeout) + SELECT id, url, CAST(payload AS BLOB), timeout FROM pending_payloads_old", + [], + )?; + tx.execute("DROP TABLE pending_payloads_old", [])?; + tx.commit()?; + Ok(()) + } + fn insert_payload( conn: &Connection, url: &str, - payload: &serde_json::Value, + payload_bytes: &[u8], timeout: Duration, ) -> Result<(), db_error> { - let payload_text = payload.to_string(); let timeout_ms: u64 = timeout.as_millis().try_into().expect("Timeout too large"); conn.execute( "INSERT INTO pending_payloads (url, payload, timeout) VALUES (?1, ?2, ?3)", - params![url, payload_text, timeout_ms], + params![url, payload_bytes, timeout_ms], )?; Ok(()) } @@ -393,7 +435,7 @@ impl EventObserver { fn insert_payload_with_retry( conn: &Connection, url: &str, - payload: &serde_json::Value, + payload_bytes: &[u8], timeout: Duration, ) { let mut attempts = 0i64; @@ -401,7 +443,7 @@ impl EventObserver { let max_backoff = Duration::from_secs(5); // Cap the backoff duration loop { - match Self::insert_payload(conn, url, payload, timeout) { + match Self::insert_payload(conn, url, payload_bytes, timeout) { Ok(_) => { // Successful insert, break the loop return; @@ -431,13 +473,13 @@ impl EventObserver { } fn send_payload_directly( - payload: &serde_json::Value, + payload_bytes: &Arc<[u8]>, full_url: &str, timeout: Duration, disable_retries: bool, ) -> bool { debug!( - "Event dispatcher: Sending payload"; "url" => %full_url, "payload" => ?payload + "Event dispatcher: Sending payload"; "url" => %full_url, "bytes" => payload_bytes.len() ); let url = Url::parse(full_url) @@ -459,7 +501,7 @@ impl EventObserver { peerhost.clone(), "POST".into(), url.path().into(), - HttpRequestContents::new().payload_json(payload.clone()), + HttpRequestContents::new().payload_json_bytes(Arc::clone(payload_bytes)), ) .unwrap_or_else(|_| panic!("FATAL: failed to encode infallible data as HTTP request")); request.add_header("Connection".into(), "close".into()); @@ -524,6 +566,19 @@ impl EventObserver { /// Send the payload to the given URL. /// Before sending this payload, any pending payloads in the database will be sent first. pub fn send_payload(&self, payload: &serde_json::Value, path: &str, id: Option) { + let payload_bytes = match serde_json::to_vec(payload) { + Ok(bytes) => Arc::<[u8]>::from(bytes), + Err(err) => { + error!( + "Event dispatcher: failed to serialize payload"; "path" => path, "error" => ?err + ); + return; + } + }; + self.send_payload_with_bytes(payload_bytes, path, id); + } + + fn send_payload_with_bytes(&self, payload_bytes: Arc<[u8]>, path: &str, id: Option) { // Construct the full URL let url_str = if path.starts_with('/') { format!("{}{path}", &self.endpoint) @@ -534,7 +589,7 @@ impl EventObserver { // if the observer is in "disable_retries" mode quickly send the payload without checking for the db if self.disable_retries { - Self::send_payload_directly(payload, &full_url, self.timeout, true); + Self::send_payload_directly(&payload_bytes, &full_url, self.timeout, true); } else if let Some(db_path) = &self.db_path { let conn = Connection::open(db_path).expect("Failed to open database for event observer"); @@ -542,12 +597,18 @@ impl EventObserver { let id = match id { Some(id) => id, None => { - Self::insert_payload_with_retry(&conn, &full_url, payload, self.timeout); + Self::insert_payload_with_retry( + &conn, + &full_url, + payload_bytes.as_ref(), + self.timeout, + ); conn.last_insert_rowid() } }; - let success = Self::send_payload_directly(payload, &full_url, self.timeout, false); + let success = + Self::send_payload_directly(&payload_bytes, &full_url, self.timeout, false); // This is only `false` when the TestFlag is set to skip retries if !success { return; @@ -561,16 +622,14 @@ impl EventObserver { } } else { // No database, just send the payload - Self::send_payload_directly(payload, &full_url, self.timeout, false); + Self::send_payload_directly(&payload_bytes, &full_url, self.timeout, false); } } fn make_new_mempool_txs_payload(transactions: Vec) -> serde_json::Value { let raw_txs = transactions .into_iter() - .map(|tx| { - serde_json::Value::String(format!("0x{}", &bytes_to_hex(&tx.serialize_to_vec()))) - }) + .map(|tx| serde_json::Value::String(to_hex_prefixed(&tx.serialize_to_vec(), true))) .collect(); serde_json::Value::Array(raw_txs) @@ -645,7 +704,7 @@ impl EventObserver { TransactionOrigin::Burn(op) => (op.txid(), "00".to_string(), Some(op.clone())), TransactionOrigin::Stacks(ref tx) => { let txid = tx.txid(); - let bytes = bytes_to_hex(&tx.serialize_to_vec()); + let bytes = to_hex(&tx.serialize_to_vec()); (txid, bytes, None) } }; @@ -683,7 +742,7 @@ impl EventObserver { "contract_id": format!("{}", attachment.0.contract_id), "metadata": format!("0x{}", attachment.0.metadata), "tx_id": format!("0x{}", attachment.0.tx_id), - "content": format!("0x{}", bytes_to_hex(&attachment.1.content)), + "content": to_hex_prefixed(&attachment.1.content, true), }) } @@ -1274,8 +1333,7 @@ impl EventDispatcher { block_timestamp: Option, coinbase_height: u64, ) { - let all_receipts = receipts.to_owned(); - let (dispatch_matrix, events) = self.create_dispatch_matrix_and_event_vector(&all_receipts); + let (dispatch_matrix, events) = self.create_dispatch_matrix_and_event_vector(receipts); if !dispatch_matrix.is_empty() { let mature_rewards_vec = if let Some(rewards_info) = mature_rewards_info { @@ -1660,7 +1718,10 @@ impl EventDispatcher { ); if conf.disable_retries { - warn!("Observer {} is configured in \"disable_retries\" mode: events are not guaranteed to be delivered", conf.endpoint); + warn!( + "Observer {} is configured in \"disable_retries\" mode: events are not guaranteed to be delivered", + conf.endpoint + ); } let observer_index = self.registered_observers.len() as u16; @@ -1731,34 +1792,39 @@ impl EventDispatcher { } fn init_db(db_path: &PathBuf) -> Result { - let conn = Connection::open(db_path.to_str().unwrap())?; + let mut conn = Connection::open(db_path.to_str().unwrap())?; conn.execute( "CREATE TABLE IF NOT EXISTS pending_payloads ( id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT NOT NULL, - payload TEXT NOT NULL, + payload BLOB NOT NULL, timeout INTEGER NOT NULL )", [], )?; + if let Some(col_type) = EventObserver::get_payload_column_type(&conn)? { + if col_type.eq_ignore_ascii_case("TEXT") { + info!("Event observer: migrating pending_payloads.payload from TEXT to BLOB"); + EventObserver::migrate_payload_column_to_blob(&mut conn)?; + } + } Ok(conn) } fn get_pending_payloads( conn: &Connection, - ) -> Result, db_error> { + ) -> Result, u64)>, db_error> { let mut stmt = conn.prepare("SELECT id, url, payload, timeout FROM pending_payloads ORDER BY id")?; let payload_iter = stmt.query_and_then( [], - |row| -> Result<(i64, String, serde_json::Value, u64), db_error> { + |row| -> Result<(i64, String, Arc<[u8]>, u64), db_error> { let id: i64 = row.get(0)?; let url: String = row.get(1)?; - let payload_text: String = row.get(2)?; - let payload: serde_json::Value = - serde_json::from_str(&payload_text).map_err(db_error::SerializationError)?; + let payload_bytes: Vec = row.get(2)?; + let payload_bytes = Arc::<[u8]>::from(payload_bytes); let timeout_ms: u64 = row.get(3)?; - Ok((id, url, payload, timeout_ms)) + Ok((id, url, payload_bytes, timeout_ms)) }, )?; payload_iter.collect() @@ -1792,7 +1858,7 @@ impl EventDispatcher { pending_payloads.len() ); - for (id, url, payload, _timeout_ms) in pending_payloads { + for (id, url, payload_bytes, _timeout_ms) in pending_payloads { info!("Event dispatcher: processing pending payload: {url}"); let full_url = Url::parse(url.as_str()) .unwrap_or_else(|_| panic!("Event dispatcher: unable to parse {url} as a URL")); @@ -1823,7 +1889,7 @@ impl EventDispatcher { continue; }; - observer.send_payload(&payload, full_url.path(), Some(id)); + observer.send_payload_with_bytes(payload_bytes, full_url.path(), Some(id)); #[cfg(test)] if TEST_EVENT_OBSERVER_SKIP_RETRY.get() { @@ -2093,6 +2159,55 @@ mod test { assert!(table_exists, "Table 'pending_payloads' does not exist"); } + #[test] + fn test_migrate_payload_column_to_blob() { + let dir = tempdir().unwrap(); + let db_path = dir.path().join("test_payload_migration.sqlite"); + + // Simulate old schema with TEXT payloads. + let conn = Connection::open(&db_path).unwrap(); + conn.execute( + "CREATE TABLE pending_payloads ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + url TEXT NOT NULL, + payload TEXT NOT NULL, + timeout INTEGER NOT NULL + )", + [], + ) + .unwrap(); + let payload_str = "{\"key\":\"value\"}"; + conn.execute( + "INSERT INTO pending_payloads (url, payload, timeout) VALUES (?1, ?2, ?3)", + params!["http://example.com/api", payload_str, 5000i64], + ) + .unwrap(); + drop(conn); + + let conn = EventDispatcher::init_db(&db_path).expect("Failed to initialize the database"); + + let col_type: String = conn + .query_row( + "SELECT type FROM pragma_table_info('pending_payloads') WHERE name = 'payload'", + [], + |row| row.get(0), + ) + .unwrap(); + assert!( + col_type.eq_ignore_ascii_case("BLOB"), + "Payload column was not migrated to BLOB" + ); + + let pending_payloads = + EventDispatcher::get_pending_payloads(&conn).expect("Failed to get pending payloads"); + assert_eq!(pending_payloads.len(), 1, "Expected one pending payload"); + assert_eq!( + pending_payloads[0].2.as_ref(), + payload_str.as_bytes(), + "Payload contents did not survive migration" + ); + } + #[test] fn test_insert_and_get_pending_payloads() { let dir = tempdir().unwrap(); @@ -2103,9 +2218,11 @@ mod test { let url = "http://example.com/api"; let payload = json!({"key": "value"}); let timeout = Duration::from_secs(5); + let payload_bytes = serde_json::to_vec(&payload).expect("Failed to serialize payload"); // Insert payload - let insert_result = EventObserver::insert_payload(&conn, url, &payload, timeout); + let insert_result = + EventObserver::insert_payload(&conn, url, payload_bytes.as_slice(), timeout); assert!(insert_result.is_ok(), "Failed to insert payload"); // Get pending payloads @@ -2113,9 +2230,13 @@ mod test { EventDispatcher::get_pending_payloads(&conn).expect("Failed to get pending payloads"); assert_eq!(pending_payloads.len(), 1, "Expected one pending payload"); - let (_id, retrieved_url, retrieved_payload, timeout_ms) = &pending_payloads[0]; + let (_id, retrieved_url, stored_bytes, timeout_ms) = &pending_payloads[0]; assert_eq!(retrieved_url, url, "URL does not match"); - assert_eq!(retrieved_payload, &payload, "Payload does not match"); + assert_eq!( + stored_bytes.as_ref(), + payload_bytes.as_slice(), + "Serialized payload does not match" + ); assert_eq!( *timeout_ms, timeout.as_millis() as u64, @@ -2133,9 +2254,10 @@ mod test { let url = "http://example.com/api"; let payload = json!({"key": "value"}); let timeout = Duration::from_secs(5); + let payload_bytes = serde_json::to_vec(&payload).expect("Failed to serialize payload"); // Insert payload - EventObserver::insert_payload(&conn, url, &payload, timeout) + EventObserver::insert_payload(&conn, url, payload_bytes.as_slice(), timeout) .expect("Failed to insert payload"); // Get pending payloads @@ -2179,6 +2301,7 @@ mod test { let conn = EventDispatcher::init_db(&db_path).expect("Failed to initialize the database"); let payload = json!({"key": "value"}); + let payload_bytes = serde_json::to_vec(&payload).expect("Failed to serialize payload"); let timeout = Duration::from_secs(5); let _m = server @@ -2193,7 +2316,7 @@ mod test { TEST_EVENT_OBSERVER_SKIP_RETRY.set(false); // Insert payload - EventObserver::insert_payload(&conn, url, &payload, timeout) + EventObserver::insert_payload(&conn, url, payload_bytes.as_slice(), timeout) .expect("Failed to insert payload"); // Process pending payloads @@ -2228,6 +2351,7 @@ mod test { let conn = EventDispatcher::init_db(&db_path).expect("Failed to initialize the database"); let payload = json!({"key": "value"}); + let payload_bytes = serde_json::to_vec(&payload).expect("Failed to serialize payload"); let timeout = Duration::from_secs(5); let mock = server @@ -2244,7 +2368,7 @@ mod test { // Use a different URL than the observer's endpoint let url = "http://different-domain.com/api"; - EventObserver::insert_payload(&conn, url, &payload, timeout) + EventObserver::insert_payload(&conn, url, payload_bytes.as_slice(), timeout) .expect("Failed to insert payload"); dispatcher.process_pending_payloads(); diff --git a/stacks-node/src/nakamoto_node/miner.rs b/stacks-node/src/nakamoto_node/miner.rs index 86b5a4985f7..e601ceb2558 100644 --- a/stacks-node/src/nakamoto_node/miner.rs +++ b/stacks-node/src/nakamoto_node/miner.rs @@ -193,6 +193,12 @@ pub enum MinerReason { /// sortition. burn_view_consensus_hash: ConsensusHash, }, + /// Issue a read-count only extension + ReadCountExtend { + /// Current consensus hash on the underlying burnchain. Corresponds to the last-seen + /// sortition. + burn_view_consensus_hash: ConsensusHash, + }, } impl MinerReason { @@ -200,6 +206,7 @@ impl MinerReason { match self { Self::BlockFound { ref late } => *late, Self::Extended { .. } => false, + Self::ReadCountExtend { .. } => false, } } } @@ -216,6 +223,12 @@ impl std::fmt::Display for MinerReason { f, "Extended: burn_view_consensus_hash = {burn_view_consensus_hash:?}", ), + MinerReason::ReadCountExtend { + burn_view_consensus_hash, + } => write!( + f, + "Read-Count Extend: burn_view_consensus_hash = {burn_view_consensus_hash:?}", + ), } } } @@ -272,6 +285,20 @@ pub struct BlockMinerThread { miner_db: MinerDB, } +/// Trait for the coordinator's read count extend timestamp check. +/// This trait is used so that we can unit test the function more easily. +trait ReadCountCheck { + /// Get the timestamp at which at least 70% of the signing power should be + /// willing to accept a time-based read-count extension. + fn get_read_count_extend_timestamp(&self) -> u64; +} + +impl ReadCountCheck for SignerCoordinator { + fn get_read_count_extend_timestamp(&self) -> u64 { + SignerCoordinator::get_read_count_extend_timestamp(self) + } +} + impl BlockMinerThread { /// Instantiate the miner thread pub fn new( @@ -1628,6 +1655,92 @@ impl BlockMinerThread { .map_err(NakamotoNodeError::from) } + fn should_full_tenure_extend( + &self, + coordinator: &mut SignerCoordinator, + ) -> Result { + if self.last_block_mined.is_none() { + // if we haven't mined blocks yet, no tenure extends needed + return Ok(false); + } + let is_replay = self.config.miner.replay_transactions + && coordinator + .get_signer_global_state() + .map(|state| state.tx_replay_set.is_some()) + .unwrap_or(false); + if is_replay { + // we're in replay, we should always TenureExtend + info!("Tenure extend: In replay, always extending tenure"); + return Ok(true); + } + + // Do not extend if we have spent a threshold amount of the + // budget, since it is not necessary. + let usage = self + .tenure_budget + .proportion_largest_dimension(&self.tenure_cost); + if usage < self.config.miner.tenure_extend_cost_threshold { + return Ok(false); + } + + let tenure_extend_timestamp = coordinator.get_tenure_extend_timestamp(); + if get_epoch_time_secs() <= tenure_extend_timestamp + && self.tenure_change_time.elapsed() <= self.config.miner.tenure_timeout + { + return Ok(false); + } + + info!("Miner: Time-based tenure extend"; + "current_timestamp" => get_epoch_time_secs(), + "tenure_extend_timestamp" => tenure_extend_timestamp, + "tenure_change_time_elapsed" => self.tenure_change_time.elapsed().as_secs(), + "tenure_timeout_secs" => self.config.miner.tenure_timeout.as_secs(), + ); + Ok(true) + } + + fn should_read_count_extend( + &self, + coordinator: &C, + ) -> Result { + if self.last_block_mined.is_none() { + // if we haven't mined blocks yet, no tenure extends needed + return Ok(false); + } + + // Do not extend if we have spent a threshold amount of the + // read-count budget, since it is not necessary. + let usage = + self.tenure_cost.read_count / std::cmp::max(1, self.tenure_budget.read_count / 100); + + if usage < self.config.miner.read_count_extend_cost_threshold { + info!( + "Miner: not read-count extending because threshold not reached"; + "threshold" => self.config.miner.read_count_extend_cost_threshold, + "usage" => usage + ); + return Ok(false); + } + + let tenure_extend_timestamp = coordinator.get_read_count_extend_timestamp(); + if get_epoch_time_secs() <= tenure_extend_timestamp { + info!( + "Miner: not read-count extending because idle timestamp not reached"; + "now" => get_epoch_time_secs(), + "extend_ts" => tenure_extend_timestamp, + ); + return Ok(false); + } + + info!("Miner: Time-based read-count extend"; + "current_timestamp" => get_epoch_time_secs(), + "tenure_extend_timestamp" => tenure_extend_timestamp, + "tenure_change_time_elapsed" => self.tenure_change_time.elapsed().as_secs(), + "tenure_timeout_secs" => self.config.miner.tenure_timeout.as_secs(), + ); + Ok(true) + } + #[cfg_attr(test, mutants::skip)] /// Create the tenure start info for the block we're going to build fn make_tenure_start_info( @@ -1656,47 +1769,18 @@ impl BlockMinerThread { } } }; - // Check if we can and should include a time-based tenure extend. if self.last_block_mined.is_some() { - if self.config.miner.replay_transactions - && coordinator - .get_signer_global_state() - .map(|state| state.tx_replay_set.is_some()) - .unwrap_or(false) - { - // we're in replay, we should always TenureExtend - info!("Tenure extend: In replay, always extending tenure"); - self.tenure_extend_reset(); + // if we've already mined blocks, we only issue tenure_change_txs in the case of an extend, + // so check if that's necessary and otherwise return None. + if self.should_full_tenure_extend(coordinator)? { + self.set_full_tenure_extend(); + } else if self.should_read_count_extend(coordinator)? { + self.set_read_count_tenure_extend(); } else { - // Do not extend if we have spent < 50% of the budget, since it is - // not necessary. - let usage = self - .tenure_budget - .proportion_largest_dimension(&self.tenure_cost); - if usage < self.config.miner.tenure_extend_cost_threshold { - return Ok(NakamotoTenureInfo { - coinbase_tx: None, - tenure_change_tx: None, - }); - } - - let tenure_extend_timestamp = coordinator.get_tenure_extend_timestamp(); - if get_epoch_time_secs() <= tenure_extend_timestamp - && self.tenure_change_time.elapsed() <= self.config.miner.tenure_timeout - { - return Ok(NakamotoTenureInfo { - coinbase_tx: None, - tenure_change_tx: None, - }); - } - - info!("Miner: Time-based tenure extend"; - "current_timestamp" => get_epoch_time_secs(), - "tenure_extend_timestamp" => tenure_extend_timestamp, - "tenure_change_time_elapsed" => self.tenure_change_time.elapsed().as_secs(), - "tenure_timeout_secs" => self.config.miner.tenure_timeout.as_secs(), - ); - self.tenure_extend_reset(); + return Ok(NakamotoTenureInfo { + coinbase_tx: None, + tenure_change_tx: None, + }); } } @@ -1742,6 +1826,30 @@ impl BlockMinerThread { let tenure_change_tx = self.generate_tenure_change_tx(current_miner_nonce, payload); (Some(tenure_change_tx), None) } + MinerReason::ReadCountExtend { + burn_view_consensus_hash, + } => { + let num_blocks_so_far = NakamotoChainState::get_nakamoto_tenure_length( + chainstate.db(), + &parent_block_id, + ) + .map_err(NakamotoNodeError::MiningFailure)?; + info!("Miner: Extending read-count"; + "burn_view_consensus_hash" => %burn_view_consensus_hash, + "parent_block_id" => %parent_block_id, + "num_blocks_so_far" => num_blocks_so_far, + ); + + // NOTE: this switches payload.cause to TenureChangeCause::Extend + payload = payload.extend_with_cause( + burn_view_consensus_hash.clone(), + parent_block_id, + num_blocks_so_far, + TenureChangeCause::ExtendedReadCount, + ); + let tenure_change_tx = self.generate_tenure_change_tx(current_miner_nonce, payload); + (Some(tenure_change_tx), None) + } }; debug!( @@ -1773,13 +1881,23 @@ impl BlockMinerThread { } } - fn tenure_extend_reset(&mut self) { + /// Set up the miner to try to issue a full tenure extend + fn set_full_tenure_extend(&mut self) { self.tenure_change_time = Instant::now(); self.reason = MinerReason::Extended { burn_view_consensus_hash: self.burn_block.consensus_hash.clone(), }; self.mined_blocks = 0; } + + /// Set up the miner to try to issue a full tenure extend + fn set_read_count_tenure_extend(&mut self) { + self.tenure_change_time = Instant::now(); + self.reason = MinerReason::ReadCountExtend { + burn_view_consensus_hash: self.burn_block.consensus_hash.clone(), + }; + self.mined_blocks = 0; + } } impl ParentStacksBlockInfo { @@ -1922,3 +2040,108 @@ impl ParentStacksBlockInfo { }) } } + +#[cfg(test)] +impl ReadCountCheck for () { + fn get_read_count_extend_timestamp(&self) -> u64 { + // always allow the read count extend + 0 + } +} + +#[test] +fn should_read_count_extend_units() { + let (sync_sender, _rcv_1) = std::sync::mpsc::sync_channel(1); + let (relay_sender, _rcv_2) = std::sync::mpsc::sync_channel(1); + let (_coord_rcv, coord_comms) = + stacks::chainstate::coordinator::comm::CoordinatorCommunication::instantiate(); + let mut miner = BlockMinerThread { + config: Config::default(), + globals: Globals::new( + coord_comms, + Arc::new(std::sync::Mutex::new( + stacks::chainstate::stacks::miner::MinerStatus::make_ready(10), + )), + relay_sender, + crate::neon::Counters::new(), + crate::syncctl::PoxSyncWatchdogComms::new(Arc::new(AtomicBool::new(true))), + Arc::new(AtomicBool::new(true)), + 0, + neon_node::LeaderKeyRegistrationState::Inactive, + ), + keychain: Keychain::default(vec![]), + burnchain: Burnchain::regtest("/dev/null"), + last_block_mined: Some((ConsensusHash([0; 20]), BlockHeaderHash([0; 32]))), + mined_blocks: 1, + tenure_cost: ExecutionCost::ZERO, + tenure_budget: ExecutionCost::ZERO, + registered_key: RegisteredKey { + target_block_height: 0, + block_height: 0, + op_vtxindex: 0, + vrf_public_key: stacks::util::vrf::VRFPublicKey::from_private( + &stacks::util::vrf::VRFPrivateKey::new(), + ), + memo: vec![], + }, + burn_election_block: BlockSnapshot::empty(), + burn_block: BlockSnapshot::empty(), + parent_tenure_id: StacksBlockId([0; 32]), + event_dispatcher: EventDispatcher::new(None), + reason: MinerReason::Extended { + burn_view_consensus_hash: ConsensusHash([0; 20]), + }, + p2p_handle: NetworkHandle::new(sync_sender), + signer_set_cache: None, + tenure_change_time: Instant::now(), + burn_tip_at_start: ConsensusHash([0; 20]), + abort_flag: Arc::new(AtomicBool::new(false)), + reset_mempool_caches: false, + miner_db: MinerDB::open("/tmp/should_read_count_extend_units.db").unwrap(), + }; + miner.config.miner.read_count_extend_cost_threshold = 20; + + miner.tenure_cost = ExecutionCost { + write_length: 1000, + write_count: 1000, + read_length: 1000, + read_count: 199, + runtime: 1000, + }; + + miner.tenure_budget = ExecutionCost { + write_length: 1000, + write_count: 1000, + read_length: 1000, + read_count: 1000, + runtime: 1000, + }; + + assert_eq!( + miner.should_read_count_extend(&()).unwrap(), + false, + "When read_count is below the configured threshold, we shouldn't try to extend" + ); + + miner.tenure_cost = ExecutionCost { + write_length: 1000, + write_count: 1000, + read_length: 1000, + read_count: 200, + runtime: 1000, + }; + + miner.tenure_budget = ExecutionCost { + write_length: 1000, + write_count: 1000, + read_length: 1000, + read_count: 1000, + runtime: 1000, + }; + + assert_eq!( + miner.should_read_count_extend(&()).unwrap(), + true, + "When read_count is at the configured threshhold, we should try to extend" + ); +} diff --git a/stacks-node/src/nakamoto_node/signer_coordinator.rs b/stacks-node/src/nakamoto_node/signer_coordinator.rs index 8876c127626..9a90acc056c 100644 --- a/stacks-node/src/nakamoto_node/signer_coordinator.rs +++ b/stacks-node/src/nakamoto_node/signer_coordinator.rs @@ -516,6 +516,13 @@ impl SignerCoordinator { .get_tenure_extend_timestamp(self.weight_threshold) } + /// Get the timestamp at which at least 70% of the signing power should be + /// willing to accept a time-based read-count extension. + pub fn get_read_count_extend_timestamp(&self) -> u64 { + self.stackerdb_comms + .get_read_count_extend_timestamp(self.weight_threshold) + } + /// Get the signer global state view if there is one pub fn get_signer_global_state(&self) -> Option { self.stackerdb_comms.get_signer_global_state() diff --git a/stacks-node/src/nakamoto_node/stackerdb_listener.rs b/stacks-node/src/nakamoto_node/stackerdb_listener.rs index 71c262c0bea..28cd911fcb1 100644 --- a/stacks-node/src/nakamoto_node/stackerdb_listener.rs +++ b/stacks-node/src/nakamoto_node/stackerdb_listener.rs @@ -101,6 +101,11 @@ pub struct StackerDBListener { /// - key: StacksPublicKey /// - value: TimestampInfo pub(crate) signer_idle_timestamps: Arc>>, + /// Tracks the timestamps from signers to decide when they should be + /// willing to accept time-based read-count extensions + /// - key: StacksPublicKey + /// - value: TimestampInfo + pub(crate) signer_read_count_timestamps: Arc>>, /// Tracks the signer's global state machine through signer state machine update messages pub(crate) global_state_evaluator: Arc>, /// Wehther we are operating on mainnet @@ -118,6 +123,11 @@ pub struct StackerDBListenerComms { /// - key: StacksPublicKey /// - value: TimestampInfo signer_idle_timestamps: Arc>>, + /// Tracks the timestamps from signers to decide when they should be + /// willing to accept time-based read-count extensions + /// - key: StacksPublicKey + /// - value: TimestampInfo + signer_read_count_timestamps: Arc>>, /// Tracks the signer's global state machine through signer state machine update messages global_state_evaluator: Arc>, } @@ -226,6 +236,7 @@ impl StackerDBListener { signer_idle_timestamps: Arc::new(Mutex::new(HashMap::new())), global_state_evaluator: Arc::new(Mutex::new(global_state_evaluator)), is_mainnet: config.is_mainnet(), + signer_read_count_timestamps: Arc::new(Mutex::new(HashMap::new())), }) } @@ -234,6 +245,7 @@ impl StackerDBListener { blocks: self.blocks.clone(), signer_idle_timestamps: self.signer_idle_timestamps.clone(), global_state_evaluator: self.global_state_evaluator.clone(), + signer_read_count_timestamps: self.signer_read_count_timestamps.clone(), } } @@ -337,6 +349,8 @@ impl StackerDBListener { response_data, } = accepted; let tenure_extend_timestamp = response_data.tenure_extend_timestamp; + let read_count_extend_timestamp = + response_data.tenure_extend_read_count_timestamp; let (lock, cvar) = &*self.blocks; let mut blocks = lock.lock().expect("FATAL: failed to lock block status"); @@ -402,6 +416,7 @@ impl StackerDBListener { "percent_rejected" => block.total_weight_rejected as f64 / self.total_weight as f64 * 100.0, "weight_threshold" => self.weight_threshold, "tenure_extend_timestamp" => tenure_extend_timestamp, + "read_count_extend_timestamp" => read_count_extend_timestamp, "server_version" => metadata.server_version, ); } @@ -415,10 +430,17 @@ impl StackerDBListener { // Update the idle timestamp for this signer self.update_idle_timestamp( - signer_pubkey, + signer_pubkey.clone(), tenure_extend_timestamp, signer_entry.weight, ); + + // Update the read-count timestamp for this signer + self.update_read_count_timestamp( + signer_pubkey, + read_count_extend_timestamp, + signer_entry.weight, + ); } SignerMessageV0::BlockResponse(BlockResponse::Rejected(rejected_data)) => { let (lock, cvar) = &*self.blocks; @@ -484,10 +506,19 @@ impl StackerDBListener { // Update the idle timestamp for this signer self.update_idle_timestamp( - signer_pubkey, + signer_pubkey.clone(), rejected_data.response_data.tenure_extend_timestamp, signer_entry.weight, ); + + // Update the read-count timestamp for this signer + self.update_read_count_timestamp( + signer_pubkey, + rejected_data + .response_data + .tenure_extend_read_count_timestamp, + signer_entry.weight, + ); } SignerMessageV0::BlockProposal(_) => { debug!("Received block proposal message. Ignoring."); @@ -530,6 +561,30 @@ impl StackerDBListener { idle_timestamps.insert(signer_pubkey, timestamp_info); } + fn update_read_count_timestamp( + &self, + signer_pubkey: StacksPublicKey, + timestamp: u64, + weight: u32, + ) { + let mut timestamps = self + .signer_read_count_timestamps + .lock() + .expect("FATAL: failed to lock idle timestamps"); + + // Check the current timestamp for the given signer_pubkey + if let Some(existing_info) = timestamps.get(&signer_pubkey) { + // Only update if the new timestamp is greater + if timestamp <= existing_info.timestamp { + return; // Exit early if the new timestamp is not greater + } + } + + // Update the map with the new timestamp and weight + let timestamp_info = TimestampInfo { timestamp, weight }; + timestamps.insert(signer_pubkey, timestamp_info); + } + fn update_global_state_evaluator(&self, pubkey: &StacksPublicKey, update: StateMachineUpdate) { let mut eval = self .global_state_evaluator @@ -646,21 +701,46 @@ impl StackerDBListenerComms { .lock() .expect("FATAL: failed to lock signer idle timestamps"); debug!("SignerCoordinator: signer_idle_timestamps: {signer_idle_timestamps:?}"); - let mut idle_timestamps = signer_idle_timestamps.values().collect::>(); - idle_timestamps.sort_by_key(|info| info.timestamp); + Self::find_weighted_timestamp_by_threshold( + weight_threshold, + signer_idle_timestamps.values(), + ) + } + + /// Get the timestamp at which at least 70% of the signing power should be + /// willing to accept a time-based tenure extension. + pub fn get_read_count_extend_timestamp(&self, weight_threshold: u32) -> u64 { + let signer_read_count_timestamps = self + .signer_read_count_timestamps + .lock() + .expect("FATAL: failed to lock signer idle timestamps"); + debug!("SignerCoordinator: signer_read_count_timestamps: {signer_read_count_timestamps:?}"); + Self::find_weighted_timestamp_by_threshold( + weight_threshold, + signer_read_count_timestamps.values(), + ) + } + + fn find_weighted_timestamp_by_threshold<'a, T: Iterator>( + weight_threshold: u32, + timestamps: T, + ) -> u64 { + let mut timestamps: Vec<_> = timestamps.collect(); + timestamps.sort_by_key(|info| info.timestamp); let mut weight_sum = 0; - for info in idle_timestamps { + for info in timestamps { weight_sum += info.weight; if weight_sum >= weight_threshold { - debug!("SignerCoordinator: 70% threshold reached for tenure extension timestamp"; - "tenure_extend_timestamp" => info.timestamp, - "tenure_extend_in" => (info.timestamp as i64 - get_epoch_time_secs() as i64) + debug!("SignerCoordinator: threshold reached for tenure extension timestamp"; + "weight_threshold" => weight_threshold, + "tenure_extend_timestamp" => info.timestamp, + "tenure_extend_in" => (info.timestamp as i64 - get_epoch_time_secs() as i64) ); return info.timestamp; } } - // We don't have enough information to reach a 70% threshold at any + // We don't have enough information to reach a threshold at any // time, so return u64::MAX to indicate that we should not extend the // tenure. u64::MAX diff --git a/stacks-node/src/tests/epoch_205.rs b/stacks-node/src/tests/epoch_205.rs index 32d9bf793ab..8e9ad1c1060 100644 --- a/stacks-node/src/tests/epoch_205.rs +++ b/stacks-node/src/tests/epoch_205.rs @@ -18,7 +18,7 @@ use stacks::core::test_util::{ }; use stacks::core::{ self, EpochList, StacksEpoch, StacksEpochId, PEER_VERSION_EPOCH_1_0, PEER_VERSION_EPOCH_2_0, - PEER_VERSION_EPOCH_2_05, PEER_VERSION_EPOCH_2_1, + PEER_VERSION_EPOCH_2_05, PEER_VERSION_EPOCH_2_1, STACKS_EPOCH_MAX, }; use stacks_common::codec::StacksMessageCodec; use stacks_common::types::chainstate::{BlockHeaderHash, BurnchainHeaderHash, VRFSeed}; @@ -53,6 +53,10 @@ fn test_exact_block_costs() { let mut epochs = EpochList::new(&*core::STACKS_EPOCHS_REGTEST); epochs[StacksEpochId::Epoch20].end_height = epoch_205_transition_height; epochs[StacksEpochId::Epoch2_05].start_height = epoch_205_transition_height; + epochs[StacksEpochId::Epoch2_05].end_height = epoch_205_transition_height + 100; + epochs[StacksEpochId::Epoch21].start_height = epoch_205_transition_height + 100; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); conf.node.mine_microblocks = true; @@ -299,6 +303,10 @@ fn test_dynamic_db_method_costs() { let mut epochs = EpochList::new(&*core::STACKS_EPOCHS_REGTEST); epochs[StacksEpochId::Epoch20].end_height = epoch_205_transition_height; epochs[StacksEpochId::Epoch2_05].start_height = epoch_205_transition_height; + epochs[StacksEpochId::Epoch2_05].end_height = epoch_205_transition_height + 100; + epochs[StacksEpochId::Epoch21].start_height = epoch_205_transition_height + 100; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); @@ -501,6 +509,10 @@ fn transition_empty_blocks() { let mut epochs = EpochList::new(&*core::STACKS_EPOCHS_REGTEST); epochs[StacksEpochId::Epoch20].end_height = epoch_2_05; epochs[StacksEpochId::Epoch2_05].start_height = epoch_2_05; + epochs[StacksEpochId::Epoch2_05].end_height = epoch_2_05 + 100; + epochs[StacksEpochId::Epoch21].start_height = epoch_2_05 + 100; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); diff --git a/stacks-node/src/tests/epoch_21.rs b/stacks-node/src/tests/epoch_21.rs index 16e1dbfc389..e95847c268a 100644 --- a/stacks-node/src/tests/epoch_21.rs +++ b/stacks-node/src/tests/epoch_21.rs @@ -3,7 +3,7 @@ use std::{env, thread}; use ::core::str; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; -use clarity::vm::{ClarityVersion, Value}; +use clarity::vm::{execute_with_parameters as execute, ClarityVersion, Value}; use stacks::burnchains::bitcoin::address::{ BitcoinAddress, LegacyBitcoinAddressType, SegwitBitcoinAddress, }; @@ -23,10 +23,9 @@ use stacks::chainstate::stacks::miner::{ set_mining_spend_amount, signal_mining_blocked, signal_mining_ready, }; use stacks::chainstate::stacks::StacksBlockHeader; -use stacks::clarity_cli::vm_execute as execute; use stacks::config::{Config, InitialBalance}; use stacks::core::test_util::make_contract_call; -use stacks::core::{self, EpochList, BURNCHAIN_TX_SEARCH_WINDOW}; +use stacks::core::{self, EpochList, BURNCHAIN_TX_SEARCH_WINDOW, STACKS_EPOCH_MAX}; use stacks::util_lib::boot::boot_code_id; use stacks_common::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, StacksAddress, StacksBlockId, VRFSeed, @@ -79,6 +78,8 @@ fn advance_to_2_1( epochs[StacksEpochId::Epoch2_05].start_height = epoch_2_05; epochs[StacksEpochId::Epoch2_05].end_height = epoch_2_1; epochs[StacksEpochId::Epoch21].start_height = epoch_2_1; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); @@ -580,6 +581,8 @@ fn transition_fixes_bitcoin_rigidity() { epochs[StacksEpochId::Epoch2_05].start_height = epoch_2_05; epochs[StacksEpochId::Epoch2_05].end_height = epoch_2_1; epochs[StacksEpochId::Epoch21].start_height = epoch_2_1; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); @@ -1089,6 +1092,8 @@ fn transition_adds_get_pox_addr_recipients() { &(*addr_variant as u8) ), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -1129,6 +1134,8 @@ fn transition_adds_get_pox_addr_recipients() { let pox_addr_tuple = execute( &format!("{{ hashbytes: 0x{bytes}, version: 0x{version:02x} }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -1476,6 +1483,8 @@ fn transition_removes_pox_sunset() { epochs[StacksEpochId::Epoch2_05].start_height = 1; epochs[StacksEpochId::Epoch2_05].end_height = epoch_21; epochs[StacksEpochId::Epoch21].start_height = epoch_21; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); @@ -1565,6 +1574,8 @@ fn transition_removes_pox_sunset() { execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash}, version: 0x00 }}"), ClarityVersion::Clarity1, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(), @@ -1622,6 +1633,8 @@ fn transition_removes_pox_sunset() { execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(), @@ -1731,6 +1744,8 @@ fn transition_empty_blocks() { epochs[StacksEpochId::Epoch2_05].start_height = epoch_2_05; epochs[StacksEpochId::Epoch2_05].end_height = epoch_2_1; epochs[StacksEpochId::Epoch21].start_height = epoch_2_1; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.node.mine_microblocks = false; conf.burnchain.max_rbf = 1000000; @@ -2006,6 +2021,8 @@ fn test_sortition_divergence_pre_21() { epochs[StacksEpochId::Epoch2_05].start_height = 101; epochs[StacksEpochId::Epoch2_05].end_height = 241; epochs[StacksEpochId::Epoch21].start_height = 241; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf_template.burnchain.epochs = Some(epochs); let privks: Vec<_> = (0..5).map(|_| StacksPrivateKey::random()).collect(); @@ -2222,6 +2239,8 @@ fn test_sortition_divergence_pre_21() { execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash}, version: 0x00 }}"), ClarityVersion::Clarity1, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(), @@ -2438,6 +2457,8 @@ fn trait_invocation_cross_epoch() { epochs[StacksEpochId::Epoch2_05].start_height = epoch_2_05; epochs[StacksEpochId::Epoch2_05].end_height = epoch_2_1; epochs[StacksEpochId::Epoch21].start_height = epoch_2_1; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); let mut burnchain_config = Burnchain::regtest(&conf.get_burn_db_path()); @@ -2703,6 +2724,8 @@ fn test_v1_unlock_height_with_current_stackers() { epochs[StacksEpochId::Epoch2_05].start_height = epoch_2_05; epochs[StacksEpochId::Epoch2_05].end_height = epoch_2_1; epochs[StacksEpochId::Epoch21].start_height = epoch_2_1; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); let mut burnchain_config = Burnchain::regtest(&conf.get_burn_db_path()); @@ -2766,6 +2789,8 @@ fn test_v1_unlock_height_with_current_stackers() { let pox_addr_tuple_1 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_1}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -2803,6 +2828,8 @@ fn test_v1_unlock_height_with_current_stackers() { let pox_addr_tuple_2 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_2}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -2956,6 +2983,8 @@ fn test_v1_unlock_height_with_delay_and_current_stackers() { epochs[StacksEpochId::Epoch2_05].start_height = epoch_2_05; epochs[StacksEpochId::Epoch2_05].end_height = epoch_2_1; epochs[StacksEpochId::Epoch21].start_height = epoch_2_1; + epochs[StacksEpochId::Epoch21].end_height = STACKS_EPOCH_MAX; + epochs.truncate_after(StacksEpochId::Epoch21); conf.burnchain.epochs = Some(epochs); let mut burnchain_config = Burnchain::regtest(&conf.get_burn_db_path()); @@ -3022,6 +3051,8 @@ fn test_v1_unlock_height_with_delay_and_current_stackers() { let pox_addr_tuple_1 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_1}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -3071,6 +3102,8 @@ fn test_v1_unlock_height_with_delay_and_current_stackers() { let pox_addr_tuple_2 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_2}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); diff --git a/stacks-node/src/tests/epoch_22.rs b/stacks-node/src/tests/epoch_22.rs index 827c540a3b8..b65393c01f6 100644 --- a/stacks-node/src/tests/epoch_22.rs +++ b/stacks-node/src/tests/epoch_22.rs @@ -2,11 +2,10 @@ use std::collections::HashMap; use std::{env, thread}; use clarity::vm::types::PrincipalData; -use clarity::vm::{ClarityVersion, Value}; +use clarity::vm::{execute_with_parameters as execute, ClarityVersion, Value}; use stacks::burnchains::{Burnchain, PoxConstants}; use stacks::chainstate::stacks::address::PoxAddress; use stacks::chainstate::stacks::db::StacksChainState; -use stacks::clarity_cli::vm_execute as execute; use stacks::config::{EventKeyType, EventObserverConfig, InitialBalance}; use stacks::core::test_util::{make_contract_call, make_stacks_transfer_serialized}; use stacks::core::{self, EpochList, STACKS_EPOCH_MAX}; @@ -196,6 +195,8 @@ fn disable_pox() { let pox_addr_tuple_1 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_1}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -203,6 +204,8 @@ fn disable_pox() { let pox_addr_tuple_3 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_3}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -253,6 +256,8 @@ fn disable_pox() { let pox_addr_tuple_2 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_2}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -720,6 +725,8 @@ fn pox_2_unlock_all() { let pox_addr_tuple_1 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_1}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -727,6 +734,8 @@ fn pox_2_unlock_all() { let pox_addr_tuple_3 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_3}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -778,6 +787,8 @@ fn pox_2_unlock_all() { let pox_addr_tuple_2 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_2}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); diff --git a/stacks-node/src/tests/epoch_24.rs b/stacks-node/src/tests/epoch_24.rs index d979fd2feea..08975c3972d 100644 --- a/stacks-node/src/tests/epoch_24.rs +++ b/stacks-node/src/tests/epoch_24.rs @@ -18,14 +18,13 @@ use std::{env, thread}; use clarity::boot_util::boot_code_id; use clarity::vm::types::PrincipalData; -use clarity::vm::{ClarityVersion, Value}; +use clarity::vm::{execute_with_parameters as execute, ClarityVersion, Value}; use stacks::burnchains::{Burnchain, PoxConstants}; use stacks::chainstate::burn::db::sortdb::SortitionDB; use stacks::chainstate::stacks::address::PoxAddress; use stacks::chainstate::stacks::boot::RawRewardSetEntry; use stacks::chainstate::stacks::db::StacksChainState; use stacks::chainstate::stacks::{Error, StacksTransaction, TransactionPayload}; -use stacks::clarity_cli::vm_execute as execute; use stacks::config::InitialBalance; use stacks::core::test_util::{make_contract_call, to_addr}; use stacks::core::{self, EpochList, StacksEpochId}; @@ -222,6 +221,8 @@ fn fix_to_pox_contract() { let pox_addr_tuple_1 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_1}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -229,6 +230,8 @@ fn fix_to_pox_contract() { let pox_addr_tuple_3 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_3}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -280,6 +283,8 @@ fn fix_to_pox_contract() { let pox_addr_tuple_2 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_2}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -850,6 +855,8 @@ fn verify_auto_unlock_behavior() { let pox_addr_tuple_1 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_1}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -857,6 +864,8 @@ fn verify_auto_unlock_behavior() { let pox_addr_tuple_3 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_3}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); @@ -908,6 +917,8 @@ fn verify_auto_unlock_behavior() { let pox_addr_tuple_2 = execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash_2}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(); diff --git a/stacks-node/src/tests/nakamoto_integrations.rs b/stacks-node/src/tests/nakamoto_integrations.rs index da1de8a559b..11bcd3e4f3d 100644 --- a/stacks-node/src/tests/nakamoto_integrations.rs +++ b/stacks-node/src/tests/nakamoto_integrations.rs @@ -142,6 +142,7 @@ pub static POX_4_DEFAULT_STACKER_STX_AMT: u128 = 99_000_000_000_000; use clarity::vm::database::STXBalance; use stacks::chainstate::stacks::boot::SIP_031_NAME; use stacks::clarity_vm::clarity::SIP_031_INITIAL_MINT; +use stacks::config::DEFAULT_MAX_TENURE_BYTES; use crate::clarity::vm::clarity::ClarityConnection; @@ -316,13 +317,19 @@ pub fn check_nakamoto_empty_block_heuristics(mainnet: bool) { ) }); if has_tenure_change { - let only_coinbase_and_tenure_change = txs.iter().all(|tx| { - matches!( + for tx in txs.iter() { + if tx.get_origin().address_testnet().is_boot_code_addr() { + // boot code txs are okay + continue; + } + if !matches!( tx.payload, TransactionPayload::TenureChange(_) | TransactionPayload::Coinbase(..) - ) - }); - assert!(only_coinbase_and_tenure_change, "Nakamoto blocks with a tenure change in them should only have coinbase or tenure changes"); + ) { + error!("Nakamoto TenureChange(BlockFound) block should only have coinbase and tenure change txs, but found tx: {tx:?}"); + panic!("Nakamoto TenureChange(BlockFound) block should only have coinbase and tenure change txs"); + } + } } } } @@ -1364,6 +1371,8 @@ pub fn setup_epoch_3_reward_set( "epoch_3_start_height" => {epoch_3_start_height}, ); for (stacker_sk, signer_sk) in stacker_sks.iter().zip(signer_sks.iter()) { + let address = StacksAddress::p2pkh(false, &StacksPublicKey::from_private(stacker_sk)); + let nonce = get_account(&http_origin, &address).nonce; let pox_addr = PoxAddress::from_legacy( AddressHashMode::SerializeP2PKH, tests::to_addr(stacker_sk).bytes().clone(), @@ -1386,7 +1395,7 @@ pub fn setup_epoch_3_reward_set( let signer_pk = StacksPublicKey::from_private(signer_sk); let stacking_tx = make_contract_call( stacker_sk, - 0, + nonce, 1000, naka_conf.burnchain.chain_id, &StacksAddress::burn_address(false), @@ -1429,12 +1438,15 @@ pub fn boot_to_epoch_3_reward_set_calculation_boundary( num_stacking_cycles, ); - let epochs = naka_conf.burnchain.epochs.clone().unwrap(); - let epoch_3 = &epochs[StacksEpochId::Epoch30]; + let epoch_3_start_height = naka_conf + .burnchain + .epochs + .as_ref() + .map(|epochs| epochs[StacksEpochId::Epoch30].start_height) + .unwrap(); let reward_cycle_len = naka_conf.get_burnchain().pox_constants.reward_cycle_length as u64; let prepare_phase_len = naka_conf.get_burnchain().pox_constants.prepare_length as u64; - let epoch_3_start_height = epoch_3.start_height; assert!( epoch_3_start_height > 0, "Epoch 3.0 start height must be greater than 0" @@ -3177,6 +3189,7 @@ fn block_proposal_api_endpoint() { None, None, None, + u64::from(DEFAULT_MAX_TENURE_BYTES), ) .expect("Failed to build Nakamoto block"); @@ -3207,6 +3220,7 @@ fn block_proposal_api_endpoint() { tx_len, &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut 0, ); assert!( matches!(res, TransactionResult::Success(..)), @@ -6761,7 +6775,7 @@ fn signer_chainstate() { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let mut sortitions_view = SortitionsView::fetch_view(proposal_conf, &signer_client).unwrap(); @@ -6897,7 +6911,7 @@ fn signer_chainstate() { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let burn_block_height = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn()) .unwrap() @@ -6977,7 +6991,7 @@ fn signer_chainstate() { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let mut sortitions_view = SortitionsView::fetch_view(proposal_conf, &signer_client).unwrap(); sortitions_view @@ -14072,15 +14086,25 @@ fn test_sip_031_last_phase_coinbase_matches_activation() { .unwrap() .as_array() .unwrap() - .get(1) - .unwrap() - .get("txid") - .unwrap() - .as_str() - .unwrap(); + .iter() + .find_map(|tx_json| { + let raw_tx = tx_json.get("raw_tx").unwrap().as_str().unwrap(); + let bytes = hex_bytes(&raw_tx[2..]).ok()?; + let tx = + StacksTransaction::consensus_deserialize(&mut bytes.as_slice()) + .ok()?; + if !matches!(tx.payload, TransactionPayload::Coinbase(..)) { + return None; + } + Some(format!("0x{}", tx.txid())) + }) + .expect("Failed to find a coinbase tx"); // check the event txid is mapped to the coinbase - assert_eq!(event.get("txid").unwrap().as_str().unwrap(), coinbase_txid); + assert_eq!( + event.get("txid").unwrap().as_str().unwrap(), + coinbase_txid.as_str() + ); } } } @@ -17695,3 +17719,581 @@ fn check_as_contract_rollback() { run_loop_thread.join().unwrap(); } + +#[test] +#[ignore] +/// Tests that the tenure size limit is correctly accounted. +/// Deploys 10 (big) contracts (each 512K) +/// The block limit is 2MB, the tenure limit is 3MB +/// One block will contain 3 of the deployed contracts (the block size will be reached at it) +/// The following one will contain 2 of the deployed contract (tenure size limit will be reached) +fn smaller_tenure_size_for_miner() { + if env::var("BITCOIND_TEST") != Ok("1".into()) { + return; + } + + let (mut naka_conf, _miner_account) = naka_neon_integration_conf(None); + + let http_origin = format!("http://{}", &naka_conf.node.rpc_bind); + + let mut senders: Vec<(Secp256k1PrivateKey, StacksAddress)> = vec![]; + + // number of deploys to submit in the test + let num_deploys = 10; + + for _ in 0..num_deploys { + let sender_sk = Secp256k1PrivateKey::random(); + let sender_addr = tests::to_addr(&sender_sk); + naka_conf.add_initial_balance( + PrincipalData::from(sender_addr.clone()).to_string(), + 10000000000000, + ); + + senders.push((sender_sk, sender_addr)); + } + + let signer_sk = Secp256k1PrivateKey::random(); + let signer_addr = tests::to_addr(&signer_sk); + + naka_conf.miner.max_tenure_bytes = 3 * 1024 * 1024; // 3MB + naka_conf.miner.log_skipped_transactions = true; + + naka_conf.add_initial_balance( + PrincipalData::from(signer_addr.clone()).to_string(), + 10000000000000, + ); + let mut signers = TestSigners::new(vec![signer_sk.clone()]); + + let stacker_sk = setup_stacker(&mut naka_conf); + + test_observer::spawn(); + test_observer::register( + &mut naka_conf, + &[EventKeyType::AnyEvent, EventKeyType::MinedBlocks], + ); + + let mut btcd_controller = BitcoinCoreController::from_stx_config(&naka_conf); + btcd_controller + .start_bitcoind() + .expect("Failed starting bitcoind"); + let mut btc_regtest_controller = BitcoinRegtestController::new(naka_conf.clone(), None); + btc_regtest_controller.bootstrap_chain(201); + + let mut run_loop = boot_nakamoto::BootRunLoop::new(naka_conf.clone()).unwrap(); + let run_loop_stopper = run_loop.get_termination_switch(); + let Counters { + blocks_processed, .. + } = run_loop.counters(); + let counters = run_loop.counters(); + + let coord_channel = run_loop.coordinator_channels(); + + let run_loop_thread = thread::Builder::new() + .name("run_loop".into()) + .spawn(move || run_loop.start(None, 0)) + .unwrap(); + wait_for_runloop(&blocks_processed); + + boot_to_epoch_3( + &naka_conf, + &blocks_processed, + &[stacker_sk.clone()], + &[signer_sk], + &mut Some(&mut signers), + &mut btc_regtest_controller, + ); + + info!("Bootstrapped to Epoch-3.0 boundary, starting nakamoto miner"); + + info!("Nakamoto miner started..."); + blind_signer(&naka_conf, &signers, &counters); + + let mut long_comment = String::from(";; "); + long_comment.extend(std::iter::repeat('x').take(524_288 - long_comment.len())); + let contract = format!( + r#" + {long_comment} + (define-public (test-fn) + (ok "Hello, world!") + ) + "# + ); + + let deploy_fee = 524504; + + test_observer::clear(); + + for deploy in 0..num_deploys { + info!("Submitting deploy {deploy}"); + let contract_name = format!("test-{deploy}"); + + let contract_tx = make_contract_publish( + &senders[deploy].0, + 0, + deploy_fee, + naka_conf.burnchain.chain_id, + &contract_name, + &contract, + ); + + submit_tx(&http_origin, &contract_tx); + } + + next_block_and(&mut btc_regtest_controller, 60, || { + let nakamoto_block_events = test_observer::get_mined_nakamoto_blocks(); + if !nakamoto_block_events.is_empty() { + let nakamoto_block_event = nakamoto_block_events.last().unwrap(); + let mut skipped_transactions = 0; + for tx_event in &nakamoto_block_event.tx_events { + match tx_event { + TransactionEvent::Skipped(reason) => { + if reason.error == "Too much data in tenure" { + skipped_transactions += 1; + } + } + _ => (), + } + } + // assume 2 blocks, the first one with 3 transactions the second with 2 + // that means we will have 5 skipped transactions at the end + if skipped_transactions == 5 { + return Ok(true); + } + } + Ok(false) + }) + .unwrap(); + + // wait for signers + wait_for(30, || Ok(test_observer::get_blocks().len() >= 3)) + .expect("Timed out waiting for signers"); + + let blocks = test_observer::get_blocks(); + + assert_eq!( + blocks.len(), + 3, + "Should have successfully mined three blocks, but got {}", + blocks.len() + ); + + let mut deployed_contracts = 0; + for deploy in 0..num_deploys { + if get_account(&http_origin, &senders[deploy].1).nonce == 1 { + deployed_contracts += 1; + } + } + + assert_eq!( + deployed_contracts, 5, + "Should have successfully deployed 5 contracts, but got {}", + deployed_contracts + ); + + // ensure no tenure extend + for block in &blocks { + let txs = test_observer::parse_transactions(block); + let has_tenure_extend = txs.iter().any(|tx| match &tx.payload { + TransactionPayload::TenureChange(tenure_change) => tenure_change.cause.is_extended(), + _ => false, + }); + + assert!(!has_tenure_extend, "Unexpected tenure extend transaction"); + } + + coord_channel + .lock() + .expect("Mutex poisoned") + .stop_chains_coordinator(); + run_loop_stopper.store(false, Ordering::SeqCst); + + run_loop_thread.join().unwrap(); +} + +#[test] +#[ignore] +/// Tests that the tenure size limit is correctly accounted. +/// Deploys 10 (big) contracts (each 512K) +/// The block limit is 2MB, the tenure limit is 3MB +/// One block will contain 3 of the deployed contracts (the block size will be reached at it) +/// The following one will contain 2 of the deployed contract (tenure size limit will be reached) +/// Start a new tenure to process the remaining transactions. +fn smaller_tenure_size_for_miner_on_two_tenures() { + if env::var("BITCOIND_TEST") != Ok("1".into()) { + return; + } + + let (mut naka_conf, _miner_account) = naka_neon_integration_conf(None); + + let http_origin = format!("http://{}", &naka_conf.node.rpc_bind); + + let mut senders: Vec<(Secp256k1PrivateKey, StacksAddress)> = vec![]; + + // number of deploys to submit in the test + let num_deploys = 10; + + for _ in 0..num_deploys { + let sender_sk = Secp256k1PrivateKey::random(); + let sender_addr = tests::to_addr(&sender_sk); + naka_conf.add_initial_balance( + PrincipalData::from(sender_addr.clone()).to_string(), + 10000000000000, + ); + + senders.push((sender_sk, sender_addr)); + } + + let signer_sk = Secp256k1PrivateKey::random(); + let signer_addr = tests::to_addr(&signer_sk); + + naka_conf.miner.max_tenure_bytes = 3 * 1024 * 1024; // 3MB + naka_conf.miner.log_skipped_transactions = true; + + naka_conf.add_initial_balance( + PrincipalData::from(signer_addr.clone()).to_string(), + 10000000000000, + ); + let mut signers = TestSigners::new(vec![signer_sk.clone()]); + + let stacker_sk = setup_stacker(&mut naka_conf); + + test_observer::spawn(); + test_observer::register( + &mut naka_conf, + &[ + EventKeyType::AnyEvent, + EventKeyType::MinedBlocks, + EventKeyType::MemPoolTransactions, + ], + ); + + let mut btcd_controller = BitcoinCoreController::from_stx_config(&naka_conf); + btcd_controller + .start_bitcoind() + .expect("Failed starting bitcoind"); + let mut btc_regtest_controller = BitcoinRegtestController::new(naka_conf.clone(), None); + btc_regtest_controller.bootstrap_chain(201); + + let mut run_loop = boot_nakamoto::BootRunLoop::new(naka_conf.clone()).unwrap(); + let run_loop_stopper = run_loop.get_termination_switch(); + let Counters { + blocks_processed, .. + } = run_loop.counters(); + let counters = run_loop.counters(); + + let coord_channel = run_loop.coordinator_channels(); + + let run_loop_thread = thread::Builder::new() + .name("run_loop".into()) + .spawn(move || run_loop.start(None, 0)) + .unwrap(); + wait_for_runloop(&blocks_processed); + + boot_to_epoch_3( + &naka_conf, + &blocks_processed, + &[stacker_sk.clone()], + &[signer_sk], + &mut Some(&mut signers), + &mut btc_regtest_controller, + ); + + info!("Bootstrapped to Epoch-3.0 boundary, starting nakamoto miner"); + + info!("Nakamoto miner started..."); + blind_signer(&naka_conf, &signers, &counters); + + let mut long_comment = String::from(";; "); + long_comment.extend(std::iter::repeat('x').take(524_288 - long_comment.len())); + let contract = format!( + r#" + {long_comment} + (define-public (test-fn) + (ok "Hello, world!") + ) + "# + ); + + let deploy_fee = 524504; + + test_observer::clear(); + + for deploy in 0..num_deploys { + info!("Submitting deploy {deploy}"); + let contract_name = format!("test-{deploy}"); + + let contract_tx = make_contract_publish( + &senders[deploy].0, + 0, + deploy_fee, + naka_conf.burnchain.chain_id, + &contract_name, + &contract, + ); + + submit_tx(&http_origin, &contract_tx); + } + + next_block_and(&mut btc_regtest_controller, 60, || { + let nakamoto_block_events = test_observer::get_mined_nakamoto_blocks(); + if !nakamoto_block_events.is_empty() { + let nakamoto_block_event = nakamoto_block_events.last().unwrap(); + let mut skipped_transactions = 0; + for tx_event in &nakamoto_block_event.tx_events { + match tx_event { + TransactionEvent::Skipped(reason) => { + if reason.error == "Too much data in tenure" { + skipped_transactions += 1; + } + } + _ => (), + } + } + // assume 2 blocks, the first one with 3 transactions the second with 2 + // that means we will have 5 skipped transactions at the end + if skipped_transactions == 5 { + return Ok(true); + } + } + Ok(false) + }) + .unwrap(); + + // wait for signers + wait_for(30, || Ok(test_observer::get_blocks().len() >= 3)) + .expect("Timed out waiting for signers"); + + // start the second tenure and wait till no more transactions are skipped + next_block_and(&mut btc_regtest_controller, 60, || { + let nakamoto_block_events = test_observer::get_mined_nakamoto_blocks(); + if !nakamoto_block_events.is_empty() { + let nakamoto_block_event = nakamoto_block_events.last().unwrap(); + let mut skipped_transactions = 0; + for tx_event in &nakamoto_block_event.tx_events { + match tx_event { + TransactionEvent::Skipped(reason) => { + if reason.error == "Too much data in tenure" { + skipped_transactions += 1; + } + } + _ => (), + } + } + if skipped_transactions == 0 { + return Ok(true); + } + } + Ok(false) + }) + .unwrap(); + + // wait for signers + wait_for(30, || Ok(test_observer::get_blocks().len() >= 6)) + .expect("Timed out waiting for signers"); + + let blocks = test_observer::get_blocks(); + + assert_eq!( + blocks.len(), + 6, + "Should have successfully mined six blocks, but got {}", + blocks.len() + ); + + let mut deployed_contracts = 0; + for deploy in 0..num_deploys { + if get_account(&http_origin, &senders[deploy].1).nonce == 1 { + deployed_contracts += 1; + } + } + + assert_eq!( + deployed_contracts, 10, + "Should have successfully deployes 10 contracts, but got {}", + deployed_contracts + ); + + // ensure no tenure extend + for block in &blocks { + let txs = test_observer::parse_transactions(block); + let has_tenure_extend = txs.iter().any(|tx| match &tx.payload { + TransactionPayload::TenureChange(tenure_change) => tenure_change.cause.is_extended(), + _ => false, + }); + + assert!(!has_tenure_extend, "Unexpected tenure extend transaction"); + } + + coord_channel + .lock() + .expect("Mutex poisoned") + .stop_chains_coordinator(); + run_loop_stopper.store(false, Ordering::SeqCst); + + run_loop_thread.join().unwrap(); +} + +#[test] +#[ignore] +/// Tests that the tenure size limit is correctly reset on tenure extend. +/// Deploys 10 (big) contracts (each 512K) +/// The block limit is 2MB, the tenure limit is 3MB +/// One block will contain 3 of the deployed contracts (the block size will be reached at it) +/// The following ones will contain the others as tenure extend is constantly triggered +fn smaller_tenure_size_for_miner_with_tenure_extend() { + if env::var("BITCOIND_TEST") != Ok("1".into()) { + return; + } + + let (mut naka_conf, _miner_account) = naka_neon_integration_conf(None); + + let http_origin = format!("http://{}", &naka_conf.node.rpc_bind); + + let mut senders: Vec<(Secp256k1PrivateKey, StacksAddress)> = vec![]; + + // number of deploys to submit in the test + let num_deploys = 10; + + for _ in 0..num_deploys { + let sender_sk = Secp256k1PrivateKey::random(); + let sender_addr = tests::to_addr(&sender_sk); + naka_conf.add_initial_balance( + PrincipalData::from(sender_addr.clone()).to_string(), + 10000000000000, + ); + + senders.push((sender_sk, sender_addr)); + } + + let signer_sk = Secp256k1PrivateKey::random(); + let signer_addr = tests::to_addr(&signer_sk); + + naka_conf.miner.max_tenure_bytes = 3 * 1024 * 1024; // 3MB + naka_conf.miner.log_skipped_transactions = true; + // quickly tenure extend + naka_conf.miner.tenure_timeout = Duration::from_secs(0); + naka_conf.miner.tenure_extend_cost_threshold = 0; + + naka_conf.add_initial_balance( + PrincipalData::from(signer_addr.clone()).to_string(), + 10000000000000, + ); + let mut signers = TestSigners::new(vec![signer_sk.clone()]); + + let stacker_sk = setup_stacker(&mut naka_conf); + + test_observer::spawn(); + test_observer::register( + &mut naka_conf, + &[EventKeyType::AnyEvent, EventKeyType::MinedBlocks], + ); + + let mut btcd_controller = BitcoinCoreController::from_stx_config(&naka_conf); + btcd_controller + .start_bitcoind() + .expect("Failed starting bitcoind"); + let mut btc_regtest_controller = BitcoinRegtestController::new(naka_conf.clone(), None); + btc_regtest_controller.bootstrap_chain(201); + + let mut run_loop = boot_nakamoto::BootRunLoop::new(naka_conf.clone()).unwrap(); + let run_loop_stopper = run_loop.get_termination_switch(); + let Counters { + blocks_processed, .. + } = run_loop.counters(); + let counters = run_loop.counters(); + + let coord_channel = run_loop.coordinator_channels(); + + let run_loop_thread = thread::Builder::new() + .name("run_loop".into()) + .spawn(move || run_loop.start(None, 0)) + .unwrap(); + wait_for_runloop(&blocks_processed); + + boot_to_epoch_3( + &naka_conf, + &blocks_processed, + &[stacker_sk.clone()], + &[signer_sk], + &mut Some(&mut signers), + &mut btc_regtest_controller, + ); + + info!("Bootstrapped to Epoch-3.0 boundary, starting nakamoto miner"); + + info!("Nakamoto miner started..."); + blind_signer(&naka_conf, &signers, &counters); + + let mut long_comment = String::from(";; "); + long_comment.extend(std::iter::repeat('x').take(524_288 - long_comment.len())); + let contract = format!( + r#" + {long_comment} + (define-public (test-fn) + (ok "Hello, world!") + ) + "# + ); + + let deploy_fee = 524504; + + test_observer::clear(); + + for deploy in 0..num_deploys { + info!("Submitting deploy {deploy}"); + let contract_name = format!("test-{deploy}"); + + let contract_tx = make_contract_publish( + &senders[deploy].0, + 0, + deploy_fee, + naka_conf.burnchain.chain_id, + &contract_name, + &contract, + ); + + submit_tx(&http_origin, &contract_tx); + } + + next_block_and(&mut btc_regtest_controller, 60, || { + let mut deployed_contracts = 0; + for deploy in 0..num_deploys { + if get_account(&http_origin, &senders[deploy].1).nonce == 1 { + deployed_contracts += 1; + } + } + Ok(deployed_contracts == 10) + }) + .unwrap(); + + let blocks = test_observer::get_blocks(); + + assert!( + blocks.len() >= 5, + "Should have successfully mined >= 5 blocks, but got {}", + blocks.len() + ); + + // ensure tenure extend is present in the last 3 blocks + for (block_index, block) in blocks.iter().enumerate() { + let txs = test_observer::parse_transactions(block); + let has_tenure_extend = txs.iter().any(|tx| match &tx.payload { + TransactionPayload::TenureChange(tenure_change) => tenure_change.cause.is_extended(), + _ => false, + }); + + if block_index >= 1 { + assert!(has_tenure_extend, "Expected tenure extend transaction"); + } else { + assert!(!has_tenure_extend, "Unexpected tenure extend transaction"); + } + } + + coord_channel + .lock() + .expect("Mutex poisoned") + .stop_chains_coordinator(); + run_loop_stopper.store(false, Ordering::SeqCst); + + run_loop_thread.join().unwrap(); +} diff --git a/stacks-node/src/tests/neon_integrations.rs b/stacks-node/src/tests/neon_integrations.rs index e87059cf0c3..cf349fdc30b 100644 --- a/stacks-node/src/tests/neon_integrations.rs +++ b/stacks-node/src/tests/neon_integrations.rs @@ -9,7 +9,10 @@ use clarity::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; use clarity::vm::costs::ExecutionCost; use clarity::vm::types::serialization::SerializationError; use clarity::vm::types::PrincipalData; -use clarity::vm::{ClarityName, ClarityVersion, ContractName, Value, MAX_CALL_STACK_DEPTH}; +use clarity::vm::{ + execute_with_parameters as execute, ClarityName, ClarityVersion, ContractName, Value, + MAX_CALL_STACK_DEPTH, +}; use rusqlite::params; use serde::Deserialize; use serde_json::json; @@ -36,7 +39,6 @@ use stacks::chainstate::stacks::{ StacksBlock, StacksBlockHeader, StacksMicroblock, StacksPrivateKey, StacksPublicKey, StacksTransaction, TransactionContractCall, TransactionPayload, }; -use stacks::clarity_cli::vm_execute as execute; use stacks::codec::StacksMessageCodec; use stacks::config::{EventKeyType, EventObserverConfig, FeeEstimatorName, InitialBalance}; use stacks::core::mempool::{MemPoolWalkStrategy, MemPoolWalkTxTypes}; @@ -2368,6 +2370,8 @@ fn stx_delegate_btc_integration_test() { execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash}, version: 0x00 }}"), ClarityVersion::Clarity2, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(), @@ -5356,6 +5360,8 @@ fn pox_integration_test() { execute( &format!("{{ hashbytes: 0x{pox_pubkey_hash}, version: 0x00 }}"), ClarityVersion::Clarity1, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(), @@ -5468,6 +5474,8 @@ fn pox_integration_test() { execute( &format!("{{ hashbytes: 0x{pox_2_pubkey_hash}, version: 0x00 }}"), ClarityVersion::Clarity1, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(), @@ -5492,6 +5500,8 @@ fn pox_integration_test() { execute( &format!("{{ hashbytes: 0x{pox_2_pubkey_hash}, version: 0x00 }}"), ClarityVersion::Clarity1, + StacksEpochId::latest(), + false, ) .unwrap() .unwrap(), diff --git a/stacks-node/src/tests/signer/commands/block_wait.rs b/stacks-node/src/tests/signer/commands/block_wait.rs index cb41356ce2e..04e9b9f2b74 100644 --- a/stacks-node/src/tests/signer/commands/block_wait.rs +++ b/stacks-node/src/tests/signer/commands/block_wait.rs @@ -26,7 +26,6 @@ pub struct ChainExpectNakaBlock { #[derive(Debug)] enum HeightStrategy { - FromGlobalHeight, FromMinerHeight, FromStateHeight, } @@ -44,10 +43,6 @@ impl ChainExpectNakaBlock { } } - pub fn from_global_height(ctx: Arc, miner_index: usize) -> Self { - Self::new(ctx, miner_index, HeightStrategy::FromGlobalHeight) - } - pub fn from_miner_height(ctx: Arc, miner_index: usize) -> Self { Self::new(ctx, miner_index, HeightStrategy::FromMinerHeight) } @@ -76,33 +71,6 @@ impl Command for ChainExpectNakaBlock { // Calculate expected height based on the strategy match self.height_strategy { - HeightStrategy::FromGlobalHeight => { - // Use global height approach - let conf = self.ctx.get_node_config(self.miner_index); - let stacks_height_before = self.ctx.get_peer_stacks_tip_height(); - let expected_height = stacks_height_before + 1; - - let miner_block = - wait_for_block_pushed_by_miner_key(30, expected_height, &miner_pk).expect( - &format!( - "Failed to get block for miner {} - Strategy: {:?}", - self.miner_index, self.height_strategy - ), - ); - - let mined_block_height = miner_block.header.chain_length; - - info!( - "Miner {} mined Nakamoto block at height {}", - self.miner_index, mined_block_height - ); - - let info_after = get_chain_info(&conf); - - assert_eq!(info_after.stacks_tip, miner_block.header.block_hash()); - assert_eq!(info_after.stacks_tip_height, mined_block_height); - assert_eq!(mined_block_height, expected_height); - } HeightStrategy::FromMinerHeight => { // Use miner-specific height approach let conf = self.ctx.get_node_config(self.miner_index); @@ -175,7 +143,7 @@ impl Command for ChainExpectNakaBlock { (1usize..=2usize).prop_flat_map(move |miner_index| { prop_oneof![ Just(CommandWrapper::new( - ChainExpectNakaBlock::from_global_height(ctx.clone(), miner_index) + ChainExpectNakaBlock::from_state_height(ctx.clone(), miner_index) )), Just(CommandWrapper::new( ChainExpectNakaBlock::from_miner_height(ctx.clone(), miner_index) @@ -349,22 +317,23 @@ impl Command for ChainExpectStacksTenureChan true } - fn apply(&self, _state: &mut SignerTestState) { + fn apply(&self, state: &mut SignerTestState) { let miner_pk = self.ctx.get_miner_public_key(self.miner_index); - // TODO: this is a bug. You cannot gaurantee that the block has not already been processed - // by the node causing a potential off by one race condition. - // See https://github.com/stacks-network/stacks-core/issues/6221 - let expected_height = self.ctx.get_peer_stacks_tip_height() + 1; + // Cannot use global height as this would result in a race condition. Cannot gaurantee + // that the node has not already processed the stacks block. Must use stored state. + let expected_height = state.last_stacks_block_height.expect( + "Cannot wait for a tenure change block if we haven't set the last_stacks_block_height", + ) + 1; info!( - "Applying: Waiting for tenure change block at height {} from miner {}", - expected_height, self.miner_index + "Applying: Waiting for tenure change block at height {expected_height} from miner {}", + self.miner_index ); let block = wait_for_block_pushed_by_miner_key(30, expected_height, &miner_pk).expect(&format!( - "Failed to get tenure change block for miner {} at height {}", - self.miner_index, expected_height + "Failed to get tenure change block for miner {} at height {expected_height}", + self.miner_index )); // Verify this is a tenure change block @@ -380,15 +349,14 @@ impl Command for ChainExpectStacksTenureChan assert!( is_tenure_change_block_found, - "Block at height {} from miner {} is not a proper tenure change block. Transactions: {:?}", - expected_height, + "Block at height {expected_height} from miner {} is not a proper tenure change block. Transactions: {:?}", self.miner_index, block.txs.iter().map(|tx| &tx.payload).collect::>() ); info!( - "Successfully verified tenure change block at height {} from miner {}", - expected_height, self.miner_index + "Successfully verified tenure change block at height {expected_height} from miner {}", + self.miner_index ); } diff --git a/stacks-node/src/tests/signer/commands/boot.rs b/stacks-node/src/tests/signer/commands/boot.rs index e9b6cddcb2a..20ffbdf371c 100644 --- a/stacks-node/src/tests/signer/commands/boot.rs +++ b/stacks-node/src/tests/signer/commands/boot.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use madhouse::{Command, CommandWrapper}; use proptest::prelude::{Just, Strategy}; +use stacks::core::StacksEpochId; use super::context::{SignerTestContext, SignerTestState}; use crate::tests::neon_integrations::get_chain_info; @@ -32,17 +33,24 @@ impl Command for ChainBootToEpoch3 { fn apply(&self, state: &mut SignerTestState) { info!("Applying: Booting miners to Nakamoto"); - self.ctx.miners.lock().unwrap().boot_to_epoch_3(); - // We can use miner 1 conf to get the chain info - it's the same for both miners let conf = self.ctx.get_node_config(1); - let burn_block_height = get_chain_info(&conf).burn_block_height; - - state.epoch_3_start_block_height = Some(self.ctx.get_peer_stacks_tip_height()); - - // Epoch 3.0 is expected to start at burn block height 231 - assert_eq!(burn_block_height, 231); + let epoch_3_start_height = conf + .burnchain + .epochs + .as_ref() + .map(|epochs| epochs[StacksEpochId::Epoch30].start_height) + .unwrap(); + // If we have successfully bootstrapped already, don't bother doing it again. + if get_chain_info(&conf).burn_block_height < epoch_3_start_height { + self.ctx.miners.lock().unwrap().boot_to_epoch_3(); + assert_eq!( + get_chain_info(&conf).burn_block_height, + epoch_3_start_height + ); + state.epoch_3_start_block_height = Some(self.ctx.get_peer_stacks_tip_height()); + } state.is_booted_to_nakamoto = true; } diff --git a/stacks-node/src/tests/signer/mod.rs b/stacks-node/src/tests/signer/mod.rs index e97b8523aa8..d8db0e960d0 100644 --- a/stacks-node/src/tests/signer/mod.rs +++ b/stacks-node/src/tests/signer/mod.rs @@ -13,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . mod commands; -#[cfg(feature = "build-signer-v3-1-0-0-13")] +#[cfg(feature = "build-signer-v3-3-0-0-1")] pub mod multiversion; pub mod v0; @@ -1673,7 +1673,8 @@ impl SignerTest { let accepted = BlockResponse::accepted( block.header.signer_signature_hash(), signature, - get_epoch_time_secs().wrapping_add(u64::MAX), + get_epoch_time_secs().saturating_add(u64::MAX), + get_epoch_time_secs().saturating_add(u64::MAX), ); stackerdb .send_message_with_retry::(accepted.into()) diff --git a/stacks-node/src/tests/signer/multiversion.rs b/stacks-node/src/tests/signer/multiversion.rs index e02a7284de1..152b9747357 100644 --- a/stacks-node/src/tests/signer/multiversion.rs +++ b/stacks-node/src/tests/signer/multiversion.rs @@ -16,17 +16,21 @@ use std::sync::mpsc::TryRecvError; use std::thread; use std::time::Duration; -use libsigner::v0::messages::{SignerMessage, StateMachineUpdate}; +use libsigner::v0::messages::{ + BlockAccepted, BlockResponse, BlockResponseData, RejectReason, SignerMessage, + SignerMessageMetadata, +}; use libsigner::v0::signer_state::{MinerState, ReplayTransactionSet, SignerStateMachine}; +use libsigner_v3_3_0_0_1::v0::messages::SignerMessage as OldSignerMessage; use stacks::chainstate::stacks::StacksTransaction; -use stacks::util::hash::Hash160; -use stacks::util::secp256k1::Secp256k1PrivateKey; +use stacks::util::hash::{Hash160, Sha512Trunc256Sum}; +use stacks::util::secp256k1::{MessageSignature, Secp256k1PrivateKey}; use stacks_common::types::chainstate::{ConsensusHash, StacksBlockId}; -use stacks_common_v3_1_00_13::codec::StacksMessageCodec as OldStacksMessageCodec; +use stacks_common_v3_3_0_0_1::codec::StacksMessageCodec as OldStacksMessageCodec; use stacks_signer::runloop::{RewardCycleInfo, State, StateInfo}; use stacks_signer::v0::signer_state::LocalStateMachine; use stacks_signer::v0::SpawnedSigner; -use {libsigner_v3_1_0_0_13, signer_v3_1_0_0_13, stacks_common_v3_1_00_13, stacks_v3_1_00_13}; +use {libsigner_v3_3_0_0_1, signer_v3_3_0_0_1, stacks_common_v3_3_0_0_1, stacks_v3_3_0_0_1}; use super::SpawnedSignerTrait; use crate::stacks_common::codec::StacksMessageCodec; @@ -37,24 +41,24 @@ use crate::tests::{self}; use crate::Keychain; pub enum MultiverSpawnedSigner { - V310012(signer_v3_1_0_0_13::v0::SpawnedSigner), + V33001(signer_v3_3_0_0_1::v0::SpawnedSigner), Current(SpawnedSigner), } pub enum ReceiveResult { - V310012(Result), + V33001(Result), Current(Result), } -// Helper function to convert libsigner_v3_1_0_0_13 miner state to current miner state -pub fn miner_state_v3_1_00_13_to_current( - miner_state: &libsigner_v3_1_0_0_13::v0::signer_state::MinerState, +// Helper function to convert libsigner_v3_3_0_0_1 miner state to current miner state +pub fn miner_state_v3_3_0_0_1_to_current( + miner_state: &libsigner_v3_3_0_0_1::v0::signer_state::MinerState, ) -> MinerState { match miner_state { - libsigner_v3_1_0_0_13::v0::signer_state::MinerState::NoValidMiner => { + libsigner_v3_3_0_0_1::v0::signer_state::MinerState::NoValidMiner => { MinerState::NoValidMiner } - libsigner_v3_1_0_0_13::v0::signer_state::MinerState::ActiveMiner { + libsigner_v3_3_0_0_1::v0::signer_state::MinerState::ActiveMiner { current_miner_pkh, tenure_id, parent_tenure_id, @@ -71,29 +75,29 @@ pub fn miner_state_v3_1_00_13_to_current( } // Helper function to convert from one to the other -pub fn stacks_transaction_v3_1_00_13_to_current( - tx: &stacks_v3_1_00_13::chainstate::stacks::StacksTransaction, +pub fn stacks_transaction_v3_3_0_0_1_to_current( + tx: &stacks_v3_3_0_0_1::chainstate::stacks::StacksTransaction, ) -> StacksTransaction { let tx_bytes = tx.serialize_to_vec(); StacksTransaction::consensus_deserialize(&mut &tx_bytes[..]).unwrap() } // Helper function to convert libsigner_v3_1_0_0_13 signer state machine to current signer state machine -pub fn signer_state_update_v3_1_00_13_to_current( - update: &signer_v3_1_0_0_13::v0::signer_state::StateMachineUpdate, +pub fn signer_state_update_v3_3_0_0_1_to_current( + update: &signer_v3_3_0_0_1::v0::signer_state::StateMachineUpdate, ) -> stacks_signer::v0::signer_state::StateMachineUpdate { let serialized = serde_json::to_string(update).unwrap(); serde_json::from_str(&serialized).unwrap() } // Helper function to convert libsigner_v3_1_0_0_13 signer state machine to current signer state machine -pub fn signer_state_machine_v3_1_00_13_to_current( - machine: &libsigner_v3_1_0_0_13::v0::signer_state::SignerStateMachine, +pub fn signer_state_machine_v3_3_0_0_1_to_current( + machine: &libsigner_v3_3_0_0_1::v0::signer_state::SignerStateMachine, ) -> SignerStateMachine { SignerStateMachine { burn_block: ConsensusHash(machine.burn_block.0), burn_block_height: machine.burn_block_height, - current_miner: miner_state_v3_1_00_13_to_current(&machine.current_miner), + current_miner: miner_state_v3_3_0_0_1_to_current(&machine.current_miner), active_signer_protocol_version: machine.active_signer_protocol_version, tx_replay_set: ReplayTransactionSet::new( machine @@ -101,28 +105,28 @@ pub fn signer_state_machine_v3_1_00_13_to_current( .clone() .unwrap_or_default() .iter() - .map(stacks_transaction_v3_1_00_13_to_current) + .map(stacks_transaction_v3_3_0_0_1_to_current) .collect(), ), } } // Helper function to convert signer_v3_1_0_0_13 local state machines to current local state machines -pub fn local_state_machine_v3_1_00_13_to_current( - state_machine: &signer_v3_1_0_0_13::v0::signer_state::LocalStateMachine, +pub fn local_state_machine_v3_3_0_0_1_to_current( + state_machine: &signer_v3_3_0_0_1::v0::signer_state::LocalStateMachine, ) -> LocalStateMachine { match state_machine { - signer_v3_1_0_0_13::v0::signer_state::LocalStateMachine::Uninitialized => { + signer_v3_3_0_0_1::v0::signer_state::LocalStateMachine::Uninitialized => { LocalStateMachine::Uninitialized } - signer_v3_1_0_0_13::v0::signer_state::LocalStateMachine::Pending { prior, update } => { + signer_v3_3_0_0_1::v0::signer_state::LocalStateMachine::Pending { prior, update } => { LocalStateMachine::Pending { - prior: signer_state_machine_v3_1_00_13_to_current(prior), - update: signer_state_update_v3_1_00_13_to_current(update), + prior: signer_state_machine_v3_3_0_0_1_to_current(prior), + update: signer_state_update_v3_3_0_0_1_to_current(update), } } - signer_v3_1_0_0_13::v0::signer_state::LocalStateMachine::Initialized(machine) => { - LocalStateMachine::Initialized(signer_state_machine_v3_1_00_13_to_current(machine)) + signer_v3_3_0_0_1::v0::signer_state::LocalStateMachine::Initialized(machine) => { + LocalStateMachine::Initialized(signer_state_machine_v3_3_0_0_1_to_current(machine)) } } } @@ -135,7 +139,7 @@ impl SpawnedSignerTrait for MultiverSpawnedSigner { if c.endpoint.port() % 2 == 0 { Self::Current(SpawnedSigner::new(c)) } else { - let config = signer_v3_1_0_0_13::config::GlobalConfig { + let config = signer_v3_3_0_0_1::config::GlobalConfig { node_host: c.node_host, endpoint: c.endpoint, stacks_private_key: serde_json::from_value( @@ -146,7 +150,7 @@ impl SpawnedSignerTrait for MultiverSpawnedSigner { serde_json::to_value(&c.stacks_address).unwrap(), ) .unwrap(), - network: signer_v3_1_0_0_13::config::Network::Testnet, + network: signer_v3_3_0_0_1::config::Network::Testnet, event_timeout: c.event_timeout, auth_password: c.auth_password, db_path: c.db_path, @@ -163,16 +167,20 @@ impl SpawnedSignerTrait for MultiverSpawnedSigner { dry_run: c.dry_run, proposal_wait_for_parent_time: c.proposal_wait_for_parent_time, validate_with_replay_tx: c.validate_with_replay_tx, + capitulate_miner_view_timeout: c.capitulate_miner_view_timeout, + reset_replay_set_after_fork_blocks: c.reset_replay_set_after_fork_blocks, + stackerdb_timeout: c.stackerdb_timeout, + supported_signer_protocol_version: c.supported_signer_protocol_version, }; - Self::V310012(signer_v3_1_0_0_13::v0::SpawnedSigner::new(config)) + Self::V33001(signer_v3_3_0_0_1::v0::SpawnedSigner::new(config)) } } fn try_recv(&self) -> Self::ReceiveResult { match self { - MultiverSpawnedSigner::V310012(spawned_signer) => { + MultiverSpawnedSigner::V33001(spawned_signer) => { let result = spawned_signer.res_recv.try_recv().map_err(|_| ()); - ReceiveResult::V310012(result) + ReceiveResult::V33001(result) } MultiverSpawnedSigner::Current(spawned_signer) => { ReceiveResult::Current(spawned_signer.res_recv.try_recv()) @@ -182,7 +190,7 @@ impl SpawnedSignerTrait for MultiverSpawnedSigner { fn stop(self) -> Option { match self { - MultiverSpawnedSigner::V310012(spawned_signer) => spawned_signer.stop().map(|_| ()), + MultiverSpawnedSigner::V33001(spawned_signer) => spawned_signer.stop().map(|_| ()), MultiverSpawnedSigner::Current(spawned_signer) => spawned_signer.stop().map(|_| ()), } } @@ -191,13 +199,13 @@ impl SpawnedSignerTrait for MultiverSpawnedSigner { result: Self::ReceiveResult, ) -> Option { match result { - ReceiveResult::V310012(signer_result) => { - let Ok(signer_v3_1_0_0_13::runloop::SignerResult::StatusCheck(state_info)) = + ReceiveResult::V33001(signer_result) => { + let Ok(signer_v3_3_0_0_1::runloop::SignerResult::StatusCheck(state_info)) = signer_result else { return None; }; - let signer_v3_1_0_0_13::runloop::StateInfo { + let signer_v3_3_0_0_1::runloop::StateInfo { runloop_state, reward_cycle_info, running_signers, @@ -207,11 +215,11 @@ impl SpawnedSignerTrait for MultiverSpawnedSigner { } = state_info; Some(StateInfo { runloop_state: match runloop_state { - signer_v3_1_0_0_13::runloop::State::Uninitialized => State::Uninitialized, - signer_v3_1_0_0_13::runloop::State::NoRegisteredSigners => { + signer_v3_3_0_0_1::runloop::State::Uninitialized => State::Uninitialized, + signer_v3_3_0_0_1::runloop::State::NoRegisteredSigners => { State::NoRegisteredSigners } - signer_v3_1_0_0_13::runloop::State::RegisteredSigners => { + signer_v3_3_0_0_1::runloop::State::RegisteredSigners => { State::RegisteredSigners } }, @@ -239,7 +247,7 @@ impl SpawnedSignerTrait for MultiverSpawnedSigner { *i, machine .as_ref() - .map(local_state_machine_v3_1_00_13_to_current), + .map(local_state_machine_v3_3_0_0_1_to_current), ) }) .collect(), @@ -265,6 +273,65 @@ impl SpawnedSignerTrait for MultiverSpawnedSigner { } } +#[test] +fn old_version_parses_new_messages() { + let new_msg = BlockAccepted { + signer_signature_hash: Sha512Trunc256Sum::from_data(&[0, 1, 2, 3]), + signature: MessageSignature([0xf3; 65]), + metadata: SignerMessageMetadata { + server_version: "latest-version_signer".into(), + }, + response_data: BlockResponseData { + version: 4, + tenure_extend_timestamp: 2049, + reject_reason: RejectReason::NotRejected, + tenure_extend_read_count_timestamp: 5058, + unknown_bytes: vec![], + }, + }; + + let serialized_new_msg = + SignerMessage::BlockResponse(BlockResponse::Accepted(new_msg.clone())).serialize_to_vec(); + let old_msg = + OldSignerMessage::consensus_deserialize(&mut serialized_new_msg.as_slice()).unwrap(); + let OldSignerMessage::BlockResponse(ref old_block_response) = old_msg else { + panic!("Old version should have parsed response to a block response"); + }; + let as_block_accepted = old_block_response.as_block_accepted().unwrap(); + assert_eq!( + as_block_accepted.signer_signature_hash.0, + new_msg.signer_signature_hash.0 + ); + assert_eq!(as_block_accepted.signature.0, new_msg.signature.0); + assert_eq!( + as_block_accepted.metadata.server_version, + new_msg.metadata.server_version + ); + assert_eq!( + as_block_accepted.response_data.version, + new_msg.response_data.version + ); + assert_eq!( + as_block_accepted.response_data.tenure_extend_timestamp, + new_msg.response_data.tenure_extend_timestamp + ); + assert_eq!( + as_block_accepted.response_data.reject_reason.to_string(), + new_msg.response_data.reject_reason.to_string() + ); + assert_eq!( + as_block_accepted.response_data.unknown_bytes, + new_msg + .response_data + .tenure_extend_read_count_timestamp + .to_be_bytes() + .to_vec() + ); + + let serialized_old_msg = old_msg.serialize_to_vec(); + assert_eq!(serialized_new_msg, serialized_old_msg); +} + #[test] #[ignore] fn with_new_miner_and_old_signers() { @@ -351,14 +418,10 @@ fn with_new_miners(supported_signer_protocol_version: u64 else { return false; }; - let SignerMessage::StateMachineUpdate(StateMachineUpdate { - local_supported_signer_protocol_version, - .. - }) = message - else { + let SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)) = message else { return false; }; - local_supported_signer_protocol_version == 1 + accepted.response_data.version == 3 }) .count(); let new_updates_count = stackerdb_events @@ -370,19 +433,15 @@ fn with_new_miners(supported_signer_protocol_version: u64 else { return false; }; - let SignerMessage::StateMachineUpdate(StateMachineUpdate { - local_supported_signer_protocol_version, - .. - }) = message - else { + let SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)) = message else { return false; }; - local_supported_signer_protocol_version == supported_signer_protocol_version + accepted.response_data.version == 4 }) .count(); - info!("--------------- Sent {old_updates_count} Old Updates ---------------"); - info!("--------------- Sent {new_updates_count} New Updates ---------------"); + info!("--------------- Sent {old_updates_count} Old Responses ---------------"); + info!("--------------- Sent {new_updates_count} New Responses ---------------"); assert_ne!( old_updates_count, 0, "Expected some signers to be configured to support only the old protocol version" diff --git a/stacks-node/src/tests/signer/v0.rs b/stacks-node/src/tests/signer/v0.rs index 60a516994db..5d90a21be53 100644 --- a/stacks-node/src/tests/signer/v0.rs +++ b/stacks-node/src/tests/signer/v0.rs @@ -56,7 +56,9 @@ use stacks::chainstate::stacks::{ StacksTransaction, TenureChangeCause, TenureChangePayload, TransactionPayload, }; use stacks::codec::StacksMessageCodec; -use stacks::config::{Config as NeonConfig, EventKeyType, EventObserverConfig}; +use stacks::config::{ + Config as NeonConfig, EventKeyType, EventObserverConfig, DEFAULT_MAX_TENURE_BYTES, +}; use stacks::core::mempool::MemPoolWalkStrategy; use stacks::core::test_util::{ insert_tx_in_mempool, make_big_read_count_contract, make_contract_call, make_contract_publish, @@ -1773,7 +1775,7 @@ fn block_proposal_rejection() { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let mut block = NakamotoBlock { header: NakamotoBlockHeader::empty(), @@ -1882,7 +1884,15 @@ fn block_proposal_rejection() { /// Test Assertion: /// Each signer successfully rejects the invalid block proposal. fn sip034_tenure_extend_proposal_rejection() { - sip034_tenure_extend_proposal(false) + sip034_tenure_extend_proposal( + false, + &[ + TenureChangeCause::ExtendedReadLength, + TenureChangeCause::ExtendedRuntime, + TenureChangeCause::ExtendedWriteLength, + TenureChangeCause::ExtendedWriteCount, + ], + ) } #[tag(bitcoind)] @@ -1903,18 +1913,14 @@ fn sip034_tenure_extend_proposal_rejection() { /// Test Assertion: /// Each signer successfully accepts the block proposal. fn sip034_tenure_extend_proposal_acceptance() { - sip034_tenure_extend_proposal(true) + sip034_tenure_extend_proposal(true, &[TenureChangeCause::ExtendedReadCount]) } -fn sip034_tenure_extend_proposal(allow: bool) { +fn sip034_tenure_extend_proposal(allow: bool, extend_types: &[TenureChangeCause]) { if env::var("BITCOIND_TEST") != Ok("1".into()) { return; } - if allow { - std::env::set_var("SIGNER_TEST_SIP034", "1"); - } - tracing_subscriber::registry() .with(fmt::layer()) .with(EnvFilter::from_default_env()) @@ -1927,6 +1933,7 @@ fn sip034_tenure_extend_proposal(allow: bool) { vec![], |signer_config| { signer_config.tenure_idle_timeout = Duration::from_millis(0); + signer_config.read_count_idle_timeout = Duration::from_millis(0); }, |node_config| { // boot directly to epoch 3.3 @@ -1987,20 +1994,11 @@ fn sip034_tenure_extend_proposal(allow: bool) { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: allow, + read_count_idle_timeout: Duration::from_secs(12000), }; - // Propose a tenure-extend for each kind of SIP-034 tenure extension - for (i, extend_cause) in [ - TenureChangeCause::ExtendedRuntime, - TenureChangeCause::ExtendedReadCount, - TenureChangeCause::ExtendedReadLength, - TenureChangeCause::ExtendedWriteCount, - TenureChangeCause::ExtendedWriteLength, - ] - .iter() - .enumerate() - { + // Propose tenure-extends + for (i, extend_cause) in extend_types.iter().enumerate() { // force timestamp to advance sleep_ms(2000); @@ -2048,6 +2046,7 @@ fn sip034_tenure_extend_proposal(allow: bool) { None, None, None, + u64::from(DEFAULT_MAX_TENURE_BYTES), ) .expect("Failed to build Nakamoto block"); @@ -2067,6 +2066,7 @@ fn sip034_tenure_extend_proposal(allow: bool) { tenure_change.serialize_to_vec().len() as u64, &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut 0, ) .unwrap(); let block = builder.mine_nakamoto_block(&mut tenure_tx, burn_chain_height); @@ -3119,6 +3119,7 @@ fn forked_tenure_testing( burn_header_timestamp: tip_sn.burn_header_timestamp, anchored_block_size: tip_b_block.serialize_to_vec().len() as u64, burn_view: Some(tip_b_block.header.consensus_hash), + total_tenure_size: 0, }; let blocks = test_observer::get_mined_nakamoto_blocks(); @@ -6464,6 +6465,70 @@ fn signers_broadcast_signed_blocks() { signer_test.shutdown(); } +#[test] +#[ignore] +/// This test verifies that a miner will produce a read-count +/// extension after the signers' read count idle timeout is reached. +fn read_count_extend_after_idle_signers() { + if env::var("BITCOIND_TEST") != Ok("1".into()) { + return; + } + + tracing_subscriber::registry() + .with(fmt::layer()) + .with(EnvFilter::from_default_env()) + .init(); + + info!("------------------------- Test Setup -------------------------"); + let num_signers = 5; + let idle_timeout = Duration::from_secs(30); + let signer_test: SignerTest = SignerTest::new_with_config_modifications( + num_signers, + vec![], + |config| { + // use a different timeout to ensure that the correct timeout + // is read by the miner + config.tenure_idle_timeout = Duration::from_secs(36000); + config.read_count_idle_timeout = idle_timeout; + }, + |node_config| { + node_config.miner.tenure_extend_cost_threshold = 0; + node_config.miner.read_count_extend_cost_threshold = 0; + + // boot directly to epoch 3.3 + let epochs = node_config.burnchain.epochs.as_mut().unwrap(); + let epoch_30_height = epochs[StacksEpochId::Epoch30].start_height; + + epochs[StacksEpochId::Epoch30].end_height = epoch_30_height; + epochs[StacksEpochId::Epoch31].start_height = epoch_30_height; + epochs[StacksEpochId::Epoch31].end_height = epoch_30_height; + epochs[StacksEpochId::Epoch32].start_height = epoch_30_height; + epochs[StacksEpochId::Epoch32].end_height = epoch_30_height; + epochs[StacksEpochId::Epoch33].start_height = epoch_30_height; + }, + None, + None, + ); + + signer_test.boot_to_epoch_3(); + + info!("---- Nakamoto booted, starting test ----"); + signer_test.mine_nakamoto_block(Duration::from_secs(30), true); + signer_test.check_signer_states_normal(); + + info!("---- Waiting for a tenure extend ----"); + + // Now, wait for a block with a tenure extend + wait_for(idle_timeout.as_secs() + 10, || { + Ok(last_block_contains_tenure_change_tx( + TenureChangeCause::ExtendedReadCount, + )) + }) + .expect("Timed out waiting for a block with a tenure extend"); + + signer_test.shutdown(); +} + #[test] #[ignore] /// This test verifies that a miner will produce a TenureExtend transaction after the signers' idle timeout is reached. @@ -11023,7 +11088,7 @@ fn block_validation_response_timeout() { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let mut block = NakamotoBlock { header: NakamotoBlockHeader::empty(), @@ -11320,7 +11385,7 @@ fn block_validation_pending_table() { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let mut block = NakamotoBlock { header: NakamotoBlockHeader::empty(), @@ -12675,7 +12740,7 @@ fn incoming_signers_ignore_block_proposals() { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let mut block = NakamotoBlock { header: NakamotoBlockHeader::empty(), @@ -12854,7 +12919,7 @@ fn outgoing_signers_ignore_block_proposals() { tenure_idle_timeout_buffer: Duration::from_secs(2), reorg_attempts_activity_timeout: Duration::from_secs(30), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let mut block = NakamotoBlock { header: NakamotoBlockHeader::empty(), @@ -17840,6 +17905,7 @@ fn reorging_signers_capitulate_to_nonreorging_signers_during_tenure_fork() { burn_header_timestamp: tip_sn.burn_header_timestamp, anchored_block_size: tenure_b_block.serialize_to_vec().len() as u64, burn_view: Some(tenure_b_block.header.consensus_hash), + total_tenure_size: 0, }; // Block B was built atop block A @@ -19026,7 +19092,8 @@ fn signers_treat_signatures_as_precommits() { let accepted = BlockResponse::accepted( block_proposal.header.signer_signature_hash(), signature, - get_epoch_time_secs().wrapping_add(u64::MAX), + get_epoch_time_secs().saturating_add(u64::MAX), + get_epoch_time_secs().saturating_add(u64::MAX), ); let signers_contract_id = diff --git a/stacks-signer/CHANGELOG.md b/stacks-signer/CHANGELOG.md index fc7ce56508e..709abc6a244 100644 --- a/stacks-signer/CHANGELOG.md +++ b/stacks-signer/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to the versioning scheme outlined in the [README.md](README.md). +## [3.3.0.0.2.0] + +### Added + +- Support read-count tenure extends + - Added `read_count_idle_timeout_secs` config option to set the amount of seconds of idle time must pass before a read-count tenure extend is allowed (defaults to 20 seconds) + - Send a read-count tenure extend timestamp in the block responses + - Approve a block with a read-count tenure extend when the appropriate amount of idle time has passed ## [3.2.0.0.2.0] diff --git a/stacks-signer/src/chainstate/mod.rs b/stacks-signer/src/chainstate/mod.rs index 672e77718cd..4cd59a71244 100644 --- a/stacks-signer/src/chainstate/mod.rs +++ b/stacks-signer/src/chainstate/mod.rs @@ -79,6 +79,8 @@ pub struct ProposalEvalConfig { pub tenure_last_block_proposal_timeout: Duration, /// How much idle time must pass before allowing a tenure extend pub tenure_idle_timeout: Duration, + /// How much idle time must pass before allowing a read-count tenure extend + pub read_count_idle_timeout: Duration, /// How much buffer to add to the tenure idle timeout sent to miners to account for clock skew pub tenure_idle_timeout_buffer: Duration, /// Time following the last block of the previous tenure's global acceptance that a signer will consider an attempt by @@ -89,8 +91,6 @@ pub struct ProposalEvalConfig { /// How many blocks after a fork should we reset the replay set, /// as a failsafe mechanism pub reset_replay_set_after_fork_blocks: u64, - /// Whether or not this signer supports SIP-034 tenure extensions - pub supports_sip034_tenure_extensions: bool, } impl From<&SignerConfig> for ProposalEvalConfig { @@ -104,26 +104,11 @@ impl From<&SignerConfig> for ProposalEvalConfig { tenure_idle_timeout_buffer: value.tenure_idle_timeout_buffer, proposal_wait_for_parent_time: value.proposal_wait_for_parent_time, reset_replay_set_after_fork_blocks: value.reset_replay_set_after_fork_blocks, - // disabled for now, but can be overridden in tests - supports_sip034_tenure_extensions: Self::config_sip034_tenure_extensions(), + read_count_idle_timeout: value.read_count_idle_timeout, } } } -impl ProposalEvalConfig { - #[cfg(any(test, feature = "testing"))] - fn config_sip034_tenure_extensions() -> bool { - std::env::var("SIGNER_TEST_SIP034") - .map(|var| var.as_str() == "1") - .unwrap_or(false) - } - - #[cfg(not(any(test, feature = "testing")))] - fn config_sip034_tenure_extensions() -> bool { - false - } -} - /// Captures the Stacks sortition related data for /// a successful sortition. /// diff --git a/stacks-signer/src/chainstate/tests/v1.rs b/stacks-signer/src/chainstate/tests/v1.rs index 840e7f27747..fbd769f8f7f 100644 --- a/stacks-signer/src/chainstate/tests/v1.rs +++ b/stacks-signer/src/chainstate/tests/v1.rs @@ -103,7 +103,7 @@ fn setup_test_environment( reorg_attempts_activity_timeout: Duration::from_secs(3), proposal_wait_for_parent_time: Duration::from_secs(0), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }, }; @@ -505,7 +505,24 @@ fn check_proposal_tenure_extend_invalid_conditions() { let tx = make_tenure_change_tx(extend_payload); block.txs = vec![tx]; block.header.sign_miner(&block_sk).unwrap(); - view.config.supports_sip034_tenure_extensions = true; + view.check_proposal( + &stacks_client, + &mut signer_db, + &block, + false, + ReplayTransactionSet::none(), + ) + .expect_err("Proposal should not validate"); + + let mut extend_payload = make_tenure_change_payload(); + extend_payload.cause = TenureChangeCause::ExtendedReadCount; + extend_payload.burn_view_consensus_hash = view.cur_sortition.data.consensus_hash.clone(); + extend_payload.tenure_consensus_hash = block.header.consensus_hash.clone(); + extend_payload.prev_tenure_consensus_hash = block.header.consensus_hash.clone(); + let tx = make_tenure_change_tx(extend_payload); + block.txs = vec![tx]; + block.header.sign_miner(&block_sk).unwrap(); + view.config.read_count_idle_timeout = Duration::ZERO; view.check_proposal( &stacks_client, &mut signer_db, diff --git a/stacks-signer/src/chainstate/tests/v2.rs b/stacks-signer/src/chainstate/tests/v2.rs index bc93a9967b2..5f541e1e72e 100644 --- a/stacks-signer/src/chainstate/tests/v2.rs +++ b/stacks-signer/src/chainstate/tests/v2.rs @@ -98,7 +98,7 @@ fn setup_test_environment( reorg_attempts_activity_timeout: Duration::from_secs(3), proposal_wait_for_parent_time: Duration::from_secs(0), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let stacks_client = StacksClient::new( @@ -380,7 +380,7 @@ fn check_proposal_tenure_extend() { setup_test_environment(function_name!()); block.header.consensus_hash = cur_sortition.data.consensus_hash.clone(); let mut extend_payload = make_tenure_change_payload(); - extend_payload.burn_view_consensus_hash = cur_sortition.data.consensus_hash; + extend_payload.burn_view_consensus_hash = cur_sortition.data.consensus_hash.clone(); extend_payload.tenure_consensus_hash = block.header.consensus_hash.clone(); extend_payload.prev_tenure_consensus_hash = block.header.consensus_hash.clone(); let tx = make_tenure_change_tx(extend_payload); @@ -426,7 +426,19 @@ fn check_proposal_tenure_extend() { block.header.miner_signature = block_sk .sign(block.header.miner_signature_hash().as_bytes()) .unwrap(); - sortitions_view.config.supports_sip034_tenure_extensions = true; + sortitions_view + .check_proposal(&stacks_client, &mut signer_db, &block) + .expect_err("Proposal should not validate"); + + let mut extend_payload = make_tenure_change_payload(); + extend_payload.cause = TenureChangeCause::ExtendedReadCount; + extend_payload.burn_view_consensus_hash = cur_sortition.data.consensus_hash; + extend_payload.tenure_consensus_hash = block.header.consensus_hash.clone(); + extend_payload.prev_tenure_consensus_hash = block.header.consensus_hash.clone(); + let tx = make_tenure_change_tx(extend_payload); + block.txs = vec![tx]; + block.header.sign_miner(&block_sk).unwrap(); + sortitions_view.config.read_count_idle_timeout = Duration::ZERO; sortitions_view .check_proposal(&stacks_client, &mut signer_db, &block) .expect("Proposal should validate"); diff --git a/stacks-signer/src/chainstate/v1.rs b/stacks-signer/src/chainstate/v1.rs index 46b41e19624..b1d4347fcbe 100644 --- a/stacks-signer/src/chainstate/v1.rs +++ b/stacks-signer/src/chainstate/v1.rs @@ -15,7 +15,6 @@ use std::time::{Duration, UNIX_EPOCH}; -use blockstack_lib::chainstate::nakamoto::miner::MinerTenureInfoCause; use blockstack_lib::chainstate::nakamoto::NakamotoBlock; use blockstack_lib::chainstate::stacks::TenureChangePayload; use blockstack_lib::net::api::getsortition::SortitionInfo; @@ -332,14 +331,29 @@ impl SortitionsView { } } - if let Some(tenure_extend) = block.get_tenure_extend_tx_payload() { - // in tenure extends, we need to check: + // is there an unsupported tenure extend type? + if let Some(tenure_extend) = block.get_tenure_extend_tx_payload().filter(|extend| { + !(extend.cause.is_full_extend() || extend.cause.is_read_count_extend()) + }) { + warn!( + "Miner block proposal contains a tenure extend with an unsupported cause"; + "tenure_extend_cause" => %tenure_extend.cause, + ); + return Err(RejectReason::InvalidTenureExtend); + } + + // is there a full tenure extend in this block? + if let Some(tenure_extend) = block + .get_tenure_extend_tx_payload() + .filter(|extend| extend.cause.is_full_extend()) + { + // in full tenure extends, we need to check: // (1) if this is the most recent sortition, an extend is allowed if it changes the burnchain view // (2) if this is the most recent sortition, an extend is allowed if enough time has passed to refresh the block limit let sortition_consensus_hash = &proposed_by.state().data.consensus_hash; let changed_burn_view = &tenure_extend.burn_view_consensus_hash != sortition_consensus_hash; - let extend_timestamp = signer_db.calculate_tenure_extend_timestamp( + let extend_timestamp = signer_db.calculate_full_extend_timestamp( self.config.tenure_idle_timeout, block, false, @@ -360,14 +374,37 @@ impl SortitionsView { ); return Err(RejectReason::InvalidTenureExtend); } - // For the time being, the signer will not allow SIP-034 tenure extend until the - // requisite idle-time logic for each dimension has been added. However, this can be - // overridden in integration tests. - if MinerTenureInfoCause::from(tenure_extend.cause).is_sip034_tenure_extension() - && !self.config.supports_sip034_tenure_extensions - { + } + + // is there a read-count tenure extend in this block? + if let Some(tenure_extend) = block + .get_tenure_extend_tx_payload() + .filter(|extend| extend.cause.is_read_count_extend()) + { + // burn view changes are not allowed during read-count tenure extends + let sortition_consensus_hash = &proposed_by.state().data.consensus_hash; + let changed_burn_view = + &tenure_extend.burn_view_consensus_hash != sortition_consensus_hash; + if changed_burn_view { + warn!( + "Miner block proposal contains a read-count extend, but the conditions for allowing a tenure extend are not met. Considering proposal invalid."; + "proposed_block_consensus_hash" => %block.header.consensus_hash, + "signer_signature_hash" => %block.header.signer_signature_hash(), + "changed_burn_view" => changed_burn_view, + ); + return Err(RejectReason::InvalidTenureExtend); + } + let extend_timestamp = signer_db.calculate_read_count_extend_timestamp( + self.config.read_count_idle_timeout, + block, + false, + ); + let epoch_time = get_epoch_time_secs(); + let enough_time_passed = epoch_time >= extend_timestamp; + let is_in_replay = replay_set.is_some(); + if !enough_time_passed && !is_in_replay { warn!( - "Miner block proposal contains a SIP-034 tenure extension, which is not yet supported"; + "Miner block proposal contains a read-count extend, but the conditions for allowing a tenure extend are not met. Considering proposal invalid."; "proposed_block_consensus_hash" => %block.header.consensus_hash, "signer_signature_hash" => %block.header.signer_signature_hash(), "extend_timestamp" => extend_timestamp, @@ -375,7 +412,6 @@ impl SortitionsView { "is_in_replay" => is_in_replay, "changed_burn_view" => changed_burn_view, "enough_time_passed" => enough_time_passed, - "tenure_extend.cause" => ?tenure_extend.cause, ); return Err(RejectReason::InvalidTenureExtend); } diff --git a/stacks-signer/src/chainstate/v2.rs b/stacks-signer/src/chainstate/v2.rs index 198fb9757f8..226b7076359 100644 --- a/stacks-signer/src/chainstate/v2.rs +++ b/stacks-signer/src/chainstate/v2.rs @@ -15,7 +15,6 @@ use std::time::{Duration, UNIX_EPOCH}; -use blockstack_lib::chainstate::nakamoto::miner::MinerTenureInfoCause; use blockstack_lib::chainstate::nakamoto::NakamotoBlock; use blockstack_lib::chainstate::stacks::TenureChangePayload; use blockstack_lib::net::api::getsortition::SortitionInfo; @@ -189,13 +188,28 @@ impl GlobalStateView { } } - if let Some(tenure_extend) = block.get_tenure_extend_tx_payload() { - // in tenure extends, we need to check: + // is there an unsupported tenure extend type? + if let Some(tenure_extend) = block.get_tenure_extend_tx_payload().filter(|extend| { + !(extend.cause.is_full_extend() || extend.cause.is_read_count_extend()) + }) { + warn!( + "Miner block proposal contains a tenure extend with an unsupported cause"; + "tenure_extend_cause" => %tenure_extend.cause, + ); + return Err(RejectReason::InvalidTenureExtend); + } + + // is there a full tenure extend in this block? + if let Some(tenure_extend) = block + .get_tenure_extend_tx_payload() + .filter(|extend| extend.cause.is_full_extend()) + { + // in full tenure extends, we need to check: // (1) if this is the most recent sortition, an extend is allowed if it changes the burnchain view // (2) if this is the most recent sortition, an extend is allowed if enough time has passed to refresh the block limit // (3) if we are in replay, an extend is allowed let changed_burn_view = &tenure_extend.burn_view_consensus_hash != tenure_id; - let extend_timestamp = signer_db.calculate_tenure_extend_timestamp( + let extend_timestamp = signer_db.calculate_full_extend_timestamp( self.config.tenure_idle_timeout, block, false, @@ -216,14 +230,35 @@ impl GlobalStateView { ); return Err(RejectReason::InvalidTenureExtend); } - // For the time being, the signer will not allow SIP-034 tenure extend until the - // requisite idle-time logic for each dimension has been added. However, this can be - // overridden in integration tests. - if MinerTenureInfoCause::from(tenure_extend.cause).is_sip034_tenure_extension() - && !self.config.supports_sip034_tenure_extensions - { + } + + // is there a read-count tenure extend in this block? + if let Some(tenure_extend) = block + .get_tenure_extend_tx_payload() + .filter(|extend| extend.cause.is_read_count_extend()) + { + // burn view changes are not allowed during read-count tenure extends + let changed_burn_view = &tenure_extend.burn_view_consensus_hash != tenure_id; + if changed_burn_view { + warn!( + "Miner block proposal contains a read-count extend, but the conditions for allowing a tenure extend are not met. Considering proposal invalid."; + "proposed_block_consensus_hash" => %block.header.consensus_hash, + "signer_signature_hash" => %block.header.signer_signature_hash(), + "changed_burn_view" => changed_burn_view, + ); + return Err(RejectReason::InvalidTenureExtend); + } + let extend_timestamp = signer_db.calculate_read_count_extend_timestamp( + self.config.read_count_idle_timeout, + block, + false, + ); + let epoch_time = get_epoch_time_secs(); + let enough_time_passed = epoch_time >= extend_timestamp; + let is_in_replay = self.signer_state.tx_replay_set.is_some(); + if !enough_time_passed && !is_in_replay { warn!( - "Miner block proposal contains a SIP-034 tenure extension, which is not yet supported"; + "Miner block proposal contains a read-count extend, but the conditions for allowing a tenure extend are not met. Considering proposal invalid."; "proposed_block_consensus_hash" => %block.header.consensus_hash, "signer_signature_hash" => %block.header.signer_signature_hash(), "extend_timestamp" => extend_timestamp, @@ -231,7 +266,6 @@ impl GlobalStateView { "is_in_replay" => is_in_replay, "changed_burn_view" => changed_burn_view, "enough_time_passed" => enough_time_passed, - "tenure_extend.cause" => ?tenure_extend.cause, ); return Err(RejectReason::InvalidTenureExtend); } diff --git a/stacks-signer/src/client/mod.rs b/stacks-signer/src/client/mod.rs index 11014a4a6c0..9c893237be6 100644 --- a/stacks-signer/src/client/mod.rs +++ b/stacks-signer/src/client/mod.rs @@ -21,7 +21,7 @@ pub(crate) mod stacks_client; use std::time::Duration; -use clarity::vm::errors::Error as ClarityError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::serialization::SerializationError; use libsigner::RPCError; use libstackerdb::Error as StackerDBError; @@ -81,7 +81,7 @@ pub enum ClientError { NotConnected, /// Clarity interpreter error #[error("Clarity interpreter error: {0}")] - ClarityError(#[from] ClarityError), + ClarityError(#[from] VmExecutionError), /// Malformed reward set #[error("Malformed contract data: {0}")] MalformedContractData(String), @@ -302,6 +302,7 @@ pub(crate) mod tests { network_epoch: 0, }, ], + current_epoch: StacksEpochId::Epoch30, reward_cycle_length: thread_rng().next_u64(), rejection_votes_left_required: None, next_reward_cycle_in: thread_rng().next_u64(), @@ -440,6 +441,7 @@ pub(crate) mod tests { #[cfg(any(test, feature = "testing"))] supported_signer_protocol_version: SUPPORTED_SIGNER_PROTOCOL_VERSION, stackerdb_timeout: Duration::from_secs(DEFAULT_STACKERDB_TIMEOUT_SECS), + read_count_idle_timeout: config.read_count_idle_timeout, } } diff --git a/stacks-signer/src/client/stackerdb.rs b/stacks-signer/src/client/stackerdb.rs index 1be0b770008..a1aa730c9c6 100644 --- a/stacks-signer/src/client/stackerdb.rs +++ b/stacks-signer/src/client/stackerdb.rs @@ -341,6 +341,7 @@ mod tests { response_data: BlockResponseData::new( thread_rng().next_u64(), RejectReason::RejectedInPriorRound, + thread_rng().next_u64(), ), }; let signer_message = SignerMessage::BlockResponse(BlockResponse::Rejected(block_reject)); diff --git a/stacks-signer/src/client/stacks_client.rs b/stacks-signer/src/client/stacks_client.rs index abf09834595..682e29000b6 100644 --- a/stacks-signer/src/client/stacks_client.rs +++ b/stacks-signer/src/client/stacks_client.rs @@ -274,31 +274,7 @@ impl StacksClient { pub fn get_node_epoch(&self) -> Result { debug!("StacksClient: Getting node epoch"); let pox_info = self.get_pox_data()?; - let burn_block_height = self.get_burn_block_height()?; - - let epoch_25 = pox_info - .epochs - .iter() - .find(|epoch| epoch.epoch_id == StacksEpochId::Epoch25) - .ok_or(ClientError::UnsupportedStacksFeature( - "/v2/pox must report epochs".into(), - ))?; - - let epoch_30 = pox_info - .epochs - .iter() - .find(|epoch| epoch.epoch_id == StacksEpochId::Epoch30) - .ok_or(ClientError::UnsupportedStacksFeature( - "/v2/pox mut report epochs".into(), - ))?; - - if burn_block_height < epoch_25.start_height { - Ok(StacksEpochId::Epoch24) - } else if burn_block_height < epoch_30.start_height { - Ok(StacksEpochId::Epoch25) - } else { - Ok(StacksEpochId::Epoch30) - } + Ok(pox_info.current_epoch) } /// Submit the block proposal to the stacks node. The block will be validated and returned via the HTTP endpoint for Block events. @@ -553,12 +529,6 @@ impl StacksClient { Ok(pox_info_data) } - /// Helper function to retrieve the burn tip height from the stacks node - fn get_burn_block_height(&self) -> Result { - debug!("StacksClient: Getting burn block height"); - self.get_peer_info().map(|info| info.burn_block_height) - } - /// Get the current reward cycle info from the stacks node pub fn get_current_reward_cycle_info(&self) -> Result { debug!("StacksClient: Getting current reward cycle info"); @@ -914,17 +884,21 @@ mod tests { #[test] fn core_info_call_for_burn_block_height_should_succeed() { let mock = MockServerClient::new(); - let h = spawn(move || mock.client.get_burn_block_height()); + let h = spawn(move || mock.client.get_peer_info()); let (response, peer_info) = build_get_peer_info_response(None, None); write_response(mock.server, response.as_bytes()); - let burn_block_height = h.join().unwrap().expect("Failed to deserialize response"); + let burn_block_height = h + .join() + .unwrap() + .expect("Failed to deserialize response") + .burn_block_height; assert_eq!(burn_block_height, peer_info.burn_block_height); } #[test] fn core_info_call_for_burn_block_height_should_fail() { let mock = MockServerClient::new(); - let h = spawn(move || mock.client.get_burn_block_height()); + let h = spawn(move || mock.client.get_peer_info()); write_response( mock.server, b"HTTP/1.1 200 OK\n\n4e99f99bc4a05437abb8c7d0c306618f45b203196498e2ebe287f10497124958", @@ -998,85 +972,17 @@ mod tests { #[test] fn get_node_epoch_should_succeed() { let mock = MockServerClient::new(); - // The burn block height is one BEHIND the activation height of 2.5, therefore is 2.4 - let burn_block_height: u64 = 100; - let pox_response = build_get_pox_data_response( - None, - None, - Some(burn_block_height.saturating_add(1)), - None, - ) - .0; - let peer_response = build_get_peer_info_response(Some(burn_block_height), None).0; - let h = spawn(move || mock.client.get_node_epoch()); - write_response(mock.server, pox_response.as_bytes()); - let mock = MockServerClient::from_config(mock.config); - write_response(mock.server, peer_response.as_bytes()); - let epoch = h.join().unwrap().expect("Failed to deserialize response"); - assert_eq!(epoch, StacksEpochId::Epoch24); - // The burn block height is the same as the activation height of 2.5, therefore is 2.5 - let pox_response = build_get_pox_data_response(None, None, Some(burn_block_height), None).0; - let peer_response = build_get_peer_info_response(Some(burn_block_height), None).0; - let mock = MockServerClient::from_config(mock.config); - let h = spawn(move || mock.client.get_node_epoch()); - write_response(mock.server, pox_response.as_bytes()); - let mock = MockServerClient::from_config(mock.config); - write_response(mock.server, peer_response.as_bytes()); - let epoch = h.join().unwrap().expect("Failed to deserialize response"); - assert_eq!(epoch, StacksEpochId::Epoch25); - - // The burn block height is the AFTER as the activation height of 2.5 but BEFORE the activation height of 3.0, therefore is 2.5 - let pox_response = build_get_pox_data_response( - None, - None, - Some(burn_block_height.saturating_sub(1)), - Some(burn_block_height.saturating_add(1)), - ) - .0; - let peer_response = build_get_peer_info_response(Some(burn_block_height), None).0; - let mock = MockServerClient::from_config(mock.config); - let h = spawn(move || mock.client.get_node_epoch()); - write_response(mock.server, pox_response.as_bytes()); - let mock = MockServerClient::from_config(mock.config); - write_response(mock.server, peer_response.as_bytes()); - let epoch = h.join().unwrap().expect("Failed to deserialize response"); - assert_eq!(epoch, StacksEpochId::Epoch25); - - // The burn block height is the AFTER as the activation height of 2.5 and the SAME as the activation height of 3.0, therefore is 3.0 - let pox_response = build_get_pox_data_response( - None, - None, - Some(burn_block_height.saturating_sub(1)), - Some(burn_block_height), - ) - .0; - let peer_response = build_get_peer_info_response(Some(burn_block_height), None).0; - let mock = MockServerClient::from_config(mock.config); - let h = spawn(move || mock.client.get_node_epoch()); - write_response(mock.server, pox_response.as_bytes()); - let mock = MockServerClient::from_config(mock.config); - write_response(mock.server, peer_response.as_bytes()); - let epoch = h.join().unwrap().expect("Failed to deserialize response"); - assert_eq!(epoch, StacksEpochId::Epoch30); - - // The burn block height is the AFTER as the activation height of 2.5 and AFTER the activation height of 3.0, therefore is 3.0 - let pox_response = build_get_pox_data_response( - None, - None, - Some(burn_block_height.saturating_sub(1)), - Some(burn_block_height), - ) - .0; - let peer_response = - build_get_peer_info_response(Some(burn_block_height.saturating_add(1)), None).0; - let mock = MockServerClient::from_config(mock.config); + let expected_epoch = StacksEpochId::Epoch30; + + let (pox_response, _) = build_get_pox_data_response(None, None, None, None); + let h = spawn(move || mock.client.get_node_epoch()); + write_response(mock.server, pox_response.as_bytes()); - let mock = MockServerClient::from_config(mock.config); - write_response(mock.server, peer_response.as_bytes()); + let epoch = h.join().unwrap().expect("Failed to deserialize response"); - assert_eq!(epoch, StacksEpochId::Epoch30); + assert_eq!(epoch, expected_epoch); } #[test] diff --git a/stacks-signer/src/config.rs b/stacks-signer/src/config.rs index fe765e22916..5085f94a851 100644 --- a/stacks-signer/src/config.rs +++ b/stacks-signer/src/config.rs @@ -43,6 +43,7 @@ const DEFAULT_FIRST_PROPOSAL_BURN_BLOCK_TIMING_SECS: u64 = 60; const DEFAULT_TENURE_LAST_BLOCK_PROPOSAL_TIMEOUT_SECS: u64 = 30; const DEFAULT_DRY_RUN: bool = false; const TENURE_IDLE_TIMEOUT_SECS: u64 = 120; +const READ_COUNT_IDLE_TIMEOUT_SECS: u64 = 20; const DEFAULT_REORG_ATTEMPTS_ACTIVITY_TIMEOUT_MS: u64 = 200_000; /// Default number of seconds to add to the tenure extend time, after computing the idle timeout, /// to allow for clock skew between the signer and the miner @@ -179,6 +180,8 @@ pub struct SignerConfig { pub block_proposal_validation_timeout: Duration, /// How much idle time must pass before allowing a tenure extend pub tenure_idle_timeout: Duration, + /// How much idle time must pass before allowing a read-count tenure extend + pub read_count_idle_timeout: Duration, /// Amount of buffer time to add to the tenure extend time sent to miners to allow for /// clock skew pub tenure_idle_timeout_buffer: Duration, @@ -242,6 +245,8 @@ pub struct GlobalConfig { pub block_proposal_validation_timeout: Duration, /// How much idle time must pass before allowing a tenure extend pub tenure_idle_timeout: Duration, + /// How much idle time must pass before allowing a read-count tenure extend + pub read_count_idle_timeout: Duration, /// Amount of buffer time to add to the tenure extend time sent to miners to allow for /// clock skew pub tenure_idle_timeout_buffer: Duration, @@ -304,6 +309,8 @@ struct RawConfigFile { pub block_proposal_validation_timeout_ms: Option, /// How much idle time (in seconds) must pass before a tenure extend is allowed pub tenure_idle_timeout_secs: Option, + /// How much idle time (in seconds) must pass before a read-count tenure extend is allowed + pub read_count_idle_timeout_secs: Option, /// Number of seconds of buffer to add to the tenure extend time sent to miners to allow for /// clock skew pub tenure_idle_timeout_buffer_secs: Option, @@ -425,6 +432,12 @@ impl TryFrom for GlobalConfig { .unwrap_or(TENURE_IDLE_TIMEOUT_SECS), ); + let read_count_idle_timeout = Duration::from_secs( + raw_data + .read_count_idle_timeout_secs + .unwrap_or(READ_COUNT_IDLE_TIMEOUT_SECS), + ); + let block_proposal_max_age_secs = raw_data .block_proposal_max_age_secs .unwrap_or(DEFAULT_BLOCK_PROPOSAL_MAX_AGE_SECS); @@ -493,6 +506,7 @@ impl TryFrom for GlobalConfig { reorg_attempts_activity_timeout, dry_run, tenure_idle_timeout_buffer, + read_count_idle_timeout, proposal_wait_for_parent_time, validate_with_replay_tx, reset_replay_set_after_fork_blocks, diff --git a/stacks-signer/src/runloop.rs b/stacks-signer/src/runloop.rs index f4c0defc592..fd2c81fba1a 100644 --- a/stacks-signer/src/runloop.rs +++ b/stacks-signer/src/runloop.rs @@ -325,6 +325,7 @@ impl, T: StacksMessageCodec + Clone + Send + Debug> RunLo block_proposal_validation_timeout: self.config.block_proposal_validation_timeout, tenure_idle_timeout: self.config.tenure_idle_timeout, tenure_idle_timeout_buffer: self.config.tenure_idle_timeout_buffer, + read_count_idle_timeout: self.config.read_count_idle_timeout, block_proposal_max_age_secs: self.config.block_proposal_max_age_secs, reorg_attempts_activity_timeout: self.config.reorg_attempts_activity_timeout, proposal_wait_for_parent_time: self.config.proposal_wait_for_parent_time, diff --git a/stacks-signer/src/signerdb.rs b/stacks-signer/src/signerdb.rs index b0e0cc03bd1..98b6b557d39 100644 --- a/stacks-signer/src/signerdb.rs +++ b/stacks-signer/src/signerdb.rs @@ -20,7 +20,7 @@ use std::path::Path; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use blockstack_lib::chainstate::nakamoto::NakamotoBlock; -use blockstack_lib::chainstate::stacks::TransactionPayload; +use blockstack_lib::chainstate::stacks::{TenureChangeCause, TransactionPayload}; #[cfg(any(test, feature = "testing"))] use blockstack_lib::util_lib::db::FromColumn; use blockstack_lib::util_lib::db::{ @@ -220,8 +220,8 @@ impl From for BlockInfo { } } impl BlockInfo { - /// Whether the block is a tenure change block or not - pub fn is_tenure_change(&self) -> bool { + /// Whether the block is a tenure extend/change block or not. Used only for schema migrations + fn is_tenure_change(&self) -> bool { self.block .txs .first() @@ -229,6 +229,16 @@ impl BlockInfo { .unwrap_or(false) } + /// If the block has a tenure change tx, return the cause + fn tenure_change_cause(&self) -> Option { + let tx = self.block.txs.first()?; + let TransactionPayload::TenureChange(ref tenure_change) = tx.payload else { + // if its not a tenure change payload at all, return None + return None; + }; + Some(tenure_change.cause) + } + /// Mark this block as locally accepted, valid, signed over, and records either the self or group signed timestamp in the block info if it wasn't /// already set. pub fn mark_locally_accepted(&mut self, group_signed: bool) -> Result<(), String> { @@ -687,6 +697,11 @@ CREATE TABLE IF NOT EXISTS block_pre_commits ( PRIMARY KEY (signer_signature_hash, signer_addr) ) STRICT;"#; +static ADD_TENURE_CAUSE: &str = r#" +ALTER TABLE blocks + ADD COLUMN tenure_change_cause INTEGER; +"#; + static SCHEMA_1: &[&str] = &[ DROP_SCHEMA_0, CREATE_DB_CONFIG, @@ -805,6 +820,11 @@ static SCHEMA_17: &[&str] = &[ "INSERT INTO db_config (version) VALUES (17);", ]; +static SCHEMA_18: &[&str] = &[ + ADD_TENURE_CAUSE, + "INSERT INTO db_config (version) VALUES (18);", +]; + struct Migration { version: u32, statements: &'static [&'static str], @@ -879,11 +899,15 @@ static MIGRATIONS: &[Migration] = &[ version: 17, statements: SCHEMA_17, }, + Migration { + version: 18, + statements: SCHEMA_18, + }, ]; impl SignerDb { /// The current schema version used in this build of the signer binary. - pub const SCHEMA_VERSION: u32 = 17; + pub const SCHEMA_VERSION: u32 = 18; /// Create a new `SignerState` instance. /// This will create a new SQLite database at the given path @@ -1318,22 +1342,31 @@ impl SignerDb { "broadcasted" => ?broadcasted, "vote" => vote ); - self.db.execute("INSERT OR REPLACE INTO blocks (reward_cycle, burn_block_height, signer_signature_hash, block_info, signed_over, broadcasted, stacks_height, consensus_hash, valid, state, signed_group, signed_self, proposed_time, validation_time_ms, tenure_change) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)", params![ - u64_to_sql(block_info.reward_cycle)?, - u64_to_sql(block_info.burn_block_height)?, - hash.to_string(), - block_json, - &block_info.signed_over, - &broadcasted, - u64_to_sql(block_info.block.header.chain_length)?, - block_info.block.header.consensus_hash.to_hex(), - &block_info.valid, &block_info.state.to_string(), - &block_info.signed_group, - &block_info.signed_self, - &block_info.proposed_time, - &block_info.validation_time_ms, - &block_info.is_tenure_change() - ])?; + self.db.execute( + "INSERT OR REPLACE INTO blocks + (reward_cycle, burn_block_height, signer_signature_hash, block_info, signed_over, + broadcasted, stacks_height, consensus_hash, valid, state, signed_group, signed_self, + proposed_time, validation_time_ms, tenure_change, tenure_change_cause) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16)", + params![ + u64_to_sql(block_info.reward_cycle)?, + u64_to_sql(block_info.burn_block_height)?, + hash.to_string(), + block_json, + &block_info.signed_over, + &broadcasted, + u64_to_sql(block_info.block.header.chain_length)?, + block_info.block.header.consensus_hash.to_hex(), + &block_info.valid, + &block_info.state.to_string(), + &block_info.signed_group, + &block_info.signed_self, + &block_info.proposed_time, + &block_info.validation_time_ms, + &block_info.is_tenure_change(), + &block_info.tenure_change_cause().map(|x| x.as_u8()), + ], + )?; Ok(()) } @@ -1579,29 +1612,43 @@ impl SignerDb { Ok(()) } - /// Return the start time (epoch time in seconds) and the processing time in milliseconds of the tenure (idenfitied by consensus_hash). - fn get_tenure_times(&self, tenure: &ConsensusHash) -> Result<(u64, u64), DBError> { - let query = "SELECT tenure_change, proposed_time, validation_time_ms FROM blocks WHERE consensus_hash = ?1 AND state = ?2 ORDER BY stacks_height DESC"; + /// Returns: + /// * the time (epoch time in seconds) of the last tenure change during the tenure identified by `tenure` + /// where the change cause matches `cause_match` + /// * the processing time in milliseconds of the blocks since that time + fn get_tenure_times( + &self, + tenure: &ConsensusHash, + cause_match: F, + ) -> Result<(u64, u64), DBError> + where + F: Fn(TenureChangeCause) -> bool, + { + let query = "SELECT tenure_change_cause, proposed_time, validation_time_ms FROM blocks WHERE consensus_hash = ?1 AND state = ?2 ORDER BY stacks_height DESC"; let args = params![tenure, BlockState::GloballyAccepted.to_string()]; let mut stmt = self.db.prepare(query)?; let rows = stmt.query_map(args, |row| { - let tenure_change_block: bool = row.get(0)?; + let tenure_change_cause: Option = row.get(0)?; + let tenure_change_cause = tenure_change_cause + .and_then(|cause_byte| TenureChangeCause::try_from(cause_byte).ok()); let proposed_time: u64 = row.get(1)?; let validation_time_ms: Option = row.get(2)?; - Ok((tenure_change_block, proposed_time, validation_time_ms)) + Ok((tenure_change_cause, proposed_time, validation_time_ms)) })?; let mut tenure_processing_time_ms = 0_u64; let mut tenure_start_time = None; let mut nmb_rows = 0; for (i, row) in rows.enumerate() { nmb_rows += 1; - let (tenure_change_block, proposed_time, validation_time_ms) = row?; + let (tenure_change_cause, proposed_time, validation_time_ms) = row?; tenure_processing_time_ms = tenure_processing_time_ms.saturating_add(validation_time_ms.unwrap_or(0)); tenure_start_time = Some(proposed_time); - if tenure_change_block { - debug!("Found tenure change block {i} blocks ago in tenure {tenure}"); - break; + if let Some(tenure_change_cause) = tenure_change_cause { + if cause_match(tenure_change_cause) { + debug!("Found matching tenure change block {i} blocks ago in tenure {tenure}"); + break; + } } } debug!("Calculated tenure extend timestamp from {nmb_rows} blocks in tenure {tenure}"); @@ -1611,22 +1658,85 @@ impl SignerDb { )) } - /// Calculate the tenure extend timestamp. If determine the timestamp for a block rejection, check_tenure_extend should be set to false to avoid recalculating + /// Calculate the timestamp for the next read count tenure extend. + /// + /// If determining the timestamp for a block rejection, check_tenure_extend should be set to false to avoid recalculating + /// the tenure extend timestamp for a tenure extend block. + #[allow(unused)] + pub fn calculate_read_count_extend_timestamp( + &self, + tenure_idle_timeout: Duration, + block: &NakamotoBlock, + check_tenure_extend: bool, + ) -> u64 { + self.calculate_tenure_extend_timestamp( + tenure_idle_timeout, + block, + check_tenure_extend, + |change_cause| { + matches!( + change_cause, + // Note: we want to "reset" our timestamp whenever the read-count dimension is extended. This means + // that "full" extends should also reset our timestamp + TenureChangeCause::BlockFound + | TenureChangeCause::Extended + | TenureChangeCause::ExtendedReadCount + ) + }, + ) + } + + /// Calculate the (full) tenure extend timestamp. + /// + /// If determining the timestamp for a block rejection, check_tenure_extend should be set to false to avoid recalculating /// the tenure extend timestamp for a tenure extend block. - pub fn calculate_tenure_extend_timestamp( + pub fn calculate_full_extend_timestamp( &self, tenure_idle_timeout: Duration, block: &NakamotoBlock, check_tenure_extend: bool, ) -> u64 { - if check_tenure_extend && block.get_tenure_tx_payload().is_some() { - let tenure_extend_timestamp = - get_epoch_time_secs().wrapping_add(tenure_idle_timeout.as_secs()); - debug!("Calculated tenure extend timestamp for a tenure extend block. Rolling over timestamp: {tenure_extend_timestamp}"); - return tenure_extend_timestamp; + self.calculate_tenure_extend_timestamp( + tenure_idle_timeout, + block, + check_tenure_extend, + |change_cause| { + matches!( + change_cause, + TenureChangeCause::BlockFound | TenureChangeCause::Extended + ) + }, + ) + } + + fn calculate_tenure_extend_timestamp( + &self, + tenure_idle_timeout: Duration, + block: &NakamotoBlock, + check_tenure_extend: bool, + tenure_change_match: F, + ) -> u64 + where + F: Fn(TenureChangeCause) -> bool, + { + if check_tenure_extend { + if let Some(tenure_change) = block.get_tenure_change_tx_payload() { + if tenure_change_match(tenure_change.cause) { + let tenure_extend_timestamp = + get_epoch_time_secs().wrapping_add(tenure_idle_timeout.as_secs()); + debug!("Calculated tenure extend timestamp for a tenure extend block. Rolling over timestamp: {tenure_extend_timestamp}"); + return tenure_extend_timestamp; + } + } } let tenure_idle_timeout_secs = tenure_idle_timeout.as_secs(); - let (tenure_start_time, tenure_process_time_ms) = self.get_tenure_times(&block.header.consensus_hash).inspect_err(|e| error!("Error occurred calculating tenure extend timestamp: {e:?}. Defaulting to {tenure_idle_timeout_secs} from now.")).unwrap_or((get_epoch_time_secs(), 0)); + let (tenure_start_time, tenure_process_time_ms) = self.get_tenure_times( + &block.header.consensus_hash, + tenure_change_match, + ).unwrap_or_else(|e| { + error!("Error occurred calculating tenure extend timestamp: {e:?}. Defaulting to {tenure_idle_timeout_secs} from now."); + (get_epoch_time_secs(), 0) + }); // Plus (ms + 999)/1000 to round up to the nearest second let tenure_extend_timestamp = tenure_start_time .saturating_add(tenure_idle_timeout_secs) @@ -2835,15 +2945,24 @@ pub mod tests { db.insert_block(&block_infos[0]).unwrap(); db.insert_block(&block_infos[1]).unwrap(); + let change_match = |change_cause| { + matches!( + change_cause, + TenureChangeCause::BlockFound | TenureChangeCause::Extended + ) + }; + // Verify tenure consensus_hash_1 - let (start_time, processing_time) = db.get_tenure_times(consensus_hash_1).unwrap(); + let (start_time, processing_time) = + db.get_tenure_times(consensus_hash_1, change_match).unwrap(); assert_eq!(start_time, block_infos[0].proposed_time); assert_eq!(processing_time, 3000); db.insert_block(&block_infos[2]).unwrap(); db.insert_block(&block_infos[3]).unwrap(); - let (start_time, processing_time) = db.get_tenure_times(consensus_hash_1).unwrap(); + let (start_time, processing_time) = + db.get_tenure_times(consensus_hash_1, change_match).unwrap(); assert_eq!(start_time, block_infos[2].proposed_time); assert_eq!(processing_time, 5000); @@ -2851,12 +2970,15 @@ pub mod tests { db.insert_block(&block_infos[5]).unwrap(); // Verify tenure consensus_hash_2 - let (start_time, processing_time) = db.get_tenure_times(consensus_hash_2).unwrap(); + let (start_time, processing_time) = + db.get_tenure_times(consensus_hash_2, change_match).unwrap(); assert_eq!(start_time, block_infos[4].proposed_time); assert_eq!(processing_time, 20000); // Verify tenure consensus_hash_3 (unknown hash) - let (start_time, validation_time) = db.get_tenure_times(&consensus_hash_3).unwrap(); + let (start_time, validation_time) = db + .get_tenure_times(&consensus_hash_3, change_match) + .unwrap(); assert!(start_time < block_infos[0].proposed_time, "Should have been generated from get_epoch_time_secs() making it much older than our artificially late proposal times"); assert_eq!(validation_time, 0); } @@ -2876,7 +2998,7 @@ pub mod tests { let tenure_idle_timeout = Duration::from_secs(10); // Verify tenure consensus_hash_1 let timestamp_hash_1_before = - db.calculate_tenure_extend_timestamp(tenure_idle_timeout, &block_infos[0].block, true); + db.calculate_full_extend_timestamp(tenure_idle_timeout, &block_infos[0].block, true); assert_eq!( timestamp_hash_1_before, block_infos[0] @@ -2889,7 +3011,7 @@ pub mod tests { db.insert_block(&block_infos[3]).unwrap(); let timestamp_hash_1_after = - db.calculate_tenure_extend_timestamp(tenure_idle_timeout, &block_infos[0].block, true); + db.calculate_full_extend_timestamp(tenure_idle_timeout, &block_infos[0].block, true); assert_eq!( timestamp_hash_1_after, @@ -2903,7 +3025,7 @@ pub mod tests { db.insert_block(&block_infos[5]).unwrap(); // Verify tenure consensus_hash_2 - let timestamp_hash_2 = db.calculate_tenure_extend_timestamp( + let timestamp_hash_2 = db.calculate_full_extend_timestamp( tenure_idle_timeout, &block_infos.last().unwrap().block, true, @@ -2918,13 +3040,13 @@ pub mod tests { let now = get_epoch_time_secs().saturating_add(tenure_idle_timeout.as_secs()); let timestamp_hash_2_no_tenure_extend = - db.calculate_tenure_extend_timestamp(tenure_idle_timeout, &block_infos[0].block, false); + db.calculate_full_extend_timestamp(tenure_idle_timeout, &block_infos[0].block, false); assert_ne!(timestamp_hash_2, timestamp_hash_2_no_tenure_extend); assert!(now < timestamp_hash_2_no_tenure_extend); // Verify tenure consensus_hash_3 (unknown hash) let timestamp_hash_3 = - db.calculate_tenure_extend_timestamp(tenure_idle_timeout, &unknown_block, true); + db.calculate_full_extend_timestamp(tenure_idle_timeout, &unknown_block, true); assert!( timestamp_hash_3.saturating_add(tenure_idle_timeout.as_secs()) < block_infos[0].proposed_time diff --git a/stacks-signer/src/tests/signer_state.rs b/stacks-signer/src/tests/signer_state.rs index ee9077c9638..77c1a8aaa7f 100644 --- a/stacks-signer/src/tests/signer_state.rs +++ b/stacks-signer/src/tests/signer_state.rs @@ -285,7 +285,7 @@ fn check_miner_inactivity_timeout() { reorg_attempts_activity_timeout: Duration::from_secs(3), proposal_wait_for_parent_time: Duration::from_secs(0), reset_replay_set_after_fork_blocks: DEFAULT_RESET_REPLAY_SET_AFTER_FORK_BLOCKS, - supports_sip034_tenure_extensions: false, + read_count_idle_timeout: Duration::from_secs(12000), }; let block_sk = StacksPrivateKey::from_seed(&[0, 1]); diff --git a/stacks-signer/src/v0/signer.rs b/stacks-signer/src/v0/signer.rs index 70012e8910c..fb40e39b2b0 100644 --- a/stacks-signer/src/v0/signer.rs +++ b/stacks-signer/src/v0/signer.rs @@ -473,13 +473,20 @@ impl Signer { BlockAccepted::new( block.header.signer_signature_hash(), signature, - self.signer_db.calculate_tenure_extend_timestamp( + self.signer_db.calculate_full_extend_timestamp( self.proposal_config .tenure_idle_timeout .saturating_add(self.proposal_config.tenure_idle_timeout_buffer), block, true, ), + self.signer_db.calculate_read_count_extend_timestamp( + self.proposal_config + .read_count_idle_timeout + .saturating_add(self.proposal_config.tenure_idle_timeout_buffer), + block, + true, + ), ) } @@ -692,13 +699,20 @@ impl Signer { reject_reason, &self.private_key, self.mainnet, - self.signer_db.calculate_tenure_extend_timestamp( + self.signer_db.calculate_full_extend_timestamp( self.proposal_config .tenure_idle_timeout .saturating_add(self.proposal_config.tenure_idle_timeout_buffer), block, false, ), + self.signer_db.calculate_read_count_extend_timestamp( + self.proposal_config + .read_count_idle_timeout + .saturating_add(self.proposal_config.tenure_idle_timeout_buffer), + block, + false, + ), ) } @@ -1449,13 +1463,20 @@ impl Signer { block_validate_reject.clone(), &self.private_key, self.mainnet, - self.signer_db.calculate_tenure_extend_timestamp( + self.signer_db.calculate_full_extend_timestamp( self.proposal_config .tenure_idle_timeout .saturating_add(self.proposal_config.tenure_idle_timeout_buffer), &block_info.block, false, ), + self.signer_db.calculate_read_count_extend_timestamp( + self.proposal_config + .read_count_idle_timeout + .saturating_add(self.proposal_config.tenure_idle_timeout_buffer), + &block_info.block, + false, + ), ); block_info.reject_reason = Some(block_rejection.response_data.reject_reason.clone()); diff --git a/stackslib/Cargo.toml b/stackslib/Cargo.toml index 10e94f4b470..0b8d920ab33 100644 --- a/stackslib/Cargo.toml +++ b/stackslib/Cargo.toml @@ -18,10 +18,6 @@ rust-version = "1.80" name = "blockstack_lib" path = "src/lib.rs" -[[bin]] -name = "clarity-cli" -path = "src/clarity_cli_main.rs" - [dependencies] rand = { workspace = true } rand_core = { workspace = true } diff --git a/stackslib/src/chainstate/burn/db/sortdb.rs b/stackslib/src/chainstate/burn/db/sortdb.rs index 651a2984f1f..9bb99f7afc3 100644 --- a/stackslib/src/chainstate/burn/db/sortdb.rs +++ b/stackslib/src/chainstate/burn/db/sortdb.rs @@ -1250,7 +1250,9 @@ impl<'a> SortitionHandleTx<'a> { key_vtxindex: u32, tip: &SortitionId, ) -> Result, db_error> { - assert!(key_block_height < BLOCK_HEIGHT_MAX); + if key_block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let ancestor_snapshot = match SortitionDB::get_ancestor_snapshot_tx(self, key_block_height, tip)? { Some(sn) => sn, @@ -1318,7 +1320,9 @@ impl<'a> SortitionHandleTx<'a> { &mut self, block_height: u64, ) -> Result, db_error> { - assert!(block_height < BLOCK_HEIGHT_MAX); + if block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let chain_tip = self.context.chain_tip.clone(); match SortitionDB::get_ancestor_snapshot_tx(self, block_height, &chain_tip)? { @@ -1345,7 +1349,9 @@ impl<'a> SortitionHandleTx<'a> { &mut self, burn_block_height: u64, ) -> Result { - assert!(burn_block_height < BLOCK_HEIGHT_MAX); + if burn_block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } test_debug!( "Get snapshot at from sortition tip {}, expect height {}", &self.context.chain_tip, @@ -1392,7 +1398,9 @@ impl<'a> SortitionHandleTx<'a> { &mut self, leader_key: &LeaderKeyRegisterOp, ) -> Result { - assert!(leader_key.block_height < BLOCK_HEIGHT_MAX); + if leader_key.block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let chain_tip = self.context.chain_tip.clone(); let key_status = @@ -1425,7 +1433,9 @@ impl<'a> SortitionHandleTx<'a> { vtxindex: u32, tip: &SortitionId, ) -> Result, db_error> { - assert!(block_height < BLOCK_HEIGHT_MAX); + if block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let ancestor_id = match get_ancestor_sort_id_tx(self, block_height, tip)? { Some(id) => id, None => { @@ -1520,7 +1530,9 @@ impl SortitionHandle for SortitionHandleTx<'_> { &mut self, block_height: u64, ) -> Result, db_error> { - assert!(block_height < BLOCK_HEIGHT_MAX); + if block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let chain_tip = self.context.chain_tip.clone(); SortitionDB::get_ancestor_snapshot_tx(self, block_height, &chain_tip) } @@ -2119,7 +2131,9 @@ impl<'a> SortitionHandleConn<'a> { /// Returns None if the block height or block hash does not correspond to a /// known snapshot. pub fn get_consensus_at(&self, block_height: u64) -> Result, db_error> { - assert!(block_height < BLOCK_HEIGHT_MAX); + if block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } match SortitionDB::get_ancestor_snapshot(self, block_height, &self.context.chain_tip)? { Some(sn) => Ok(Some(sn.consensus_hash)), @@ -2131,7 +2145,9 @@ impl<'a> SortitionHandleConn<'a> { &self, block_height: u64, ) -> Result, db_error> { - assert!(block_height < BLOCK_HEIGHT_MAX); + if block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } // Note: This would return None if `block_height` were the height of `chain_tip`. SortitionDB::get_ancestor_snapshot(self, block_height, &self.context.chain_tip) @@ -2203,7 +2219,9 @@ impl<'a> SortitionHandleConn<'a> { &self, burn_block_height: u64, ) -> Result { - assert!(burn_block_height < BLOCK_HEIGHT_MAX); + if burn_block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } test_debug!( "Get snapshot at from sortition tip {}, expect height {}", &self.context.chain_tip, @@ -4955,7 +4973,9 @@ impl SortitionDB { ancestor_block_height: u64, tip_block_hash: &SortitionId, ) -> Result, db_error> { - assert!(ancestor_block_height < BLOCK_HEIGHT_MAX); + if ancestor_block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let ancestor = match get_ancestor_sort_id(ic, ancestor_block_height, tip_block_hash)? { Some(id) => id, @@ -4978,7 +4998,9 @@ impl SortitionDB { ancestor_block_height: u64, tip_block_hash: &SortitionId, ) -> Result, db_error> { - assert!(ancestor_block_height < BLOCK_HEIGHT_MAX); + if ancestor_block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let ancestor = match get_ancestor_sort_id_tx(ic, ancestor_block_height, tip_block_hash)? { Some(id) => id, @@ -5002,7 +5024,9 @@ impl SortitionDB { vtxindex: u32, tip: &SortitionId, ) -> Result, db_error> { - assert!(block_height < BLOCK_HEIGHT_MAX); + if block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let ancestor_id = match get_ancestor_sort_id(ic, block_height, tip)? { Some(id) => id, None => { @@ -5019,7 +5043,9 @@ impl SortitionDB { block_height: u64, vtxindex: u32, ) -> Result, db_error> { - assert!(block_height < BLOCK_HEIGHT_MAX); + if block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let qry = "SELECT * FROM block_commits WHERE sortition_id = ?1 AND block_height = ?2 AND vtxindex = ?3 LIMIT 2"; let args = params![sortition, u64_to_sql(block_height)?, vtxindex]; @@ -5041,7 +5067,9 @@ impl SortitionDB { key_vtxindex: u32, tip: &SortitionId, ) -> Result, db_error> { - assert!(key_block_height < BLOCK_HEIGHT_MAX); + if key_block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let ancestor_snapshot = match SortitionDB::get_ancestor_snapshot(ic, key_block_height, tip)? { Some(sn) => sn, @@ -5227,7 +5255,9 @@ impl SortitionDB { burn_block_height: u64, chain_tip: &SortitionId, ) -> Result { - assert!(burn_block_height < BLOCK_HEIGHT_MAX); + if burn_block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } test_debug!( "Get snapshot at from sortition tip {}, expect height {}", chain_tip, @@ -5525,7 +5555,9 @@ impl SortitionHandleTx<'_> { leader_key: &LeaderKeyRegisterOp, sort_id: &SortitionId, ) -> Result<(), db_error> { - assert!(leader_key.block_height < BLOCK_HEIGHT_MAX); + if leader_key.block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } let args = params![ leader_key.txid, @@ -5633,7 +5665,9 @@ impl SortitionHandleTx<'_> { block_commit: &LeaderBlockCommitOp, sort_id: &SortitionId, ) -> Result<(), db_error> { - assert!(block_commit.block_height < BLOCK_HEIGHT_MAX); + if block_commit.block_height >= BLOCK_HEIGHT_MAX { + return Err(db_error::BlockHeightOutOfRange); + } // serialize tx input to JSON let tx_input_str = @@ -5732,8 +5766,10 @@ impl SortitionHandleTx<'_> { snapshot: &BlockSnapshot, total_pox_payouts: (Vec, u128), ) -> Result<(), db_error> { - assert!(snapshot.block_height < BLOCK_HEIGHT_MAX); - assert!(snapshot.num_sortitions < BLOCK_HEIGHT_MAX); + if snapshot.block_height >= BLOCK_HEIGHT_MAX || snapshot.num_sortitions >= BLOCK_HEIGHT_MAX + { + return Err(db_error::BlockHeightOutOfRange); + } let pox_payouts_json = serde_json::to_string(&total_pox_payouts) .expect("FATAL: could not encode `total_pox_payouts` as JSON"); diff --git a/stackslib/src/chainstate/coordinator/mod.rs b/stackslib/src/chainstate/coordinator/mod.rs index f25b2e5fc20..26f22dab0dd 100644 --- a/stackslib/src/chainstate/coordinator/mod.rs +++ b/stackslib/src/chainstate/coordinator/mod.rs @@ -1732,6 +1732,16 @@ impl< Ok(None) } + /// A helper function for exposing the private process_new_pox_anchor_test function + #[cfg(test)] + pub fn process_new_pox_anchor_test( + &mut self, + block_id: BlockHeaderHash, + already_processed_burn_blocks: &mut HashSet, + ) -> Result, Error> { + self.process_new_pox_anchor(block_id, already_processed_burn_blocks) + } + /// Process a new PoX anchor block, possibly resulting in the PoX history being unwound and /// replayed through a different sequence of consensus hashes. If the new anchor block causes /// the node to reach a prepare-phase that elects a network-affirmed anchor block that we don't diff --git a/stackslib/src/chainstate/coordinator/tests.rs b/stackslib/src/chainstate/coordinator/tests.rs index ed8f7cbfa25..d7e15a18490 100644 --- a/stackslib/src/chainstate/coordinator/tests.rs +++ b/stackslib/src/chainstate/coordinator/tests.rs @@ -23,7 +23,7 @@ use std::sync::Arc; use clarity::vm::clarity::TransactionConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; use clarity::vm::database::BurnStateDB; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::Value; use lazy_static::lazy_static; @@ -640,7 +640,7 @@ fn make_genesis_block_with_recipients( .0; builder - .try_mine_tx(&mut epoch_tx, &coinbase_op, None) + .try_mine_tx(&mut epoch_tx, &coinbase_op, None, &mut 0) .unwrap(); let block = builder.mine_anchored_block(&mut epoch_tx); @@ -904,11 +904,13 @@ fn make_stacks_block_with_input( .0; builder - .try_mine_tx(&mut epoch_tx, &coinbase_op, None) + .try_mine_tx(&mut epoch_tx, &coinbase_op, None, &mut 0) .unwrap(); for tx in txs { - builder.try_mine_tx(&mut epoch_tx, tx, None).unwrap(); + builder + .try_mine_tx(&mut epoch_tx, tx, None, &mut 0) + .unwrap(); } let block = builder.mine_anchored_block(&mut epoch_tx); @@ -4830,7 +4832,7 @@ fn get_total_stacked_info( parent_tip: &StacksBlockId, reward_cycle: u64, is_pox_2: bool, -) -> Result { +) -> Result { chainstate .with_read_only_clarity_tx(burn_dbconn, parent_tip, |conn| { conn.with_readonly_clarity_env( diff --git a/stackslib/src/chainstate/nakamoto/coordinator/mod.rs b/stackslib/src/chainstate/nakamoto/coordinator/mod.rs index ce736616418..a154c330623 100644 --- a/stackslib/src/chainstate/nakamoto/coordinator/mod.rs +++ b/stackslib/src/chainstate/nakamoto/coordinator/mod.rs @@ -363,28 +363,13 @@ pub fn load_nakamoto_reward_set( provider: &U, ) -> Result, Error> { let cycle_start_height = burnchain.nakamoto_first_block_of_cycle(reward_cycle); - - let epoch_at_height = SortitionDB::get_stacks_epoch(sort_db.conn(), cycle_start_height)? - .unwrap_or_else(|| { - panic!( - "FATAL: no epoch defined for burn height {}", - cycle_start_height - ) - }); - - // Find the first Stacks block in this reward cycle's preceding prepare phase. - // This block will have invoked `.signers.stackerdb-set-signer-slots()` with the reward set. - // Note that we may not have processed it yet. But, if we do find it, then it's - // unique (and since Nakamoto Stacks blocks are processed in order, the anchor block - // cannot change later). - let first_epoch30_reward_cycle = burnchain - .block_height_to_reward_cycle(epoch_at_height.start_height) - .expect("FATAL: no reward cycle for epoch 3.0 start height"); - - if !epoch_at_height - .epoch_id - .uses_nakamoto_reward_set(reward_cycle, first_epoch30_reward_cycle) - { + let prepare_phase_start_height = + cycle_start_height.saturating_sub(u64::from(burnchain.pox_constants.prepare_length)); + let epoch_at_height = + SortitionDB::get_stacks_epoch(sort_db.conn(), prepare_phase_start_height)?.unwrap_or_else( + || panic!("FATAL: no epoch defined for burn height {prepare_phase_start_height}"), + ); + if epoch_at_height.epoch_id < StacksEpochId::Epoch30 { // in epoch 2.5, and in the first reward cycle of epoch 3.0, the reward set can *only* be found in the sortition DB. // The nakamoto chain-processing rules aren't active yet, so we can't look for the reward // cycle info in the nakamoto chain state. @@ -392,7 +377,7 @@ pub fn load_nakamoto_reward_set( get_ancestor_sort_id(&sort_db.index_conn(), cycle_start_height, sortition_tip)? else { // reward cycle is too far in the future - warn!("Requested reward cycle start ancestor sortition ID for cycle {} prepare-end height {}, but tip is {}", reward_cycle, cycle_start_height, sortition_tip); + warn!("Requested reward cycle start ancestor sortition ID for cycle {reward_cycle} prepare-end height {cycle_start_height}, but tip is {sortition_tip}"); return Ok(None); }; diff --git a/stackslib/src/chainstate/nakamoto/coordinator/tests.rs b/stackslib/src/chainstate/nakamoto/coordinator/tests.rs index 24e813f1e05..9ba2ba59a2f 100644 --- a/stackslib/src/chainstate/nakamoto/coordinator/tests.rs +++ b/stackslib/src/chainstate/nakamoto/coordinator/tests.rs @@ -28,8 +28,7 @@ use stacks_common::address::{AddressHashMode, C32_ADDRESS_VERSION_TESTNET_SINGLE use stacks_common::bitvec::BitVec; use stacks_common::consts::{FIRST_BURNCHAIN_CONSENSUS_HASH, FIRST_STACKS_BLOCK_HASH}; use stacks_common::types::chainstate::{ - BurnchainHeaderHash, ConsensusHash, StacksAddress, StacksBlockId, StacksPrivateKey, - StacksPublicKey, + BurnchainHeaderHash, StacksAddress, StacksBlockId, StacksPrivateKey, StacksPublicKey, }; use stacks_common::types::{Address, StacksEpoch, StacksPublicKeyBuffer}; use stacks_common::util::hash::{to_hex, Hash160}; @@ -59,8 +58,8 @@ use crate::chainstate::stacks::events::TransactionOrigin; use crate::chainstate::stacks::tests::TestStacksNode; use crate::chainstate::stacks::{ Error as ChainstateError, StacksTransaction, StacksTransactionSigner, TenureChangeCause, - TenureChangePayload, TokenTransferMemo, TransactionAnchorMode, TransactionAuth, - TransactionPayload, TransactionSmartContract, TransactionVersion, + TokenTransferMemo, TransactionAnchorMode, TransactionAuth, TransactionPayload, + TransactionSmartContract, TransactionVersion, }; use crate::chainstate::tests::TestChainstateConfig; use crate::clarity::vm::types::StacksAddressExtensions; @@ -86,24 +85,6 @@ impl NakamotoStagingBlocksConnRef<'_> { } } -impl TenureChangePayload { - pub fn extend_with_cause( - &self, - burn_view_consensus_hash: ConsensusHash, - last_tenure_block_id: StacksBlockId, - num_blocks_so_far: u32, - cause: TenureChangeCause, - ) -> Self { - let mut ext = self.extend( - burn_view_consensus_hash, - last_tenure_block_id, - num_blocks_so_far, - ); - ext.cause = cause; - ext - } -} - /// Bring a TestPeer into the Nakamoto Epoch fn advance_to_nakamoto( peer: &mut TestPeer, @@ -942,7 +923,7 @@ fn block_descendant() { pox_constants.v2_unlock_height = 21; pox_constants.pox_3_activation_height = 26; pox_constants.v3_unlock_height = 27; - pox_constants.pox_4_activation_height = 28; + pox_constants.pox_4_activation_height = 33; let mut boot_plan = NakamotoBootPlan::new(function_name!()) .with_test_stackers(test_stackers) @@ -1031,7 +1012,7 @@ fn block_info_tests(use_primary_testnet: bool) { pox_constants.v2_unlock_height = 21; pox_constants.pox_3_activation_height = 26; pox_constants.v3_unlock_height = 27; - pox_constants.pox_4_activation_height = 28; + pox_constants.pox_4_activation_height = 33; let chain_id = if use_primary_testnet { CHAIN_ID_TESTNET @@ -1466,7 +1447,7 @@ fn pox_treatment() { pox_constants.v2_unlock_height = 21; pox_constants.pox_3_activation_height = 26; pox_constants.v3_unlock_height = 27; - pox_constants.pox_4_activation_height = 28; + pox_constants.pox_4_activation_height = 33; let mut boot_plan = NakamotoBootPlan::new(function_name!()) .with_test_stackers(test_stackers.clone()) @@ -1719,7 +1700,7 @@ fn transactions_indexing() { pox_constants.v2_unlock_height = 21; pox_constants.pox_3_activation_height = 26; pox_constants.v3_unlock_height = 27; - pox_constants.pox_4_activation_height = 28; + pox_constants.pox_4_activation_height = 33; let mut boot_plan = NakamotoBootPlan::new(function_name!()) .with_test_stackers(test_stackers.clone()) @@ -1784,7 +1765,7 @@ fn transactions_not_indexing() { pox_constants.v2_unlock_height = 21; pox_constants.pox_3_activation_height = 26; pox_constants.v3_unlock_height = 27; - pox_constants.pox_4_activation_height = 28; + pox_constants.pox_4_activation_height = 33; let mut boot_plan = NakamotoBootPlan::new(function_name!()) .with_test_stackers(test_stackers.clone()) @@ -3897,7 +3878,7 @@ fn process_next_nakamoto_block_deadlock() { pox_constants.v2_unlock_height = 21; pox_constants.pox_3_activation_height = 26; pox_constants.v3_unlock_height = 27; - pox_constants.pox_4_activation_height = 28; + pox_constants.pox_4_activation_height = 33; let mut boot_plan = NakamotoBootPlan::new(function_name!()) .with_test_stackers(test_stackers) diff --git a/stackslib/src/chainstate/nakamoto/miner.rs b/stackslib/src/chainstate/nakamoto/miner.rs index fbf7cba6fd3..628971c17ca 100644 --- a/stackslib/src/chainstate/nakamoto/miner.rs +++ b/stackslib/src/chainstate/nakamoto/miner.rs @@ -28,7 +28,7 @@ use crate::chainstate::nakamoto::{ MaturedMinerRewards, NakamotoBlock, NakamotoBlockHeader, NakamotoChainState, SetupBlockResult, }; use crate::chainstate::stacks::address::StacksAddressExtensions; -use crate::chainstate::stacks::db::blocks::DummyEventDispatcher; +use crate::chainstate::stacks::db::blocks::{DummyEventDispatcher, MAX_RECEIPT_SIZES}; use crate::chainstate::stacks::db::{ ChainstateTx, ClarityTx, StacksBlockHeaderTypes, StacksChainState, StacksHeaderInfo, }; @@ -37,7 +37,7 @@ use crate::chainstate::stacks::miner::{ }; use crate::chainstate::stacks::{Error, StacksBlockHeader, *}; use crate::clarity_vm::clarity::ClarityInstance; -use crate::config::DEFAULT_CONTRACT_COST_LIMIT_PERCENTAGE; +use crate::config::{DEFAULT_CONTRACT_COST_LIMIT_PERCENTAGE, DEFAULT_MAX_TENURE_BYTES}; use crate::core::mempool::*; use crate::core::*; use crate::monitoring::{ @@ -96,6 +96,8 @@ pub struct NakamotoBlockBuilder { /// Percentage of a block's budget that may be consumed by /// contract calls before reverting to stx transfers/boot contract calls only contract_limit_percentage: Option, + /// Maximum size of the whole tenure + pub max_tenure_bytes: u64, } /// NB: No PartialEq implementation is deliberate in order to ensure that we use the appropriate @@ -235,6 +237,7 @@ impl NakamotoBlockBuilder { header: NakamotoBlockHeader::genesis(), soft_limit: None, contract_limit_percentage: None, + max_tenure_bytes: u64::from(DEFAULT_MAX_TENURE_BYTES), } } @@ -266,6 +269,7 @@ impl NakamotoBlockBuilder { soft_limit: Option, contract_limit_percentage: Option, timestamp: Option, + max_tenure_bytes: u64, ) -> Result { let next_height = parent_stacks_header .anchored_header @@ -308,6 +312,7 @@ impl NakamotoBlockBuilder { ), soft_limit, contract_limit_percentage, + max_tenure_bytes, }) } @@ -671,6 +676,7 @@ impl NakamotoBlockBuilder { None, settings.mempool_settings.contract_cost_limit_percentage, None, + settings.max_tenure_bytes, )?; let ts_start = get_epoch_time_ms(); @@ -801,11 +807,26 @@ impl BlockBuilder for NakamotoBlockBuilder { tx_len: u64, limit_behavior: &BlockLimitFunction, max_execution_time: Option, + total_receipts_size: &mut u64, ) -> TransactionResult { if self.bytes_so_far + tx_len >= u64::from(MAX_EPOCH_SIZE) { return TransactionResult::skipped_due_to_error(tx, Error::BlockTooBigError); } + if let Some(parent_header) = &self.parent_header { + let mut total_tenure_size = self.bytes_so_far + tx_len; + + // if we are in the same tenure of the parent, accumulate the parent total_tenure_size + // note that total_tenure_size is reset whenever a new tenure extend happens + if parent_header.consensus_hash == self.header.consensus_hash { + total_tenure_size += parent_header.total_tenure_size; + } + + if total_tenure_size >= self.max_tenure_bytes { + return TransactionResult::skipped_due_to_error(tx, Error::TenureTooBigError); + } + } + let non_boot_code_contract_call = match &tx.payload { TransactionPayload::ContractCall(cc) => !cc.address.is_boot_code_addr(), TransactionPayload::SmartContract(..) => true, @@ -846,11 +867,23 @@ impl BlockBuilder for NakamotoBlockBuilder { } let cost_before = clarity_tx.cost_so_far(); - let (_fee, receipt) = match StacksChainState::process_transaction( + let (_fee, receipt) = match StacksChainState::process_transaction_with_check( clarity_tx, tx, quiet, max_execution_time, + |receipt| { + let size = receipt.size().ok_or_else(|| { + Error::InvalidStacksBlock("Could not calculate receipt size".into()) + })?; + let next_size = size.saturating_add(*total_receipts_size); + if next_size >= MAX_RECEIPT_SIZES { + Err(Error::BlockCostExceeded) + } else { + *total_receipts_size = next_size; + Ok(()) + } + }, ) { Ok(x) => x, Err(e) => { diff --git a/stackslib/src/chainstate/nakamoto/mod.rs b/stackslib/src/chainstate/nakamoto/mod.rs index e45e57c399b..25abcda6dd8 100644 --- a/stackslib/src/chainstate/nakamoto/mod.rs +++ b/stackslib/src/chainstate/nakamoto/mod.rs @@ -296,6 +296,20 @@ pub static NAKAMOTO_CHAINSTATE_SCHEMA_7: &[&str] = &[ "CREATE INDEX IF NOT EXISTS naka_block_headers_by_burn_ht ON nakamoto_block_headers(burn_header_height);" ]; +pub static NAKAMOTO_CHAINSTATE_SCHEMA_8: &[&str] = &[ + r#"UPDATE db_config SET version = "13";"#, + // Add a `total_tenure_size` field to the block header row, so we can keep track + // of the whole tenure size (and eventually limit it) + // + // Default to 0. + r#" + -- total_tenure_size cannot be consensus critical as existing nodes which migrate will report a 0 size while + -- nodes booting from genesis sync will get the true tenure size + ALTER TABLE nakamoto_block_headers + ADD COLUMN total_tenure_size NOT NULL DEFAULT 0; + "#, +]; + #[cfg(test)] mod fault_injection { static PROCESS_BLOCK_STALL: std::sync::Mutex = std::sync::Mutex::new(false); @@ -2657,6 +2671,19 @@ impl NakamotoChainState { Ok(result) } + /// Load the total_tenure_size for a Nakamoto header + pub fn get_block_header_nakamoto_total_tenure_size( + chainstate_conn: &Connection, + index_block_hash: &StacksBlockId, + ) -> Result, ChainstateError> { + let sql = + "SELECT total_tenure_size FROM nakamoto_block_headers WHERE index_block_hash = ?1"; + let result = query_row_panic(chainstate_conn, sql, &[&index_block_hash], || { + "FATAL: multiple rows for the same block hash".to_string() + })?; + Ok(result) + } + /// Load an epoch2 header pub fn get_block_header_epoch2( chainstate_conn: &Connection, @@ -3253,6 +3280,7 @@ impl NakamotoChainState { stacks_block_height, burn_header_height, burn_header_timestamp, + total_tenure_size, .. } = tip_info; @@ -3309,6 +3337,7 @@ impl NakamotoChainState { "Nakamoto block StacksHeaderInfo did not set burnchain view".into(), )) })?, + total_tenure_size ]; chainstate_tx.execute( @@ -3341,8 +3370,9 @@ impl NakamotoChainState { vrf_proof, signer_bitvec, height_in_tenure, - burn_view) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27)", + burn_view, + total_tenure_size) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28)", args )?; @@ -3408,6 +3438,9 @@ impl NakamotoChainState { let mut marf_keys = vec![]; let mut marf_values = vec![]; + // assume a new tenure (we will eventually add the parent accumulated size later) + let mut total_tenure_size = block_size; + if new_tenure { // make the coinbase height point to this tenure-start block marf_keys.push(nakamoto_keys::ongoing_tenure_coinbase_height( @@ -3471,6 +3504,28 @@ impl NakamotoChainState { marf_keys.push(nakamoto_keys::ongoing_tenure_id().to_string()); marf_values.push(nakamoto_keys::make_tenure_id_value(&tenure_id)); + } else { + // if we are here (no new tenure or tenure_extend) we need to accumulate the parent total tenure size + if let Some(current_total_tenure_size) = + NakamotoChainState::get_block_header_nakamoto_total_tenure_size( + &headers_tx, + &new_tip.parent_block_id, + )? + { + total_tenure_size = match total_tenure_size.checked_add(current_total_tenure_size) { + Some(total_tenure_size) => total_tenure_size, + // in the extremely improbable case of overflow, just throw the tenure too big error + None => { + return Err(ChainstateError::TenureTooBigError); + } + }; + } else { + warn!( + "Unable to retrieve total tenure size"; + "consensus_hash" => %new_tip.consensus_hash, + "parent_block_id" => %new_tip.parent_block_id, + ); + } } // record the highest block in this tenure @@ -3502,6 +3557,7 @@ impl NakamotoChainState { burn_header_timestamp: new_burnchain_timestamp, anchored_block_size: block_size, burn_view: Some(burn_view.clone()), + total_tenure_size, }; let tenure_fees = block_fees diff --git a/stackslib/src/chainstate/nakamoto/shadow.rs b/stackslib/src/chainstate/nakamoto/shadow.rs index 8f3d3aeba69..58133588a29 100644 --- a/stackslib/src/chainstate/nakamoto/shadow.rs +++ b/stackslib/src/chainstate/nakamoto/shadow.rs @@ -70,6 +70,7 @@ use crate::chainstate::stacks::{ use crate::clarity::vm::types::StacksAddressExtensions; use crate::clarity_vm::clarity::ClarityInstance; use crate::clarity_vm::database::SortitionDBRef; +use crate::config::DEFAULT_MAX_TENURE_BYTES; use crate::net::Error as NetError; use crate::util_lib::db::{query_row, u64_to_sql, Error as DBError}; @@ -520,6 +521,7 @@ impl NakamotoBlockBuilder { break; } + let mut receipts_total = 0u64; let mut miner_tenure_info = builder.shadow_load_tenure_info(&mut chainstate, burn_dbconn, tenure_cause)?; let burn_chain_height = miner_tenure_info.burn_tip_height; @@ -536,6 +538,7 @@ impl NakamotoBlockBuilder { tx_len, &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut receipts_total, ) { TransactionResult::Success(..) => { debug!("Included {}", &tx.txid()); @@ -726,6 +729,7 @@ impl NakamotoBlockBuilder { None, None, None, + u64::from(DEFAULT_MAX_TENURE_BYTES), )?; let mut block_txs = vec![tenure_change_tx, coinbase_tx]; diff --git a/stackslib/src/chainstate/nakamoto/tests/mod.rs b/stackslib/src/chainstate/nakamoto/tests/mod.rs index 575e777d983..3c58a33f793 100644 --- a/stackslib/src/chainstate/nakamoto/tests/mod.rs +++ b/stackslib/src/chainstate/nakamoto/tests/mod.rs @@ -668,6 +668,7 @@ pub fn test_load_store_update_nakamoto_blocks() { burn_header_timestamp: 1000, anchored_block_size: 12345, burn_view: None, + total_tenure_size: 0, }; let epoch2_execution_cost = ExecutionCost { @@ -801,6 +802,7 @@ pub fn test_load_store_update_nakamoto_blocks() { burn_header_timestamp: 1001, anchored_block_size: 123, burn_view: Some(nakamoto_header.consensus_hash.clone()), + total_tenure_size: 0, }; let epoch2_block = StacksBlock { @@ -847,6 +849,7 @@ pub fn test_load_store_update_nakamoto_blocks() { burn_header_timestamp: 1001, anchored_block_size: 123, burn_view: Some(nakamoto_header_2.consensus_hash.clone()), + total_tenure_size: 0, }; let nakamoto_block_2 = NakamotoBlock { @@ -888,6 +891,7 @@ pub fn test_load_store_update_nakamoto_blocks() { burn_header_timestamp: 1001, anchored_block_size: 123, burn_view: Some(nakamoto_header_3.consensus_hash.clone()), + total_tenure_size: 0, }; let nakamoto_block_3 = NakamotoBlock { @@ -921,6 +925,7 @@ pub fn test_load_store_update_nakamoto_blocks() { burn_header_timestamp: 1001, anchored_block_size: 123, burn_view: Some(nakamoto_header_3.consensus_hash.clone()), + total_tenure_size: 0, }; let nakamoto_block_3_weight_2 = NakamotoBlock { @@ -954,6 +959,7 @@ pub fn test_load_store_update_nakamoto_blocks() { burn_header_timestamp: 1001, anchored_block_size: 123, burn_view: Some(nakamoto_header_4.consensus_hash.clone()), + total_tenure_size: 0, }; let nakamoto_block_4 = NakamotoBlock { diff --git a/stackslib/src/chainstate/nakamoto/tests/node.rs b/stackslib/src/chainstate/nakamoto/tests/node.rs index 02969cf7c4b..656bff1316b 100644 --- a/stackslib/src/chainstate/nakamoto/tests/node.rs +++ b/stackslib/src/chainstate/nakamoto/tests/node.rs @@ -48,6 +48,7 @@ use crate::chainstate::stacks::db::*; use crate::chainstate::stacks::miner::*; use crate::chainstate::stacks::tests::TestStacksNode; use crate::chainstate::stacks::{Error as ChainstateError, StacksBlock, *}; +use crate::config::DEFAULT_MAX_TENURE_BYTES; use crate::core::{BOOT_BLOCK_HASH, STACKS_EPOCH_3_0_MARKER}; use crate::net::relay::{BlockAcceptResponse, Relayer}; use crate::net::test::{TestPeer, *}; @@ -796,6 +797,7 @@ impl TestStacksNode { None, None, None, + u64::from(DEFAULT_MAX_TENURE_BYTES), )? } else { NakamotoBlockBuilder::new_first_block( @@ -1010,6 +1012,7 @@ impl TestStacksNode { builder.load_tenure_info(&mut chainstate, burn_dbconn, tenure_cause)?; let burn_chain_height = miner_tenure_info.burn_tip_height; let mut tenure_tx = builder.tenure_begin(burn_dbconn, &mut miner_tenure_info)?; + let mut total = 0; for tx in txs.into_iter() { let tx_len = tx.tx_len(); match builder.try_mine_tx_with_len( @@ -1018,6 +1021,7 @@ impl TestStacksNode { tx_len, &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut total, ) { TransactionResult::Success(..) => { debug!("Included {}", &tx.txid()); @@ -1062,6 +1066,120 @@ impl TestStacksNode { Ok((block, size, cost)) } + /// Insert a staging pre-Nakamoto block and microblocks + /// then process them as the next ready block + /// NOTE: Will panic if called with unprocessed staging + /// blocks already in the queue. + pub fn process_pre_nakamoto_next_ready_block<'a>( + stacks_node: &mut TestStacksNode, + sortdb: &mut SortitionDB, + miner: &mut TestMiner, + coord: &mut ChainsCoordinator< + 'a, + TestEventObserver, + (), + OnChainRewardSetProvider<'a, TestEventObserver>, + (), + (), + BitcoinIndexer, + >, + block: &StacksBlock, + microblocks: &[StacksMicroblock], + ) -> Result, ChainstateError> { + // First append the block to the staging blocks + { + let ic = sortdb.index_conn(); + let tip = SortitionDB::get_canonical_burn_chain_tip(&ic).unwrap(); + + let blocks_path = stacks_node.chainstate.blocks_path.clone(); + + let mut block_tx = stacks_node.chainstate.db_tx_begin()?; + + let block_hash = block.block_hash(); + let sort_handle = SortitionHandleConn::open_reader_consensus(&ic, &tip.consensus_hash)?; + let block_commit = SortitionDB::get_block_commit_for_stacks_block( + sort_handle.conn(), + &tip.consensus_hash, + &block_hash, + ) + .unwrap() + .unwrap(); + + let parent_snapshot = SortitionDB::get_block_snapshot_for_winning_stacks_block( + &ic, + &tip.parent_sortition_id, + &block.header.parent_block, + ) + .unwrap() + .unwrap(); + // burn chain tip that selected this commit's block + let burn_chain_tip = sort_handle + .get_block_snapshot(&block_commit.burn_header_hash) + .unwrap() + .unwrap(); + + let sortition_burns = SortitionDB::get_block_burn_amount(&sort_handle, &burn_chain_tip) + .expect("FATAL: have block commit but no total burns in its sortition"); + + // queue block up for processing + StacksChainState::store_staging_block_test( + &mut block_tx, + &blocks_path, + &tip.consensus_hash, + block, + &parent_snapshot.consensus_hash, + block_commit.burn_fee, + sortition_burns, + 5, + )?; + + block_tx.commit()?; + + debug!( + "Stored {}/{} to staging", + &tip.consensus_hash, + &block.block_hash() + ); + } + + let canonical_sortition_tip = coord.canonical_sortition_tip.clone().expect( + "FAIL: processing a new Stacks block, but don't have a canonical sortition tip", + ); + let mut sort_tx = sortdb.tx_begin_at_tip(); + let res = stacks_node + .chainstate + .process_next_staging_block(&mut sort_tx, coord.dispatcher) + .map(|(epoch_receipt, _)| epoch_receipt)?; + sort_tx.commit()?; + if let Some(block_receipt) = res.as_ref() { + let in_sortition_set = coord + .sortition_db + .is_stacks_block_in_sortition_set( + &canonical_sortition_tip, + &block_receipt.header.anchored_header.block_hash(), + ) + .unwrap(); + if in_sortition_set { + let block_hash = block_receipt.header.anchored_header.block_hash(); + // Was this block sufficiently confirmed by the prepare phase that it was a PoX + // anchor block? And if we're in epoch 2.1, does it match the heaviest-confirmed + // block-commit in the burnchain DB, and is it affirmed by the majority of the + // network? + if let Some(pox_anchor) = coord + .sortition_db + .is_stacks_block_pox_anchor(&block_hash, &canonical_sortition_tip) + .unwrap() + { + debug!("Discovered PoX anchor block {block_hash} off of canonical sortition tip {canonical_sortition_tip}"); + coord + .process_new_pox_anchor_test(pox_anchor, &mut HashSet::new()) + .unwrap(); + } + } + } + Ok(res) + } + /// Insert a staging Nakamoto block as a pushed block and /// then process it as the next ready block /// NOTE: Will panic if called with unprocessed staging diff --git a/stackslib/src/chainstate/stacks/boot/contract_tests.rs b/stackslib/src/chainstate/stacks/boot/contract_tests.rs index 9b042dd8a4e..d7b9302de7b 100644 --- a/stackslib/src/chainstate/stacks/boot/contract_tests.rs +++ b/stackslib/src/chainstate/stacks/boot/contract_tests.rs @@ -6,7 +6,7 @@ use clarity::vm::analysis::mem_type_check; use clarity::vm::clarity::TransactionConnection; use clarity::vm::contexts::OwnedEnvironment; use clarity::vm::database::*; -use clarity::vm::errors::{CheckErrors, Error}; +use clarity::vm::errors::{CheckErrorKind, VmExecutionError}; use clarity::vm::test_util::{execute, symbols_from_values, TEST_BURN_STATE_DB, TEST_HEADER_DB}; use clarity::vm::types::{ OptionalData, PrincipalData, QualifiedContractIdentifier, ResponseData, StandardPrincipalData, @@ -31,7 +31,7 @@ use crate::chainstate::stacks::boot::{ use crate::chainstate::stacks::index::ClarityMarfTrieId; use crate::chainstate::stacks::{C32_ADDRESS_VERSION_TESTNET_SINGLESIG, *}; use crate::clarity_vm::clarity::{ - ClarityBlockConnection, ClarityMarfStore, ClarityMarfStoreTransaction, Error as ClarityError, + ClarityBlockConnection, ClarityError, ClarityMarfStore, ClarityMarfStoreTransaction, WritableMarfStore, }; use crate::clarity_vm::database::marf::MarfedKV; @@ -1710,8 +1710,11 @@ fn simple_epoch21_test() { ) .expect_err("2.0 'bad' contract should not deploy successfully") { - ClarityError::Analysis(e) => { - assert_eq!(*e.err, CheckErrors::UnknownFunction("stx-account".into())); + ClarityError::StaticCheck(e) => { + assert_eq!( + *e.err, + CheckErrorKind::UnknownFunction("stx-account".into()) + ); } e => panic!("Should have caused an analysis error: {:#?}", e), }; @@ -1740,7 +1743,9 @@ fn simple_epoch21_test() { ClarityError::Interpreter(e) => { assert_eq!( e, - Error::Unchecked(CheckErrors::NameAlreadyUsed("stx-account".into())) + VmExecutionError::Unchecked(CheckErrorKind::NameAlreadyUsed( + "stx-account".into() + )) ); } e => panic!("Should have caused an Interpreter error: {:#?}", e), diff --git a/stackslib/src/chainstate/stacks/boot/mod.rs b/stackslib/src/chainstate/stacks/boot/mod.rs index b60fe5cd3f0..7464c49052e 100644 --- a/stackslib/src/chainstate/stacks/boot/mod.rs +++ b/stackslib/src/chainstate/stacks/boot/mod.rs @@ -19,11 +19,11 @@ use std::collections::BTreeMap; use std::sync::LazyLock; use clarity::types::Address; -use clarity::vm::analysis::CheckErrors; -use clarity::vm::clarity::{Error as ClarityError, TransactionConnection}; +use clarity::vm::analysis::CheckErrorKind; +use clarity::vm::clarity::{ClarityError, TransactionConnection}; use clarity::vm::costs::LimitedCostTracker; use clarity::vm::database::{ClarityDatabase, NULL_BURN_STATE_DB, NULL_HEADER_DB}; -use clarity::vm::errors::Error as VmError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::events::StacksTransactionEvent; use clarity::vm::representations::ContractName; use clarity::vm::types::{ @@ -365,7 +365,7 @@ impl StacksChainState { fn mark_pox_cycle_handled( db: &mut ClarityDatabase, cycle_number: u64, - ) -> Result<(), clarity::vm::errors::Error> { + ) -> Result<(), VmExecutionError> { let db_key = Self::handled_pox_cycle_start_key(cycle_number); db.put_data(&db_key, &POX_CYCLE_START_HANDLED_VALUE.to_string())?; Ok(()) @@ -1358,8 +1358,8 @@ impl StacksChainState { // Catch the epoch boundary edge case where burn height >= pox 3 activation height, but // there hasn't yet been a Stacks block. match result { - Err(Error::ClarityError(ClarityError::Interpreter(VmError::Unchecked( - CheckErrors::NoSuchContract(_), + Err(Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( + CheckErrorKind::NoSuchContract(_), )))) => { warn!("Reward cycle attempted to calculate rewards before the PoX contract was instantiated"); return Ok(vec![]); diff --git a/stackslib/src/chainstate/stacks/db/blocks.rs b/stackslib/src/chainstate/stacks/db/blocks.rs index f5d62cd5096..509acac4f71 100644 --- a/stackslib/src/chainstate/stacks/db/blocks.rs +++ b/stackslib/src/chainstate/stacks/db/blocks.rs @@ -19,10 +19,11 @@ use std::io::{Read, Write}; use std::path::PathBuf; use std::{cmp, fs, io}; -pub use clarity::vm::analysis::errors::{CheckError, CheckErrors}; +pub use clarity::vm::analysis::errors::{CheckErrorKind, StaticCheckError}; use clarity::vm::clarity::TransactionConnection; use clarity::vm::costs::LimitedCostTracker; use clarity::vm::database::BurnStateDB; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{ BuffData, PrincipalData, QualifiedContractIdentifier, SequenceData, StacksAddressExtensions as ClarityStacksAddressExtensions, StandardPrincipalData, TupleData, @@ -109,7 +110,7 @@ pub enum MemPoolRejection { NotEnoughFunds(u128, u128), NoSuchContract, NoSuchPublicFunction, - BadFunctionArgument(CheckError), + BadFunctionArgument(StaticCheckError), ContractAlreadyExists(QualifiedContractIdentifier), PoisonMicroblocksDoNotConflict, NoAnchorBlockWithPubkeyHash(Hash160), @@ -156,6 +157,8 @@ pub struct SetupBlockResult<'a, 'b> { pub struct DummyEventDispatcher; +pub const MAX_RECEIPT_SIZES: u64 = 50 * 1024 * 1024; + impl BlockEventDispatcher for DummyEventDispatcher { fn announce_block( &self, @@ -306,8 +309,8 @@ impl From for MemPoolRejection { } } -impl From for MemPoolRejection { - fn from(e: clarity::vm::errors::Error) -> MemPoolRejection { +impl From for MemPoolRejection { + fn from(e: VmExecutionError) -> MemPoolRejection { MemPoolRejection::Other(e.to_string()) } } @@ -1515,6 +1518,31 @@ impl StacksChainState { return Ok(None); } + #[cfg(test)] + #[allow(clippy::too_many_arguments)] + /// A helper function for exposing store_staging_block + pub fn store_staging_block_test( + tx: &mut DBTx<'_>, + blocks_path: &str, + consensus_hash: &ConsensusHash, + block: &StacksBlock, + parent_consensus_hash: &ConsensusHash, + commit_burn: u64, + sortition_burn: u64, + download_time: u64, + ) -> Result<(), Error> { + Self::store_staging_block( + tx, + blocks_path, + consensus_hash, + block, + parent_consensus_hash, + commit_burn, + sortition_burn, + download_time, + ) + } + /// Store a preprocessed block, queuing it up for subsequent processing. /// The caller should at least verify that the block is attached to some fork in the burn /// chain. @@ -3101,7 +3129,6 @@ impl StacksChainState { return Err(e.into()); } }; - // burn chain tip that selected this commit's block let burn_chain_tip = db_handle .get_block_snapshot(&block_commit.burn_header_hash)? @@ -3927,7 +3954,7 @@ impl StacksChainState { ) -> Result<(bool, Vec), Error> { // is this stacks block the first of a new epoch? let (stacks_parent_epoch, sortition_epoch) = clarity_tx - .with_clarity_db_readonly::<_, Result<_, clarity::vm::errors::Error>>(|db| { + .with_clarity_db_readonly::<_, Result<_, VmExecutionError>>(|db| { Ok(( db.get_clarity_epoch_version()?, db.get_stacks_epoch(chain_tip_burn_header_height), @@ -4467,11 +4494,20 @@ impl StacksChainState { let mut fees = 0u128; let mut burns = 0u128; let mut receipts = vec![]; + let mut total_size = 0u64; for tx in block_txs.iter() { let (tx_fee, mut tx_receipt) = StacksChainState::process_transaction(clarity_tx, tx, false, None)?; fees = fees.checked_add(u128::from(tx_fee)).expect("Fee overflow"); tx_receipt.tx_index = tx_index; + total_size = total_size.saturating_add(tx_receipt.size().ok_or_else(|| { + Error::InvalidStacksBlock("Failure calculating tx receipt size".into()) + })?); + if total_size >= MAX_RECEIPT_SIZES { + return Err(Error::InvalidStacksBlock( + "Total tx receipt size too large".into(), + )); + } burns = burns .checked_add(tx_receipt.stx_burned) .expect("Burns overflow"); @@ -6614,17 +6650,16 @@ impl StacksChainState { } let (block_height, v1_unlock_height, v2_unlock_height, v3_unlock_height) = - clarity_connection - .with_clarity_db_readonly::<_, Result<_, clarity::vm::errors::Error>>( - |ref mut db| { - Ok(( - db.get_current_burnchain_block_height()? as u64, - db.get_v1_unlock_height(), - db.get_v2_unlock_height()?, - db.get_v3_unlock_height()?, - )) - }, - )?; + clarity_connection.with_clarity_db_readonly::<_, Result<_, VmExecutionError>>( + |ref mut db| { + Ok(( + db.get_current_burnchain_block_height()? as u64, + db.get_v1_unlock_height(), + db.get_v2_unlock_height()?, + db.get_v3_unlock_height()?, + )) + }, + )?; // 6: the paying account must have enough funds if !payer.stx_balance.can_transfer_at_burn_block( diff --git a/stackslib/src/chainstate/stacks/db/contracts.rs b/stackslib/src/chainstate/stacks/db/contracts.rs index 11b2ee0d023..24f515805a5 100644 --- a/stackslib/src/chainstate/stacks/db/contracts.rs +++ b/stackslib/src/chainstate/stacks/db/contracts.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -pub use clarity::vm::analysis::errors::CheckErrors; +pub use clarity::vm::analysis::errors::CheckErrorKind; use clarity::vm::contracts::Contract; -use clarity::vm::errors::Error as clarity_vm_error; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{QualifiedContractIdentifier, Value}; use crate::chainstate::stacks::db::*; @@ -31,8 +31,8 @@ impl StacksChainState { clarity_tx .with_clarity_db_readonly(|ref mut db| match db.get_contract(contract_id) { Ok(c) => Ok(Some(c)), - Err(clarity_vm_error::Unchecked(CheckErrors::NoSuchContract(_))) => Ok(None), - Err(e) => Err(clarity_error::Interpreter(e)), + Err(VmExecutionError::Unchecked(CheckErrorKind::NoSuchContract(_))) => Ok(None), + Err(e) => Err(ClarityError::Interpreter(e)), }) .map_err(Error::ClarityError) } @@ -47,10 +47,10 @@ impl StacksChainState { .with_clarity_db_readonly(|ref mut db| { match db.lookup_variable_unknown_descriptor(contract_id, data_var, &epoch) { Ok(c) => Ok(Some(c)), - Err(clarity_vm_error::Unchecked(CheckErrors::NoSuchDataVariable(_))) => { + Err(VmExecutionError::Unchecked(CheckErrorKind::NoSuchDataVariable(_))) => { Ok(None) } - Err(e) => Err(clarity_error::Interpreter(e)), + Err(e) => Err(ClarityError::Interpreter(e)), } }) .map_err(Error::ClarityError) diff --git a/stackslib/src/chainstate/stacks/db/mod.rs b/stackslib/src/chainstate/stacks/db/mod.rs index cd9231becd0..dae996501c1 100644 --- a/stackslib/src/chainstate/stacks/db/mod.rs +++ b/stackslib/src/chainstate/stacks/db/mod.rs @@ -50,7 +50,7 @@ use crate::chainstate::nakamoto::{ HeaderTypeNames, NakamotoBlockHeader, NakamotoChainState, NakamotoStagingBlocksConn, NAKAMOTO_CHAINSTATE_SCHEMA_1, NAKAMOTO_CHAINSTATE_SCHEMA_2, NAKAMOTO_CHAINSTATE_SCHEMA_3, NAKAMOTO_CHAINSTATE_SCHEMA_4, NAKAMOTO_CHAINSTATE_SCHEMA_5, NAKAMOTO_CHAINSTATE_SCHEMA_6, - NAKAMOTO_CHAINSTATE_SCHEMA_7, + NAKAMOTO_CHAINSTATE_SCHEMA_7, NAKAMOTO_CHAINSTATE_SCHEMA_8, }; use crate::chainstate::stacks::address::StacksAddressExtensions; use crate::chainstate::stacks::boot::*; @@ -66,8 +66,8 @@ use crate::chainstate::stacks::{ C32_ADDRESS_VERSION_TESTNET_SINGLESIG, *, }; use crate::clarity_vm::clarity::{ - ClarityBlockConnection, ClarityConnection, ClarityInstance, ClarityReadOnlyConnection, - Error as clarity_error, PreCommitClarityBlock, + ClarityBlockConnection, ClarityConnection, ClarityError, ClarityInstance, + ClarityReadOnlyConnection, PreCommitClarityBlock, }; use crate::clarity_vm::database::marf::MarfedKV; use crate::clarity_vm::database::HeadersDBConn; @@ -185,6 +185,9 @@ pub struct StacksHeaderInfo { /// The burnchain tip that is passed to Clarity while processing this block. /// This should always be `Some()` for Nakamoto blocks and `None` for 2.x blocks pub burn_view: Option, + /// Total tenure size (reset at every tenure extend) in bytes + /// Not consensus-critical (may differ between nodes) + pub total_tenure_size: u64, } #[derive(Debug, Clone, PartialEq)] @@ -283,8 +286,8 @@ impl DBConfig { }); match epoch_id { StacksEpochId::Epoch10 => true, - StacksEpochId::Epoch20 => (1..=12).contains(&version_u32), - StacksEpochId::Epoch2_05 => (2..=12).contains(&version_u32), + StacksEpochId::Epoch20 => (1..=CHAINSTATE_VERSION_NUMBER).contains(&version_u32), + StacksEpochId::Epoch2_05 => (2..=CHAINSTATE_VERSION_NUMBER).contains(&version_u32), StacksEpochId::Epoch21 | StacksEpochId::Epoch22 | StacksEpochId::Epoch23 @@ -293,7 +296,7 @@ impl DBConfig { | StacksEpochId::Epoch30 | StacksEpochId::Epoch31 | StacksEpochId::Epoch32 - | StacksEpochId::Epoch33 => (3..=12).contains(&version_u32), + | StacksEpochId::Epoch33 => (3..=CHAINSTATE_VERSION_NUMBER).contains(&version_u32), } } } @@ -362,6 +365,7 @@ impl StacksHeaderInfo { burn_header_timestamp: 0, anchored_block_size: 0, burn_view: None, + total_tenure_size: 0, } } @@ -382,6 +386,7 @@ impl StacksHeaderInfo { burn_header_timestamp: first_burnchain_block_timestamp, anchored_block_size: 0, burn_view: None, + total_tenure_size: 0, } } @@ -454,6 +459,13 @@ impl FromRow for StacksHeaderInfo { return Err(db_error::ParseError); } + let total_tenure_size = { + match header_type { + HeaderTypeNames::Epoch2 => 0, + HeaderTypeNames::Nakamoto => u64::from_column(row, "total_tenure_size")?, + } + }; + Ok(StacksHeaderInfo { anchored_header: stacks_header, microblock_tail: None, @@ -465,6 +477,7 @@ impl FromRow for StacksHeaderInfo { burn_header_timestamp, anchored_block_size, burn_view, + total_tenure_size, }) } } @@ -545,7 +558,7 @@ impl<'a, 'b> ClarityTx<'a, 'b> { pub fn commit_mined_block( self, block_hash: &StacksBlockId, - ) -> Result { + ) -> Result { Ok(self.block.commit_mined_block(block_hash)?.get_total()) } @@ -652,7 +665,8 @@ impl<'a> DerefMut for ChainstateTx<'a> { } } -pub const CHAINSTATE_VERSION: &str = "12"; +pub const CHAINSTATE_VERSION: &str = "13"; +pub const CHAINSTATE_VERSION_NUMBER: u32 = 13; const CHAINSTATE_INITIAL_SCHEMA: &[&str] = &[ "PRAGMA foreign_keys = ON;", @@ -1153,6 +1167,14 @@ impl StacksChainState { tx.execute_batch(cmd)?; } } + "12" => { + info!( + "Migrating chainstate schema from version 12 to 13: add total_tenure_size field" + ); + for cmd in NAKAMOTO_CHAINSTATE_SCHEMA_8.iter() { + tx.execute_batch(cmd)?; + } + } _ => { error!( "Invalid chain state database: expected version = {}, got {}", @@ -1983,7 +2005,7 @@ impl StacksChainState { parent_id_bhh: &StacksBlockId, contract: &QualifiedContractIdentifier, code: &str, - ) -> Result { + ) -> Result { self.clarity_state.eval_read_only( parent_id_bhh, &HeadersDBConn(StacksDBConn::new(&self.state_index, ())), @@ -2003,7 +2025,7 @@ impl StacksChainState { contract: &QualifiedContractIdentifier, function: &str, args: &[Value], - ) -> Result { + ) -> Result { let headers_db = HeadersDBConn(StacksDBConn::new(&self.state_index, ())); let mut conn = self.clarity_state.read_only_connection_checked( parent_id_bhh, @@ -2777,6 +2799,7 @@ impl StacksChainState { burn_header_timestamp: new_burnchain_timestamp, anchored_block_size: anchor_block_size, burn_view: None, + total_tenure_size: 0, }; StacksChainState::insert_stacks_block_header( diff --git a/stackslib/src/chainstate/stacks/db/transactions.rs b/stackslib/src/chainstate/stacks/db/transactions.rs index a72ed8b0f14..fb587c6876d 100644 --- a/stackslib/src/chainstate/stacks/db/transactions.rs +++ b/stackslib/src/chainstate/stacks/db/transactions.rs @@ -21,7 +21,7 @@ use clarity::vm::clarity::TransactionConnection; use clarity::vm::contexts::{AssetMap, AssetMapEntry, Environment}; use clarity::vm::costs::cost_functions::ClarityCostFunction; use clarity::vm::costs::{runtime_cost, CostTracker, ExecutionCost}; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::{VmExecutionError, VmInternalError}; use clarity::vm::representations::ClarityName; use clarity::vm::types::{ AssetIdentifier, BuffData, PrincipalData, QualifiedContractIdentifier, SequenceData, @@ -33,9 +33,7 @@ use crate::chainstate::nakamoto::miner::MinerTenureInfoCause; use crate::chainstate::stacks::db::*; use crate::chainstate::stacks::miner::TransactionResult; use crate::chainstate::stacks::{Error, StacksMicroblockHeader}; -use crate::clarity_vm::clarity::{ - ClarityConnection, ClarityTransactionConnection, Error as clarity_error, -}; +use crate::clarity_vm::clarity::{ClarityConnection, ClarityError, ClarityTransactionConnection}; use crate::util_lib::strings::VecDisplay; /// This is a safe-to-hash Clarity value @@ -43,12 +41,12 @@ use crate::util_lib::strings::VecDisplay; struct HashableClarityValue(Value); impl TryFrom for HashableClarityValue { - type Error = InterpreterError; + type Error = VmExecutionError; fn try_from(value: Value) -> Result { // check that serialization _will_ be successful when hashed let _bytes = value.serialize_to_vec().map_err(|_| { - InterpreterError::Interpreter(clarity::vm::errors::InterpreterError::Expect( + VmExecutionError::Internal(VmInternalError::Expect( "Failed to serialize asset in NFT during post-condition checks".into(), )) })?; @@ -192,10 +190,10 @@ impl StacksTransactionReceipt { pub fn from_analysis_failure( tx: StacksTransaction, analysis_cost: ExecutionCost, - error: clarity::vm::clarity::Error, + error: ClarityError, ) -> StacksTransactionReceipt { let error_string = match error { - clarity_error::Analysis(ref check_error) => { + ClarityError::StaticCheck(ref check_error) => { if let Some(span) = check_error.diagnostic.spans.first() { format!( ":{}:{}: {}", @@ -205,7 +203,7 @@ impl StacksTransactionReceipt { check_error.diagnostic.message.to_string() } } - clarity_error::Parse(ref parse_error) => { + ClarityError::Parse(ref parse_error) => { if let Some(span) = parse_error.diagnostic.spans.first() { format!( ":{}:{}: {}", @@ -254,7 +252,7 @@ impl StacksTransactionReceipt { tx: StacksTransaction, cost: ExecutionCost, contract_analysis: ContractAnalysis, - error: CheckErrors, + error: CheckErrorKind, ) -> StacksTransactionReceipt { StacksTransactionReceipt { transaction: tx.into(), @@ -273,7 +271,7 @@ impl StacksTransactionReceipt { pub fn from_runtime_failure_contract_call( tx: StacksTransaction, cost: ExecutionCost, - error: CheckErrors, + error: CheckErrorKind, ) -> StacksTransactionReceipt { StacksTransactionReceipt { transaction: tx.into(), @@ -353,7 +351,7 @@ impl From for MemPoolRejection { pub enum ClarityRuntimeTxError { Acceptable { - error: clarity_error, + error: ClarityError, err_type: &'static str, }, AbortedByCallback { @@ -368,35 +366,35 @@ pub enum ClarityRuntimeTxError { reason: String, }, CostError(ExecutionCost, ExecutionCost), - AnalysisError(CheckErrors), - Rejectable(clarity_error), + AnalysisError(CheckErrorKind), + Rejectable(ClarityError), } -pub fn handle_clarity_runtime_error(error: clarity_error) -> ClarityRuntimeTxError { +pub fn handle_clarity_runtime_error(error: ClarityError) -> ClarityRuntimeTxError { match error { // runtime errors are okay - clarity_error::Interpreter(InterpreterError::Runtime(_, _)) => { + ClarityError::Interpreter(VmExecutionError::Runtime(_, _)) => { ClarityRuntimeTxError::Acceptable { error, err_type: "runtime error", } } - clarity_error::Interpreter(InterpreterError::ShortReturn(_)) => { + ClarityError::Interpreter(VmExecutionError::EarlyReturn(_)) => { ClarityRuntimeTxError::Acceptable { error, err_type: "short return/panic", } } - clarity_error::Interpreter(InterpreterError::Unchecked(check_error)) => { + ClarityError::Interpreter(VmExecutionError::Unchecked(check_error)) => { if check_error.rejectable() { - ClarityRuntimeTxError::Rejectable(clarity_error::Interpreter( - InterpreterError::Unchecked(check_error), + ClarityRuntimeTxError::Rejectable(ClarityError::Interpreter( + VmExecutionError::Unchecked(check_error), )) } else { ClarityRuntimeTxError::AnalysisError(check_error) } } - clarity_error::AbortedByCallback { + ClarityError::AbortedByCallback { output, assets_modified, tx_events, @@ -407,7 +405,7 @@ pub fn handle_clarity_runtime_error(error: clarity_error) -> ClarityRuntimeTxErr tx_events, reason, }, - clarity_error::CostError(cost, budget) => ClarityRuntimeTxError::CostError(cost, budget), + ClarityError::CostError(cost, budget) => ClarityRuntimeTxError::CostError(cost, budget), unhandled_error => ClarityRuntimeTxError::Rejectable(unhandled_error), } } @@ -632,7 +630,7 @@ impl StacksChainState { origin_account: &StacksAccount, asset_map: &AssetMap, txid: Txid, - ) -> Result, InterpreterError> { + ) -> Result, VmExecutionError> { let mut checked_fungible_assets: HashMap> = HashMap::new(); let mut checked_nonfungible_assets: HashMap< @@ -961,7 +959,7 @@ impl StacksChainState { env.add_memory(u64::from( TypeSignature::PrincipalType .size() - .map_err(InterpreterError::from)?, + .map_err(VmExecutionError::from)?, )) .map_err(|e| Error::from_cost_error(e, cost_before.clone(), env.global_context))?; @@ -1210,8 +1208,8 @@ impl StacksChainState { "function_name" => %contract_call.function_name, "function_args" => %VecDisplay(&contract_call.function_args), "error" => %check_error); - return Err(Error::ClarityError(clarity_error::Interpreter( - InterpreterError::Unchecked(check_error), + return Err(Error::ClarityError(ClarityError::Interpreter( + VmExecutionError::Unchecked(check_error), ))); } } @@ -1279,7 +1277,7 @@ impl StacksChainState { Ok(x) => x, Err(e) => { match e { - clarity_error::CostError(ref cost_after, ref budget) => { + ClarityError::CostError(ref cost_after, ref budget) => { warn!("Block compute budget exceeded on {}: cost before={}, after={}, budget={}", tx.txid(), &cost_before, cost_after, budget); return Err(Error::CostOverflowError( cost_before, @@ -1288,13 +1286,13 @@ impl StacksChainState { )); } other_error => { - if let clarity_error::Parse(err) = &other_error { + if let ClarityError::Parse(err) = &other_error { if err.rejectable() { info!("Transaction {} is problematic and should have prevented this block from being relayed", tx.txid()); return Err(Error::ClarityError(other_error)); } } - if let clarity_error::Analysis(err) = &other_error { + if let ClarityError::StaticCheck(err) = &other_error { if err.err.rejectable() { info!("Transaction {} is problematic and should have prevented this block from being relayed", tx.txid()); return Err(Error::ClarityError(other_error)); @@ -1434,8 +1432,8 @@ impl StacksChainState { "txid" => %tx.txid(), "contract" => %contract_id, "error" => %check_error); - return Err(Error::ClarityError(clarity_error::Interpreter( - InterpreterError::Unchecked(check_error), + return Err(Error::ClarityError(ClarityError::Interpreter( + VmExecutionError::Unchecked(check_error), ))); } } @@ -1552,6 +1550,20 @@ impl StacksChainState { tx: &StacksTransaction, quiet: bool, max_execution_time: Option, + ) -> Result<(u64, StacksTransactionReceipt), Error> { + Self::process_transaction_with_check(clarity_block, tx, quiet, max_execution_time, |_| { + Ok(()) + }) + } + + pub fn process_transaction_with_check< + F: FnMut(&StacksTransactionReceipt) -> Result<(), Error>, + >( + clarity_block: &mut ClarityTx, + tx: &StacksTransaction, + quiet: bool, + max_execution_time: Option, + mut check: F, ) -> Result<(u64, StacksTransactionReceipt), Error> { debug!("Process transaction {} ({})", tx.txid(), tx.payload.name()); let epoch = clarity_block.get_epoch(); @@ -1641,6 +1653,8 @@ impl StacksChainState { tx_receipt }; + check(&tx_receipt)?; + transaction .commit() .map_err(|e| Error::InvalidStacksTransaction(e.to_string(), false))?; @@ -8277,7 +8291,7 @@ pub mod test { None, ) .unwrap_err(); - let Error::ClarityError(clarity_error::BadTransaction(msg)) = &err else { + let Error::ClarityError(ClarityError::BadTransaction(msg)) = &err else { panic!("Unexpected error type"); }; assert!(msg.find("never seen in this fork").is_some()); @@ -9509,7 +9523,7 @@ pub mod test { false, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( _check_error, ))) = err { @@ -9562,7 +9576,7 @@ pub mod test { false, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( _check_error, ))) = err { @@ -9613,7 +9627,7 @@ pub mod test { false, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( _check_error, ))) = err { @@ -9665,7 +9679,7 @@ pub mod test { false, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( _check_error, ))) = err { @@ -10169,7 +10183,7 @@ pub mod test { false, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( check_error, ))) = err { @@ -10628,7 +10642,7 @@ pub mod test { false, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( check_error, ))) = err { @@ -10734,7 +10748,7 @@ pub mod test { false, ) .unwrap_err(); - if let Error::ClarityError(clarity_error::Interpreter(InterpreterError::Unchecked( + if let Error::ClarityError(ClarityError::Interpreter(VmExecutionError::Unchecked( check_error, ))) = err { diff --git a/stackslib/src/chainstate/stacks/events.rs b/stackslib/src/chainstate/stacks/events.rs index a1d62930cc8..8e599b1ff52 100644 --- a/stackslib/src/chainstate/stacks/events.rs +++ b/stackslib/src/chainstate/stacks/events.rs @@ -52,7 +52,7 @@ pub struct StacksTransactionReceipt { pub execution_cost: ExecutionCost, pub microblock_header: Option, pub tx_index: u32, - /// This is really a string-formatted CheckError (which can't be clone()'ed), + /// This is really a string-formatted CheckErrorKind or VmExecutionError (which can't be clone()'ed), /// and is not consensus critical. pub vm_error: Option, } @@ -65,6 +65,19 @@ pub struct StacksBlockEventData { pub parent_microblock_sequence: u16, } +impl StacksTransactionReceipt { + pub fn size(&self) -> Option { + let mut out = 0u64; + for event in self.events.iter() { + if let StacksTransactionEvent::SmartContractEvent(event) = event { + out = out.saturating_add(event.value.size().ok()?.into()); + } + } + out = out.saturating_add(self.result.size().ok()?.into()); + Some(out) + } +} + impl From for StacksBlockEventData { fn from(block: StacksBlock) -> StacksBlockEventData { StacksBlockEventData { diff --git a/stackslib/src/chainstate/stacks/miner.rs b/stackslib/src/chainstate/stacks/miner.rs index 32dcc496fd3..cf4ba427189 100644 --- a/stackslib/src/chainstate/stacks/miner.rs +++ b/stackslib/src/chainstate/stacks/miner.rs @@ -22,9 +22,9 @@ use std::sync::{Arc, Mutex}; use std::thread::ThreadId; use std::time::Instant; -use clarity::vm::ast::errors::ParseErrors; +use clarity::vm::ast::errors::ParseErrorKind; use clarity::vm::database::BurnStateDB; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::VmExecutionError; use serde::Deserialize; use stacks_common::codec::StacksMessageCodec; use stacks_common::types::chainstate::{ @@ -50,7 +50,8 @@ use crate::chainstate::stacks::db::unconfirmed::UnconfirmedState; use crate::chainstate::stacks::db::{ChainstateTx, ClarityTx, StacksChainState}; use crate::chainstate::stacks::events::StacksTransactionReceipt; use crate::chainstate::stacks::{Error, StacksBlockHeader, StacksMicroblockHeader, *}; -use crate::clarity_vm::clarity::{ClarityInstance, Error as clarity_error}; +use crate::clarity_vm::clarity::{ClarityError, ClarityInstance}; +use crate::config::DEFAULT_MAX_TENURE_BYTES; use crate::core::mempool::*; use crate::core::*; use crate::monitoring::{ @@ -242,6 +243,7 @@ pub struct BlockBuilderSettings { /// Should the builder attempt to confirm any parent microblocks pub confirm_microblocks: bool, pub max_execution_time: Option, + pub max_tenure_bytes: u64, } impl BlockBuilderSettings { @@ -254,6 +256,7 @@ impl BlockBuilderSettings { miner_status: Arc::new(Mutex::new(MinerStatus::make_ready(0))), confirm_microblocks: true, max_execution_time: None, + max_tenure_bytes: u64::from(DEFAULT_MAX_TENURE_BYTES), } } @@ -266,6 +269,7 @@ impl BlockBuilderSettings { miner_status: Arc::new(Mutex::new(MinerStatus::make_ready(0))), confirm_microblocks: true, max_execution_time: None, + max_tenure_bytes: u64::from(DEFAULT_MAX_TENURE_BYTES), } } } @@ -655,11 +659,11 @@ impl TransactionResult { } // recover original ClarityError ClarityRuntimeTxError::Acceptable { error, .. } => { - if let clarity_error::Parse(ref parse_err) = error { + if let ClarityError::Parse(ref parse_err) = error { info!("Parse error: {}", parse_err; "txid" => %tx.txid()); match *parse_err.err { - ParseErrors::ExpressionStackDepthTooDeep - | ParseErrors::VaryExpressionStackDepthTooDeep => { + ParseErrorKind::ExpressionStackDepthTooDeep + | ParseErrorKind::VaryExpressionStackDepthTooDeep => { info!("Problematic transaction failed AST depth check"; "txid" => %tx.txid()); return (true, Error::ClarityError(error)); } @@ -669,11 +673,11 @@ impl TransactionResult { Error::ClarityError(error) } ClarityRuntimeTxError::CostError(cost, budget) => { - Error::ClarityError(clarity_error::CostError(cost, budget)) + Error::ClarityError(ClarityError::CostError(cost, budget)) } ClarityRuntimeTxError::AnalysisError(e) => { - let clarity_err = Error::ClarityError(clarity_error::Interpreter( - InterpreterError::Unchecked(e), + let clarity_err = Error::ClarityError(ClarityError::Interpreter( + VmExecutionError::Unchecked(e), )); if epoch_id < StacksEpochId::Epoch21 { // this would invalidate the block, so it's problematic @@ -688,7 +692,7 @@ impl TransactionResult { assets_modified, tx_events, reason, - } => Error::ClarityError(clarity_error::AbortedByCallback { + } => Error::ClarityError(ClarityError::AbortedByCallback { output: output.map(Box::new), assets_modified: Box::new(assets_modified), tx_events, @@ -723,6 +727,7 @@ pub trait BlockBuilder { tx_len: u64, limit_behavior: &BlockLimitFunction, max_execution_time: Option, + total_receipts_size: &mut u64, ) -> TransactionResult; /// Append a transaction if doing so won't exceed the epoch data size. @@ -732,6 +737,7 @@ pub trait BlockBuilder { clarity_tx: &mut ClarityTx, tx: &StacksTransaction, max_execution_time: Option, + total_receipts_size: &mut u64, ) -> Result { let tx_len = tx.tx_len(); match self.try_mine_tx_with_len( @@ -740,6 +746,7 @@ pub trait BlockBuilder { tx_len, &BlockLimitFunction::NO_LIMIT_HIT, max_execution_time, + total_receipts_size, ) { TransactionResult::Success(s) => Ok(TransactionResult::Success(s)), TransactionResult::Skipped(TransactionSkipped { error, .. }) @@ -1536,6 +1543,7 @@ impl StacksBlockBuilder { burn_header_height: genesis_burn_header_height, anchored_block_size: 0, burn_view: None, + total_tenure_size: 0, }; let mut builder = StacksBlockBuilder::from_parent_pubkey_hash( @@ -2038,7 +2046,7 @@ impl StacksBlockBuilder { let mut miner_epoch_info = builder.pre_epoch_begin(&mut chainstate, burn_dbconn, true)?; let (mut epoch_tx, _) = builder.epoch_begin(burn_dbconn, &mut miner_epoch_info)?; for tx in txs.into_iter() { - match builder.try_mine_tx(&mut epoch_tx, &tx, None) { + match builder.try_mine_tx(&mut epoch_tx, &tx, None, &mut 0) { Ok(_) => { debug!("Included {}", &tx.txid()); } @@ -2197,10 +2205,17 @@ impl StacksBlockBuilder { ) -> Result<(bool, Vec), Error> { let mut tx_events = Vec::new(); + let mut receipts_total = 0; + for initial_tx in initial_txs.iter() { tx_events.push( builder - .try_mine_tx(epoch_tx, initial_tx, settings.max_execution_time)? + .try_mine_tx( + epoch_tx, + initial_tx, + settings.max_execution_time, + &mut receipts_total, + )? .convert_to_event(), ); } @@ -2233,6 +2248,7 @@ impl StacksBlockBuilder { tip_height, settings, event_observer, + receipts_total, ) } else { info!("Miner: constructing block with replay transactions"); @@ -2241,6 +2257,7 @@ impl StacksBlockBuilder { builder, tip_height, replay_transactions, + receipts_total, ); Ok((txs, false)) }; @@ -2404,6 +2421,7 @@ impl BlockBuilder for StacksBlockBuilder { tx_len: u64, limit_behavior: &BlockLimitFunction, _max_execution_time: Option, + _total_receipt_size: &mut u64, ) -> TransactionResult { if self.bytes_so_far + tx_len >= u64::from(MAX_EPOCH_SIZE) { return TransactionResult::skipped_due_to_error(tx, Error::BlockTooBigError); @@ -2542,6 +2560,7 @@ fn select_and_apply_transactions_from_mempool( tip_height: u64, settings: BlockBuilderSettings, event_observer: Option<&dyn MemPoolEventDispatcher>, + initial_receipts_total: u64, ) -> Result<(Vec, bool), Error> { let mut tx_events = vec![]; let max_miner_time_ms = settings.max_miner_time_ms; @@ -2566,6 +2585,8 @@ fn select_and_apply_transactions_from_mempool( debug!("Block transaction selection begins (parent height = {tip_height})"); let mut loop_result: Result<(), Error> = Ok(()); + + let mut receipts_total = initial_receipts_total; while block_limit_hit != BlockLimitFunction::LIMIT_REACHED { let mut num_considered = 0; @@ -2651,6 +2672,7 @@ fn select_and_apply_transactions_from_mempool( txinfo.metadata.len, &block_limit_hit, settings.max_execution_time, + &mut receipts_total, ); let result_event = tx_result.convert_to_event(); @@ -2802,6 +2824,7 @@ fn select_and_apply_transactions_from_vec( builder: &mut B, tip_height: u64, replay_transactions: &[StacksTransaction], + initial_receipts_total: u64, ) -> Vec { let mut tx_events = vec![]; @@ -2809,6 +2832,7 @@ fn select_and_apply_transactions_from_vec( let mut num_considered = 0; debug!("Replay block transaction selection begins (parent height = {tip_height})"); + let mut receipts_total = initial_receipts_total; for replay_tx in replay_transactions { fault_injection_stall_tx(); if fault_injection_should_skip_replay_tx(replay_tx.txid()) { @@ -2822,6 +2846,7 @@ fn select_and_apply_transactions_from_vec( replay_tx.tx_len(), &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut receipts_total, ); let tx_event = tx_result.convert_to_event(); match tx_result { diff --git a/stackslib/src/chainstate/stacks/mod.rs b/stackslib/src/chainstate/stacks/mod.rs index f5072f36d50..1d86ab3c268 100644 --- a/stackslib/src/chainstate/stacks/mod.rs +++ b/stackslib/src/chainstate/stacks/mod.rs @@ -14,12 +14,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use std::fmt::Display; use std::hash::Hash; use std::{error, fmt, io}; use clarity::vm::contexts::GlobalContext; use clarity::vm::costs::{CostErrors, ExecutionCost}; -use clarity::vm::errors::Error as clarity_interpreter_error; +use clarity::vm::errors::VmExecutionError; use clarity::vm::representations::{ClarityName, ContractName}; use clarity::vm::types::{ PrincipalData, QualifiedContractIdentifier, StandardPrincipalData, Value, @@ -43,7 +44,7 @@ use crate::chainstate::burn::ConsensusHash; use crate::chainstate::stacks::db::accounts::MinerReward; use crate::chainstate::stacks::db::{MinerRewardInfo, StacksHeaderInfo}; use crate::chainstate::stacks::index::Error as marf_error; -use crate::clarity_vm::clarity::Error as clarity_error; +use crate::clarity_vm::clarity::ClarityError; use crate::net::Error as net_error; use crate::util_lib::db::Error as db_error; use crate::util_lib::strings::StacksString; @@ -99,7 +100,7 @@ pub enum Error { MicroblockStreamTooLongError, IncompatibleSpendingConditionError, CostOverflowError(ExecutionCost, ExecutionCost, ExecutionCost), - ClarityError(clarity_error), + ClarityError(ClarityError), DBError(db_error), NetError(net_error), CodecError(codec_error), @@ -120,6 +121,7 @@ pub enum Error { /// This error indicates a Epoch2 block attempted to build off of a Nakamoto block. InvalidChildOfNakomotoBlock, NoRegisteredSigners(u64), + TenureTooBigError, } impl From for Error { @@ -128,8 +130,8 @@ impl From for Error { } } -impl From for Error { - fn from(e: clarity_error) -> Error { +impl From for Error { + fn from(e: ClarityError) -> Error { Error::ClarityError(e) } } @@ -222,6 +224,7 @@ impl fmt::Display for Error { Error::NotInSameFork => { write!(f, "The supplied block identifiers are not in the same fork") } + Error::TenureTooBigError => write!(f, "Too much data in tenure"), } } } @@ -268,6 +271,7 @@ impl error::Error for Error { Error::ExpectedTenureChange => None, Error::NoRegisteredSigners(_) => None, Error::NotInSameFork => None, + Error::TenureTooBigError => None, } } } @@ -314,6 +318,7 @@ impl Error { Error::ExpectedTenureChange => "ExpectedTenureChange", Error::NoRegisteredSigners(_) => "NoRegisteredSigners", Error::NotInSameFork => "NotInSameFork", + Error::TenureTooBigError => "TenureTooBigError", } } @@ -342,9 +347,9 @@ impl From for Error { } } -impl From for Error { - fn from(e: clarity_interpreter_error) -> Error { - Error::ClarityError(clarity_error::Interpreter(e)) +impl From for Error { + fn from(e: VmExecutionError) -> Error { + Error::ClarityError(ClarityError::Interpreter(e)) } } @@ -705,6 +710,21 @@ pub enum TenureChangeCause { ExtendedWriteLength = 6, } +impl Display for TenureChangeCause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let name = match self { + TenureChangeCause::BlockFound => "BlockFound", + TenureChangeCause::Extended => "Extend", + TenureChangeCause::ExtendedRuntime => "ExtendRuntime", + TenureChangeCause::ExtendedReadCount => "ExtendReadCount", + TenureChangeCause::ExtendedReadLength => "ExtendReadLength", + TenureChangeCause::ExtendedWriteCount => "ExtendWriteCount", + TenureChangeCause::ExtendedWriteLength => "ExtendWriteLength", + }; + name.fmt(f) + } +} + impl TryFrom for TenureChangeCause { type Error = (); @@ -770,6 +790,26 @@ impl TenureChangeCause { (_, _) => false, } } + + pub fn is_full_extend(&self) -> bool { + matches!(self, TenureChangeCause::Extended) + } + + pub fn is_read_count_extend(&self) -> bool { + matches!(self, TenureChangeCause::ExtendedReadCount) + } + + pub fn is_extended(&self) -> bool { + match self { + TenureChangeCause::BlockFound => false, + TenureChangeCause::Extended => true, + TenureChangeCause::ExtendedRuntime => true, + TenureChangeCause::ExtendedReadCount => true, + TenureChangeCause::ExtendedReadLength => true, + TenureChangeCause::ExtendedWriteCount => true, + TenureChangeCause::ExtendedWriteLength => true, + } + } } /// Reasons why a `TenureChange` transaction can be bad @@ -823,6 +863,22 @@ impl TenureChangePayload { pubkey_hash: self.pubkey_hash.clone(), } } + + pub fn extend_with_cause( + &self, + burn_view_consensus_hash: ConsensusHash, + last_tenure_block_id: StacksBlockId, + num_blocks_so_far: u32, + cause: TenureChangeCause, + ) -> Self { + let mut ext = self.extend( + burn_view_consensus_hash, + last_tenure_block_id, + num_blocks_so_far, + ); + ext.cause = cause; + ext + } } /// NB This explicit implementation is needed because PartialEq is deliberately _not_ implemented diff --git a/stackslib/src/chainstate/stacks/tests/block_construction.rs b/stackslib/src/chainstate/stacks/tests/block_construction.rs index fb7434d78a4..d1a17b7c39f 100644 --- a/stackslib/src/chainstate/stacks/tests/block_construction.rs +++ b/stackslib/src/chainstate/stacks/tests/block_construction.rs @@ -3992,7 +3992,7 @@ fn test_is_tx_problematic() { expected_txids.push(contract_call_spends_too_much_tx.txid()); // for tenure_id == 4: - // make a contract that, when called, will result in a CheckError at + // make a contract that, when called, will result in a CheckErrorKind at // runtime let runtime_checkerror_trait = " diff --git a/stackslib/src/chainstate/stacks/tests/chain_histories.rs b/stackslib/src/chainstate/stacks/tests/chain_histories.rs index e0f593aba27..7abd6f7d2dd 100644 --- a/stackslib/src/chainstate/stacks/tests/chain_histories.rs +++ b/stackslib/src/chainstate/stacks/tests/chain_histories.rs @@ -2695,7 +2695,7 @@ pub fn mine_empty_anchored_block( let tx_coinbase_signed = make_coinbase(miner, burnchain_height); builder - .try_mine_tx(clarity_tx, &tx_coinbase_signed, None) + .try_mine_tx(clarity_tx, &tx_coinbase_signed, None, &mut 0) .unwrap(); let stacks_block = builder.mine_anchored_block(clarity_tx); @@ -2730,7 +2730,7 @@ pub fn mine_empty_anchored_block_with_burn_height_pubkh( let tx_coinbase_signed = make_coinbase(miner, burnchain_height); builder - .try_mine_tx(clarity_tx, &tx_coinbase_signed, None) + .try_mine_tx(clarity_tx, &tx_coinbase_signed, None, &mut 0) .unwrap(); let stacks_block = builder.mine_anchored_block(clarity_tx); @@ -2765,7 +2765,7 @@ pub fn mine_empty_anchored_block_with_stacks_height_pubkh( let tx_coinbase_signed = make_coinbase(miner, burnchain_height); builder - .try_mine_tx(clarity_tx, &tx_coinbase_signed, None) + .try_mine_tx(clarity_tx, &tx_coinbase_signed, None, &mut 0) .unwrap(); let stacks_block = builder.mine_anchored_block(clarity_tx); @@ -2796,7 +2796,7 @@ pub fn mine_invalid_token_transfers_block( // make a coinbase for this miner let tx_coinbase_signed = make_coinbase(miner, burnchain_height); builder - .try_mine_tx(clarity_tx, &tx_coinbase_signed, None) + .try_mine_tx(clarity_tx, &tx_coinbase_signed, None, &mut 0) .unwrap(); let recipient = @@ -2870,7 +2870,7 @@ pub fn mine_smart_contract_contract_call_block( // make a coinbase for this miner let tx_coinbase_signed = make_coinbase(miner, burnchain_height); builder - .try_mine_tx(clarity_tx, &tx_coinbase_signed, None) + .try_mine_tx(clarity_tx, &tx_coinbase_signed, None, &mut 0) .unwrap(); // make a smart contract @@ -2880,7 +2880,7 @@ pub fn mine_smart_contract_contract_call_block( builder.header.total_work.work as usize, ); builder - .try_mine_tx(clarity_tx, &tx_contract_signed, None) + .try_mine_tx(clarity_tx, &tx_contract_signed, None, &mut 0) .unwrap(); // make a contract call @@ -2892,7 +2892,7 @@ pub fn mine_smart_contract_contract_call_block( 2, ); builder - .try_mine_tx(clarity_tx, &tx_contract_call_signed, None) + .try_mine_tx(clarity_tx, &tx_contract_call_signed, None, &mut 0) .unwrap(); let stacks_block = builder.mine_anchored_block(clarity_tx); @@ -2947,7 +2947,7 @@ pub fn mine_smart_contract_block_contract_call_microblock( // make a coinbase for this miner let tx_coinbase_signed = make_coinbase(miner, burnchain_height); builder - .try_mine_tx(clarity_tx, &tx_coinbase_signed, None) + .try_mine_tx(clarity_tx, &tx_coinbase_signed, None, &mut 0) .unwrap(); // make a smart contract @@ -2957,7 +2957,7 @@ pub fn mine_smart_contract_block_contract_call_microblock( builder.header.total_work.work as usize, ); builder - .try_mine_tx(clarity_tx, &tx_contract_signed, None) + .try_mine_tx(clarity_tx, &tx_contract_signed, None, &mut 0) .unwrap(); let stacks_block = builder.mine_anchored_block(clarity_tx); @@ -3034,7 +3034,7 @@ pub fn mine_smart_contract_block_contract_call_microblock_exception( // make a coinbase for this miner let tx_coinbase_signed = make_coinbase(miner, burnchain_height); builder - .try_mine_tx(clarity_tx, &tx_coinbase_signed, None) + .try_mine_tx(clarity_tx, &tx_coinbase_signed, None, &mut 0) .unwrap(); // make a smart contract @@ -3044,7 +3044,7 @@ pub fn mine_smart_contract_block_contract_call_microblock_exception( builder.header.total_work.work as usize, ); builder - .try_mine_tx(clarity_tx, &tx_contract_signed, None) + .try_mine_tx(clarity_tx, &tx_contract_signed, None, &mut 0) .unwrap(); let stacks_block = builder.mine_anchored_block(clarity_tx); diff --git a/stackslib/src/chainstate/tests/consensus.rs b/stackslib/src/chainstate/tests/consensus.rs index 55cc74d53cc..a556dd25691 100644 --- a/stackslib/src/chainstate/tests/consensus.rs +++ b/stackslib/src/chainstate/tests/consensus.rs @@ -17,45 +17,42 @@ use std::sync::LazyLock; use clarity::boot_util::boot_code_addr; use clarity::codec::StacksMessageCodec; -use clarity::consts::{ - CHAIN_ID_TESTNET, 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, -}; +use clarity::consts::{CHAIN_ID_TESTNET, STACKS_EPOCH_MAX}; use clarity::types::chainstate::{StacksAddress, StacksPrivateKey, StacksPublicKey, TrieHash}; -use clarity::types::{StacksEpoch, StacksEpochId}; -use clarity::util::hash::{MerkleTree, Sha512Trunc256Sum}; +use clarity::types::{EpochList, StacksEpoch, StacksEpochId}; +use clarity::util::hash::{Hash160, MerkleTree, Sha512Trunc256Sum}; use clarity::util::secp256k1::MessageSignature; -use clarity::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; use clarity::vm::costs::ExecutionCost; -use clarity::vm::types::PrincipalData; -use clarity::vm::{ClarityVersion, Value as ClarityValue, MAX_CALL_STACK_DEPTH}; +use clarity::vm::types::{PrincipalData, ResponseData}; +use clarity::vm::{ClarityVersion, Value as ClarityValue}; use serde::{Deserialize, Serialize, Serializer}; use stacks_common::bitvec::BitVec; +use crate::burnchains::tests::TestBurnchainBlock; use crate::burnchains::PoxConstants; use crate::chainstate::burn::db::sortdb::SortitionDB; +use crate::chainstate::burn::operations::BlockstackOperationType; use crate::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader, NakamotoChainState}; use crate::chainstate::stacks::db::{ClarityTx, StacksChainState, StacksEpochReceipt}; use crate::chainstate::stacks::events::TransactionOrigin; -use crate::chainstate::stacks::tests::TestStacksNode; +use crate::chainstate::stacks::miner::BlockBuilder; +use crate::chainstate::stacks::tests::{make_coinbase, TestStacksNode}; use crate::chainstate::stacks::{ - Error as ChainstateError, StacksTransaction, TenureChangeCause, TransactionContractCall, - TransactionPayload, TransactionSmartContract, MINER_BLOCK_CONSENSUS_HASH, - MINER_BLOCK_HEADER_HASH, + Error as ChainstateError, StacksBlock, StacksBlockBuilder, StacksTransaction, + TransactionContractCall, TransactionPayload, TransactionSmartContract, + MINER_BLOCK_CONSENSUS_HASH, MINER_BLOCK_HEADER_HASH, }; use crate::chainstate::tests::TestChainstate; use crate::core::test_util::{ make_contract_call, make_contract_publish_versioned, make_stacks_transfer_tx, to_addr, }; -use crate::core::{EpochList, BLOCK_LIMIT_MAINNET_21}; +use crate::core::BLOCK_LIMIT_MAINNET_21; 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. -const EPOCHS_TO_TEST: &[StacksEpochId] = &[StacksEpochId::Epoch32, StacksEpochId::Epoch33]; +pub const EPOCHS_TO_TEST: &[StacksEpochId] = &[StacksEpochId::Epoch33]; pub const SK_1: &str = "a1289f6438855da7decf9b61b852c882c398cff1446b2a0f823538aa2ebef92e01"; pub const SK_2: &str = "4ce9a8f7539ea93753a36405b16e8b57e15a552430410709c2b6d65dca5c02e201"; @@ -67,11 +64,14 @@ pub static FAUCET_PRIV_KEY: LazyLock = LazyLock::new(|| { .expect("Failed to parse private key") }); +// The address for the faucet account +pub static FAUCET_ADDRESS: LazyLock = LazyLock::new(|| to_addr(&FAUCET_PRIV_KEY)); + const FOO_CONTRACT: &str = "(define-public (foo) (ok 1)) (define-public (bar (x uint)) (ok x))"; /// Returns the list of Clarity versions that can be used to deploy contracts in the given epoch. -const fn clarity_versions_for_epoch(epoch: StacksEpochId) -> &'static [ClarityVersion] { +pub const fn clarity_versions_for_epoch(epoch: StacksEpochId) -> &'static [ClarityVersion] { match epoch { StacksEpochId::Epoch10 => &[], StacksEpochId::Epoch20 | StacksEpochId::Epoch2_05 => &[ClarityVersion::Clarity1], @@ -94,275 +94,1293 @@ const fn clarity_versions_for_epoch(epoch: StacksEpochId) -> &'static [ClarityVe } } -/// A high-level test harness for running consensus-critical smart contract tests. -/// -/// This struct combines a [`ConsensusTest`] instance for chainstate management and a -/// [`TestTxFactory`] for transaction generation. It provides convenience methods to -/// automate test scenarios involving contract deployments and calls across multiple -/// epochs and Clarity versions. -struct ContractConsensusTest<'a> { - tx_factory: TestTxFactory, - consensus_test: ConsensusTest<'a>, +/// Custom serializer for `Option` to improve snapshot readability. +/// This avoids large diffs in snapshots due to code body changes and focuses on key fields. +fn serialize_opt_tx_payload( + value: &Option, + serializer: S, +) -> Result +where + S: Serializer, +{ + let changed = match value { + None => "BitcoinTx".to_string(), + Some(TransactionPayload::TokenTransfer(sender, amount, memo)) => { + format!("TokenTransfer(from: {sender}, amount: {amount}, memo: {memo})") + } + Some(TransactionPayload::SmartContract( + TransactionSmartContract { name, code_body }, + clarity_version, + )) => { + format!("SmartContract(name: {name}, code_body: [..], clarity_version: {clarity_version:?})") + } + Some(TransactionPayload::ContractCall(TransactionContractCall { + address, + contract_name, + function_name, + function_args, + })) => { + format!("ContractCall(address: {address}, contract_name: {contract_name}, function_name: {function_name}, function_args: [{function_args:?}])") + } + Some(payload) => { + format!("{payload:?}") + } + }; + serializer.serialize_str(&changed) } -impl ContractConsensusTest<'_> { - /// Creates a new `ContractConsensusTest`. - pub fn new(test_name: &str) -> Self { - Self { - tx_factory: TestTxFactory::new(CHAIN_ID_TESTNET), - consensus_test: ConsensusTest::new(test_name, vec![]), - } - } +/// Serialize an optional string field appending a non-consensus breaking info message. +fn serialize_opt_string_ncb(value: &Option, serializer: S) -> Result +where + S: Serializer, +{ + let original = match value.as_deref() { + Some(str) => format!("Some({str})"), + None => "None".to_string(), + }; + let changed = format!("{original} [NON-CONSENSUS BREAKING]"); + serializer.serialize_str(&changed) +} - /// Generates and executes the given transaction in a new block. - /// Increases the nonce if the transaction succeeds. - fn append_tx_block(&mut self, tx_spec: &TestTxSpec) -> ExpectedResult { - let tx = self.tx_factory.generate_tx(tx_spec); - let block = TestBlock { - transactions: vec![tx], - }; +/// Represents the expected output of a transaction in a test. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct ExpectedTransactionOutput { + /// The transaction that was executed. + /// `None` for bitcoin transactions. + #[serde(serialize_with = "serialize_opt_tx_payload")] + pub tx: Option, + /// The possible Clarity VM error message associated to the transaction (non-consensus breaking) + #[serde(serialize_with = "serialize_opt_string_ncb")] + pub vm_error: Option, + /// The expected return value of the transaction. + pub return_type: ClarityValue, + /// The expected execution cost of the transaction. + pub cost: ExecutionCost, +} - let result = self.consensus_test.append_block(block); +/// Represents the expected outputs for a block's execution. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct ExpectedBlockOutput { + /// The expected block marf + pub marf_hash: TrieHash, + /// The epoch in which the test block was expected to be evaluated + pub evaluated_epoch: StacksEpochId, + /// The expected outputs for each transaction, in input order. + pub transactions: Vec, + /// The total execution cost of the block. + pub total_block_cost: ExecutionCost, +} - if let ExpectedResult::Success(_) = result { - self.tx_factory.increase_nonce_for_tx(tx_spec); - } +/// Represents the expected outputs for a block's failed execution. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct ExpectedFailureOutput { + /// The epoch in which the test block was expected to be evaluated + pub evaluated_epoch: StacksEpochId, + /// The test should fail with an error matching the specified string + /// Cannot match on the exact Error directly as they do not implement + /// Serialize/Deserialize or PartialEq + pub error: String, +} - result +/// Represents the expected result of a consensus test. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub enum ExpectedResult { + /// The test should succeed with the specified outputs. + Success(ExpectedBlockOutput), + /// The test should fail with the specified outputs. + Failure(ExpectedFailureOutput), +} + +impl ExpectedResult { + fn create_from( + result: Result, + marf_hash: TrieHash, + evaluated_epoch: StacksEpochId, + ) -> Self { + match result { + Ok(epoch_receipt) => { + let transactions: Vec = epoch_receipt + .tx_receipts + .into_iter() + .map(|r| { + let tx = match r.transaction { + TransactionOrigin::Stacks(tx) => Some(tx.payload), + TransactionOrigin::Burn(..) => None, + }; + ExpectedTransactionOutput { + tx, + return_type: r.result, + cost: r.execution_cost, + vm_error: r.vm_error, + } + }) + .collect(); + ExpectedResult::Success(ExpectedBlockOutput { + marf_hash, + evaluated_epoch: epoch_receipt.evaluated_epoch, + transactions, + total_block_cost: epoch_receipt.anchored_block_cost, + }) + } + Err(e) => ExpectedResult::Failure(ExpectedFailureOutput { + error: e.to_string(), + evaluated_epoch, + }), + } } +} + +/// Represents a block to be appended in a test and its expected result. +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct TestBlock { + /// Transactions to include in the block + pub transactions: Vec, +} - /// Executes a consensus test for a contract function across multiple Stacks epochs. +/// Manages a `TestChainstate` tailored for consensus-rule verification. +/// +/// Initialises the chain with enough burn-chain blocks per epoch to run +/// the requested number of Stacks blocks per epoch. +/// +/// Provides high-level helpers for: +/// - Appending Nakamoto or pre-Nakamoto blocks +pub struct ConsensusChain<'a> { + pub test_chainstate: TestChainstate<'a>, +} + +impl ConsensusChain<'_> { + /// Creates a new [`ConsensusChain`]. /// - /// This helper automates deploying a contract and invoking one of its public functions - /// across different epochs and Clarity versions, ensuring consistent consensus behavior. + /// # Arguments + /// + /// * `test_name` – identifier used for logging / snapshot names / database names + /// * `initial_balances` – `(principal, amount)` pairs that receive an initial STX balance + /// * `num_blocks_per_epoch` – how many **Stacks** blocks must fit into each epoch + /// + /// # Panics /// - /// # Behavior + /// * If `Epoch10` is requested (unsupported) + /// * If any requested epoch is given `0` blocks + pub fn new( + test_name: &str, + initial_balances: Vec<(PrincipalData, u64)>, + num_blocks_per_epoch: HashMap, + ) -> Self { + // Validate blocks + for (epoch_id, num_blocks) in &num_blocks_per_epoch { + assert_ne!( + *epoch_id, + StacksEpochId::Epoch10, + "Epoch10 is not supported" + ); + assert!( + *num_blocks > 0, + "Each epoch must have at least one block. {epoch_id} is empty" + ); + } + // Set up chainstate to support Naka. + let mut boot_plan = NakamotoBootPlan::new(test_name) + .with_pox_constants(7, 1) + .with_initial_balances(initial_balances) + .with_private_key(FAUCET_PRIV_KEY.clone()); + let (epochs, first_burnchain_height) = + Self::calculate_epochs(&boot_plan.pox_constants, num_blocks_per_epoch); + boot_plan = boot_plan.with_epochs(epochs); + let test_chainstate = boot_plan.to_chainstate(None, Some(first_burnchain_height)); + Self { test_chainstate } + } + + /// Calculates a valid [`EpochList`] and starting burnchain height for the test harness. /// - /// The function performs two main phases: - /// 1. **Deployment:** Deploys `contract_code` in each epoch listed in `deploy_epochs` for all - /// applicable Clarity versions. - /// 2. **Execution:** Calls `function_name` in each epoch listed in `call_epochs` on every - /// previously deployed contract. + /// The resulting EpochList satisfies the following: + /// - Each epoch has enough burnchain blocks to accommodate all test blocks. + /// - Epoch 2.5 → 3.0 transition satisfies the following constraints: + /// - 2.5 and 3.0 are in **different reward cycles**. + /// - 2.5 starts **before** the prepare phase of the cycle prior to 3.0 activation. + /// - 3.0 does not start on a reward cycle boundary. + /// - All epoch heights are contiguous and correctly ordered. /// - /// ## Example - /// If `deploy_epochs` = `[2.0, 3.0]` and `call_epochs` = `[3.1]`, the following sequence occurs: - /// - Deploy contract in epoch 2.0 with Clarity 1. - /// - Deploy contract in epoch 3.0 with Clarity 1, 2, and 3. - /// - Call the function in epoch 3.1 on all four deployed contracts. + /// The resulting [`EpochList`] is used to initialize the test chainstate with correct + /// epoch boundaries, enabling accurate simulation of epoch transitions and consensus rules. /// /// # Arguments /// - /// * `contract_name` - Base name for the contract. - /// * `contract_code` - Clarity source code of the contract. - /// * `function_name` - Public function to invoke. - /// * `function_args` - Arguments to pass to the function call. - /// * `deploy_epochs` - Epochs during which the contract should be deployed. - /// * `call_epochs` - Epochs during which the function should be executed. + /// * `pox_constants` - PoX configuration (reward cycle length, prepare phase, etc.). + /// * `num_blocks_per_epoch` - Map of epoch IDs to the number of test blocks to run in each. /// /// # Returns /// - /// A `Vec` with the outcome of each block for snapshot testing. + /// `(EpochList, first_burnchain_height)` — the epoch list and the burnchain + /// height at which the first Stacks block is mined. + fn calculate_epochs( + pox_constants: &PoxConstants, + num_blocks_per_epoch: HashMap, + ) -> (EpochList, u64) { + let reward_cycle_length = pox_constants.reward_cycle_length as u64; + let prepare_length = pox_constants.prepare_length as u64; + + // Helper: is this burnchain height in a prepare phase? + let is_in_prepare_phase = |height: u64| -> bool { + let pos_in_cycle = height % reward_cycle_length; + pos_in_cycle == 0 || pos_in_cycle >= (reward_cycle_length - prepare_length) + }; + + // Helper: is this burnchain height at a reward cycle boundary? + let is_reward_cycle_boundary = |height: u64| -> bool { height % reward_cycle_length <= 1 }; + + // Helper: place N blocks starting at `start`, skipping prepare phases (for pre-3.0) + // this is necessary to prevent PoX anchor blocks getting messed with if any pre-naka + // blocks fail to append + let place_blocks_avoiding_prepare = |start: u64, n: u64| -> u64 { + let mut height = start; + let mut blocks_placed = 0; + + while blocks_placed < n { + if is_in_prepare_phase(height) { + height += 1; // skip prepare phase + } else { + blocks_placed += 1; + if blocks_placed < n { + height += 1; // move to next height only if more blocks are needed + } + } + } + + height + }; + + let first_burnchain_height = + (pox_constants.pox_4_activation_height + pox_constants.reward_cycle_length + 1) as u64; + info!("StacksEpoch calculate_epochs first_burn_height = {first_burnchain_height}"); + let mut epochs = vec![]; + let mut current_height = 0; + for epoch_id in StacksEpochId::ALL.iter() { + let start_height = current_height; + let mut end_height = match *epoch_id { + StacksEpochId::Epoch10 => first_burnchain_height, + StacksEpochId::Epoch20 + | StacksEpochId::Epoch2_05 + | StacksEpochId::Epoch21 + | StacksEpochId::Epoch22 + | StacksEpochId::Epoch23 + | StacksEpochId::Epoch24 + | StacksEpochId::Epoch25 => { + // Use test vector block count + // Always add 1 so we can ensure we are fully in the epoch before we then execute + // the corresponding test blocks in their own blocks + 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 => { + // Only need 1 block per Epoch + if num_blocks_per_epoch.contains_key(epoch_id) { + start_height + 1 + } else { + // If we don't care to have any blocks in this epoch + // don't bother giving it an epoch height + start_height + } + } + // The last Epoch height never ends + StacksEpochId::Epoch33 => STACKS_EPOCH_MAX, + }; + + // Special case the Epoch 2.5 -> Epoch 3.0 transition + if *epoch_id == StacksEpochId::Epoch25 { + // Calculate Epoch 2.5 end height and Epoch 3.0 start height. + // Epoch 2.5 must start before the prepare phase of the cycle prior to Epoch 3.0's activation. + // Epoch 2.5 end must equal Epoch 3.0 start + // Epoch 3.0 must not start at a cycle boundary + // Epoch 2.5 and 3.0 cannot be in the same reward cycle. + let num_blocks = num_blocks_per_epoch + .get(epoch_id) + .copied() + .unwrap_or(0) + .saturating_add(1); // Add one block for pox lockups. + + let epoch_25_start = start_height; + let mut epoch_30_start = end_height; // from block placement above + + let epoch_25_reward_cycle = epoch_25_start / reward_cycle_length; + let mut epoch_30_reward_cycle = epoch_30_start / reward_cycle_length; + // Ensure different reward cycles and Epoch 2.5 starts before prior cycle's prepare phase + let mut prior_cycle = epoch_30_reward_cycle.saturating_sub(1); + let mut prior_prepare_phase_start = + prior_cycle * reward_cycle_length + (reward_cycle_length - prepare_length); + while epoch_25_start + num_blocks >= prior_prepare_phase_start + || epoch_25_reward_cycle >= epoch_30_reward_cycle + || is_reward_cycle_boundary(epoch_30_start) + { + // Advance to 3.0 start so it is not in a reward cycle boundary and to ensure + // 2.5 starts prior to the prepare phase of epoch 30 reward cycle activation + epoch_30_start += 1; + epoch_30_reward_cycle = epoch_30_start / reward_cycle_length; + prior_cycle = epoch_30_reward_cycle.saturating_sub(1); + prior_prepare_phase_start = + prior_cycle * reward_cycle_length + (reward_cycle_length - prepare_length); + } + end_height = epoch_30_start; // Epoch 2.5 ends where Epoch 3.0 starts + } + // Create epoch + let block_limit = if *epoch_id == StacksEpochId::Epoch10 { + ExecutionCost::max_value() + } else { + BLOCK_LIMIT_MAINNET_21.clone() + }; + let network_epoch = StacksEpochId::network_epoch(*epoch_id); + epochs.push(StacksEpoch { + epoch_id: *epoch_id, + start_height, + end_height, + block_limit, + network_epoch, + }); + current_height = end_height; + } + // Validate test vector block counts + for (epoch_id, num_blocks) in num_blocks_per_epoch { + let epoch = epochs + .iter() + .find(|e| e.epoch_id == epoch_id) + .expect("Epoch not found"); + let epoch_length = epoch.end_height - epoch.start_height; + if epoch_id > StacksEpochId::Epoch25 { + assert!( + epoch_length > 0, + "{epoch_id:?} must have at least 1 burn block." + ); + } else { + assert!( + epoch_length >= num_blocks, + "{epoch_id:?} must have at least {num_blocks} burn blocks, got {epoch_length}" + ); + } + } + let epoch_list = EpochList::new(&epochs); + info!("Calculated EpochList from pox constants with first burnchain height of {first_burnchain_height}."; + "epochs" => ?epoch_list, + "first_burnchain_height" => first_burnchain_height + ); + (epoch_list, first_burnchain_height) + } + + /// Appends a single block to the chain as a Nakamoto block and returns the result. /// - /// # Panics + /// This method takes a [`TestBlock`] containing a list of transactions, constructs + /// a fully valid [`NakamotoBlock`], processes it against the current chainstate. /// - /// * If `deploy_epochs` is empty. - /// * If any `call_epoch` precedes the earliest `deploy_epoch`. - pub fn run( - &mut self, - contract_name: &str, - contract_code: &str, - function_name: &str, - function_args: &[ClarityValue], - deploy_epochs: &[StacksEpochId], - call_epochs: &[StacksEpochId], - ) -> Vec { - assert!( - !deploy_epochs.is_empty(), - "At least one deploy epoch is required" + /// # Arguments + /// + /// * `block` - The test block to be processed and appended to the chain. + /// + /// # Returns + /// + /// A [`ExpectedResult`] with the outcome of the block processing. + fn append_nakamoto_block(&mut self, block: TestBlock) -> ExpectedResult { + debug!("--------- Running block {block:?} ---------"); + let (nakamoto_block, _block_size) = self.construct_nakamoto_block(block); + let mut sortdb = self.test_chainstate.sortdb.take().unwrap(); + let mut stacks_node = self.test_chainstate.stacks_node.take().unwrap(); + let chain_tip = + NakamotoChainState::get_canonical_block_header(stacks_node.chainstate.db(), &sortdb) + .unwrap() + .unwrap(); + let sig_hash = nakamoto_block.header.signer_signature_hash(); + debug!( + "--------- Processing block {sig_hash} ---------"; + "block" => ?nakamoto_block ); - let min_deploy_epoch = deploy_epochs.iter().min().unwrap(); - assert!( - call_epochs.iter().all(|e| e >= min_deploy_epoch), - "All call epochs must be >= the minimum deploy epoch" + let expected_marf = nakamoto_block.header.state_index_root; + let res = TestStacksNode::process_pushed_next_ready_block( + &mut stacks_node, + &mut sortdb, + &mut self.test_chainstate.miner, + &chain_tip.consensus_hash, + &mut self.test_chainstate.coord, + nakamoto_block.clone(), + ); + debug!( + "--------- Processed block: {sig_hash} ---------"; + "block" => ?nakamoto_block ); + // Restore chainstate for the next block + self.test_chainstate.sortdb = Some(sortdb); + self.test_chainstate.stacks_node = Some(stacks_node); - let all_epochs: BTreeSet = - deploy_epochs.iter().chain(call_epochs).cloned().collect(); + let burn_block_height = self.test_chainstate.get_burn_block_height(); + let current_epoch = + SortitionDB::get_stacks_epoch(self.test_chainstate.sortdb().conn(), burn_block_height) + .unwrap() + .unwrap() + .epoch_id; - let mut contract_names = vec![]; - let sender = &FAUCET_PRIV_KEY; - let contract_addr = to_addr(sender); - // Create epoch blocks by pairing each epoch with its corresponding transactions - let mut results = vec![]; - all_epochs.into_iter().for_each(|epoch| { - self.consensus_test.advance_to_epoch(epoch); - if deploy_epochs.contains(&epoch) { - let clarity_versions = clarity_versions_for_epoch(epoch); - let epoch_name = format!("Epoch{}", epoch.to_string().replace(".", "_")); - clarity_versions.iter().for_each(|version| { - let name = format!( - "{contract_name}-{epoch_name}-{}", - version.to_string().replace(" ", "") - ); - contract_names.push(name.clone()); - let result = self.append_tx_block(&TestTxSpec::ContractDeploy { - sender, - name: &name, - code: contract_code, - clarity_version: Some(*version), - }); - results.push(result); - }); - } - if call_epochs.contains(&epoch) { - contract_names.iter().for_each(|contract_name| { - let result = self.append_tx_block(&TestTxSpec::ContractCall { - sender, - contract_addr: &contract_addr, - contract_name, - function_name, - args: function_args, - }); - results.push(result); - }); - } - }); - results + let remapped_result = res.map(|receipt| receipt.unwrap()); + ExpectedResult::create_from(remapped_result, expected_marf, current_epoch) } -} -/// Generates a consensus test for executing a contract function across multiple Stacks epochs. -/// -/// This macro automates both contract deployment and function invocation across different -/// epochs and Clarity versions. -/// It simplifies the setup of consensus-critical tests involving versioned smart contracts. -/// -/// # Behavior -/// -/// - **Deployment:** Deploys `contract_code` in each epoch specified in `deploy_epochs` -/// for every applicable [`ClarityVersion`]. -/// - **Execution:** Calls `function_name` in each epoch from `call_epochs` on all previously -/// deployed contract instances. -/// - **Structure:** Each deployment and function call is executed in its own block, ensuring -/// clear separation between transactions. -/// -/// # Arguments -/// -/// * `$name` — Name of the generated test function. -/// * `contract_name` — The name of the contract. -/// * `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. -/// * `call_epochs` — *(optional)* Epochs in which to call the function. Defaults to [`EPOCHS_TO_TEST`]. + /// Appends a single block to the chain as a Pre-Nakamoto block and returns the result. + /// + /// This method takes a [`TestBlock`] containing a list of transactions, constructs + /// a fully valid [`StacksBlock`], processes it against the current chainstate. + /// + /// # Arguments + /// + /// * `block` - The test block to be processed and appended to the chain. + /// * `coinbase_nonce` - The coinbase nonce to use and increment + /// + /// # Returns + /// + /// A [`ExpectedResult`] with the outcome of the block processing. + fn append_pre_nakamoto_block(&mut self, block: TestBlock) -> ExpectedResult { + debug!("--------- Running Pre-Nakamoto block {block:?} ---------"); + let (pre_nakamoto_block, burn_ops) = self.construct_pre_nakamoto_block(block); + let (block_height, _, consensus_hash) = self.test_chainstate.next_burnchain_block(burn_ops); + let mut stacks_node = self.test_chainstate.stacks_node.take().unwrap(); + let mut sortdb = self.test_chainstate.sortdb.take().unwrap(); + + debug!( + "--------- Processing Pre-Nakamoto block {} ---------", pre_nakamoto_block.block_hash(); + ); + let expected_marf = pre_nakamoto_block.header.state_index_root; + let res = TestStacksNode::process_pre_nakamoto_next_ready_block( + &mut stacks_node, + &mut sortdb, + &mut self.test_chainstate.miner, + &mut self.test_chainstate.coord, + &pre_nakamoto_block, + &[], + ); + + debug!( + "--------- Processed Pre-Nakamoto block {}---------", pre_nakamoto_block.block_hash(); + ); + + // Restore chainstate for the next block + self.test_chainstate.sortdb = Some(sortdb); + self.test_chainstate.stacks_node = Some(stacks_node); + + let burn_block_height = self.test_chainstate.get_burn_block_height(); + let current_epoch = + SortitionDB::get_stacks_epoch(self.test_chainstate.sortdb().conn(), burn_block_height) + .unwrap() + .unwrap() + .epoch_id; + + let remapped_result = res.map(|receipt| { + let mut receipt = receipt.unwrap(); + let mut sanitized_receipts = vec![]; + for tx_receipt in &receipt.tx_receipts { + // Remove any coinbase transactions from the output + if tx_receipt.is_coinbase_tx() { + continue; + } + sanitized_receipts.push(tx_receipt.clone()); + } + receipt.tx_receipts = sanitized_receipts; + receipt + }); + ExpectedResult::create_from(remapped_result, expected_marf, current_epoch) + } + + /// Appends a single block to the chain and returns the result. + /// + /// This method takes a [`TestBlock`] containing a list of transactions, whether the epoch [`is_naka_epoch`] , + /// constructing a fully valid [`StacksBlock`] or [`NakamotoBlock`] accordingly, processes it against the current chainstate. + /// + /// # Arguments + /// + /// * `block` - The test block to be processed and appended to the chain. + /// * `coinbase_nonce` - The coinbase nonce to use and increment + /// + /// # Returns + /// + /// A [`ExpectedResult`] with the outcome of the block processing. + pub fn append_block(&mut self, block: TestBlock, is_naka_epoch: bool) -> ExpectedResult { + if is_naka_epoch { + self.append_nakamoto_block(block) + } else { + let result = self.append_pre_nakamoto_block(block); + if matches!(result, ExpectedResult::Failure(_)) { + // We didn't successfully mine the coinbase tx. Revert the nonce of the miner. + let old_nonce = self.test_chainstate.miner.get_nonce(); + self.test_chainstate + .miner + .set_nonce(old_nonce.saturating_sub(1)); + } + result + } + } + + /// Constructs a pre-Nakamoto block with the given [`TestBlock`] configuration. + fn construct_pre_nakamoto_block( + &mut self, + test_block: TestBlock, + ) -> (StacksBlock, Vec) { + let microblock_privkey = self.test_chainstate.miner.next_microblock_privkey(); + let microblock_pubkeyhash = + Hash160::from_node_public_key(&StacksPublicKey::from_private(µblock_privkey)); + let burnchain = self.test_chainstate.config.burnchain.clone(); + + let tip = + SortitionDB::get_canonical_burn_chain_tip(self.test_chainstate.sortdb_ref().conn()) + .unwrap(); + let parent_sortition_opt = SortitionDB::get_block_snapshot( + self.test_chainstate.sortdb_ref().conn(), + &tip.parent_sortition_id, + ) + .unwrap(); + + let mut burn_block = TestBurnchainBlock::new(&tip, 0); + + let last_key = self + .test_chainstate + .stacks_node_ref() + .get_last_key(&self.test_chainstate.miner); + let vrf_proof = self + .test_chainstate + .miner + .make_proof( + &last_key.public_key, + &burn_block.parent_snapshot.sortition_hash, + ) + .unwrap_or_else(|| panic!("FATAL: no private key for {:?}", last_key.public_key)); + + let coinbase_tx = make_coinbase( + &mut self.test_chainstate.miner, + tip.block_height.try_into().unwrap(), + ); + let mut stacks_block = { + let genesis_header_info = StacksChainState::get_genesis_header_info( + self.test_chainstate.stacks_node_ref().chainstate.db(), + ) + .unwrap(); + let tip = + SortitionDB::get_canonical_burn_chain_tip(self.test_chainstate.sortdb_ref().conn()) + .unwrap(); + let parent_tip = StacksChainState::get_anchored_block_header_info( + self.test_chainstate.stacks_node_ref().chainstate.db(), + &tip.canonical_stacks_tip_consensus_hash, + &tip.canonical_stacks_tip_hash, + ) + .unwrap() + .unwrap_or(genesis_header_info); + // Just use the block builder to calculate the header easily. Note that the merkle root and state index hash will be wrong though! + let mut builder = StacksBlockBuilder::make_regtest_block_builder( + &burnchain, + &parent_tip, + &vrf_proof, + tip.total_burn, + µblock_pubkeyhash, + ) + .unwrap(); + let burndb = self + .test_chainstate + .sortdb_ref() + .index_handle(&tip.sortition_id); + let (mut chainstate, _) = self + .test_chainstate + .stacks_node_ref() + .chainstate + .reopen() + .unwrap(); + let mut miner_epoch_info = builder + .pre_epoch_begin(&mut chainstate, &burndb, true) + .unwrap(); + let (mut epoch_tx, _) = builder.epoch_begin(&burndb, &mut miner_epoch_info).unwrap(); + let mut total_receipt_size = 0; + + // First mine the coinbase transaction + builder + .try_mine_tx(&mut epoch_tx, &coinbase_tx, None, &mut total_receipt_size) + .unwrap(); + + // We attempt to mine each transaction to build the hash + for tx in &test_block.transactions { + // NOTE: It is expected to fail when trying computing the marf for invalid block/transactions. + let _ = builder.try_mine_tx(&mut epoch_tx, tx, None, &mut total_receipt_size); + } + + let stacks_block = builder.mine_anchored_block(&mut epoch_tx); + epoch_tx.rollback_block(); + stacks_block + }; + // Just in case any of the transactions failed during above marf computation, just overwrite the merkle root again + let mut txs = vec![coinbase_tx]; + txs.extend_from_slice(&test_block.transactions); + stacks_block.txs = txs; + let tx_merkle_root = { + let txid_vecs: Vec<_> = stacks_block + .txs + .iter() + .map(|tx| tx.txid().as_bytes().to_vec()) + .collect(); + MerkleTree::::new(&txid_vecs).root() + }; + stacks_block.header.tx_merkle_root = tx_merkle_root; + + let block_ops = self.test_chainstate.calculate_block_ops( + &tip, + &mut burn_block, + &last_key, + &stacks_block, + vec![], + parent_sortition_opt.as_ref(), + ); + + (stacks_block, block_ops) + } + + /// Constructs a Nakamoto block with the given [`TestBlock`] configuration. + fn construct_nakamoto_block(&mut self, test_block: TestBlock) -> (NakamotoBlock, usize) { + let chain_tip = NakamotoChainState::get_canonical_block_header( + self.test_chainstate + .stacks_node + .as_ref() + .unwrap() + .chainstate + .db(), + self.test_chainstate.sortdb.as_ref().unwrap(), + ) + .unwrap() + .unwrap(); + let cycle = self.test_chainstate.get_reward_cycle(); + let burn_spent = SortitionDB::get_block_snapshot_consensus( + self.test_chainstate.sortdb_ref().conn(), + &chain_tip.consensus_hash, + ) + .unwrap() + .map(|sn| sn.total_burn) + .unwrap(); + let mut block = NakamotoBlock { + header: NakamotoBlockHeader { + version: 1, + chain_length: chain_tip.stacks_block_height + 1, + burn_spent, + consensus_hash: chain_tip.consensus_hash.clone(), + parent_block_id: chain_tip.index_block_hash(), + tx_merkle_root: Sha512Trunc256Sum::from_data(&[]), + state_index_root: TrieHash::from_empty_data(), + timestamp: 1, + miner_signature: MessageSignature::empty(), + signer_signature: vec![], + pox_treatment: BitVec::ones(1).unwrap(), + }, + txs: test_block.transactions, + }; + + let tx_merkle_root = { + let txid_vecs: Vec<_> = block + .txs + .iter() + .map(|tx| tx.txid().as_bytes().to_vec()) + .collect(); + MerkleTree::::new(&txid_vecs).root() + }; + block.header.tx_merkle_root = tx_merkle_root; + + // Set the MARF root hash or use an all-zero hash in case of failure. + // NOTE: It is expected to fail when trying computing the marf for invalid block/transactions. + let marf_result = + self.compute_naka_block_marf_root_hash(block.header.timestamp, &block.txs); + block.header.state_index_root = match marf_result { + Ok(marf) => marf, + Err(_) => TrieHash::from_bytes(&[0; 32]).unwrap(), + }; + + self.test_chainstate.miner.sign_nakamoto_block(&mut block); + let mut signers = self + .test_chainstate + .config + .test_signers + .clone() + .unwrap_or_default(); + signers.sign_nakamoto_block(&mut block, cycle); + let block_len = block.serialize_to_vec().len(); + (block, block_len) + } + + /// Computes the MARF root hash for a Nakamoto block. + /// + /// This function is intended for use in success test cases only, where all + /// transactions are valid. In other scenarios, the computation may fail. + /// + /// The implementation is deliberately minimal: it does not cover every + /// possible situation (such as new tenure handling), but it should be + /// sufficient for the scope of our test cases. + fn compute_naka_block_marf_root_hash( + &mut self, + block_time: u64, + block_txs: &[StacksTransaction], + ) -> Result { + let node = self.test_chainstate.stacks_node.as_mut().unwrap(); + let sortdb = self.test_chainstate.sortdb.as_ref().unwrap(); + let burndb_conn = sortdb.index_handle_at_tip(); + let chainstate = &mut node.chainstate; + + let chain_tip = NakamotoChainState::get_canonical_block_header(chainstate.db(), sortdb) + .unwrap() + .unwrap(); + + let (chainstate_tx, clarity_instance) = chainstate.chainstate_tx_begin().unwrap(); + let burndb_conn = sortdb.index_handle_at_tip(); + + let mut clarity_tx = StacksChainState::chainstate_block_begin( + &chainstate_tx, + clarity_instance, + &burndb_conn, + &chain_tip.consensus_hash, + &chain_tip.anchored_header.block_hash(), + &MINER_BLOCK_CONSENSUS_HASH, + &MINER_BLOCK_HEADER_HASH, + ); + let result = Self::inner_compute_naka_block_marf_root_hash( + &mut clarity_tx, + block_time, + block_txs, + chain_tip.burn_header_height, + ); + clarity_tx.rollback_block(); + result + } + + /// This is where the real MARF computation happens for Nakamoto blocks. + /// It is extrapolated into an _inner_ method to simplify rollback handling, + /// ensuring that rollback can be applied consistently on both success and failure + /// in the _outer_ method. + fn inner_compute_naka_block_marf_root_hash( + clarity_tx: &mut ClarityTx, + block_time: u64, + block_txs: &[StacksTransaction], + burn_header_height: u32, + ) -> Result { + clarity_tx + .connection() + .as_free_transaction(|clarity_tx_conn| { + clarity_tx_conn.with_clarity_db(|db| { + db.setup_block_metadata(Some(block_time))?; + Ok(()) + }) + }) + .map_err(|e| e.to_string())?; + + StacksChainState::process_block_transactions(clarity_tx, block_txs, 0) + .map_err(|e| e.to_string())?; + + NakamotoChainState::finish_block(clarity_tx, None, false, burn_header_height) + .map_err(|e| e.to_string())?; + + Ok(clarity_tx.seal()) + } + + /// Advance out of a pre-nakamoto prepare phase to prevent potentially messing with the PoX anchor block selection + /// Is a no-op if already in Nakamoto epoch + pub fn consume_pre_naka_prepare_phase(&mut self) { + let mut block_height = self.test_chainstate.get_burn_block_height(); + let evaluating_epoch = + SortitionDB::get_stacks_epoch(self.test_chainstate.sortdb().conn(), block_height + 1) + .unwrap() + .unwrap() + .epoch_id; + if !evaluating_epoch.uses_nakamoto_blocks() { + block_height = self.test_chainstate.get_burn_block_height(); + while self + .test_chainstate + .config + .burnchain + .is_in_prepare_phase(block_height + 1) + { + // Cannot apply a pre nakamoto block in the prepare phase in case it fails and we do not calculate + // our PoX anchor properly. Mine until we are out of the prepare phase + self.test_chainstate.mine_pre_nakamoto_tenure_with_txs(&[]); + block_height = self.test_chainstate.get_burn_block_height(); + } + } + } +} + +/// A complete consensus test that drives a [`ConsensusChain`] through a series of epochs. /// -/// # Example +/// It stores the blocks to execute per epoch and runs them in chronological order, +/// producing a vector of [`ExpectedResult`] suitable for snapshot testing. +pub struct ConsensusTest<'a> { + pub chain: ConsensusChain<'a>, + epoch_blocks: HashMap>, +} + +impl ConsensusTest<'_> { + /// Constructs a [`ConsensusTest`] from a map of **epoch → blocks**. + /// + /// The map is converted into `num_blocks_per_epoch` for chain initialisation. + pub fn new( + test_name: &str, + initial_balances: Vec<(PrincipalData, u64)>, + epoch_blocks: HashMap>, + ) -> Self { + let mut num_blocks_per_epoch = HashMap::new(); + for (epoch, blocks) in &epoch_blocks { + num_blocks_per_epoch.insert(*epoch, blocks.len() as u64); + } + Self { + chain: ConsensusChain::new(test_name, initial_balances, num_blocks_per_epoch), + epoch_blocks, + } + } + + /// Executes a full test plan by processing blocks across multiple epochs. + /// + /// This function serves as the primary test runner. It iterates through the + /// provided epochs in chronological order, automatically advancing the + /// chainstate to the start of each epoch. It then processes all [`TestBlock`]'s + /// associated with that epoch and collects their results. + /// + /// # Returns + /// + /// A Vec<['ExpectedResult`]> with the outcome of each block for snapshot testing. + pub fn run(mut self) -> Vec { + let mut sorted_epochs: Vec<_> = self.epoch_blocks.clone().into_iter().collect(); + sorted_epochs.sort_by_key(|(epoch_id, _)| *epoch_id); + + let mut results = vec![]; + + for (epoch, blocks) in sorted_epochs { + debug!( + "--------- Processing epoch {epoch:?} with {} blocks ---------", + blocks.len() + ); + // Use the miner key to prevent messing with FAUCET nonces. + let miner_key = self.chain.test_chainstate.miner.nakamoto_miner_key(); + self.chain + .test_chainstate + .advance_into_epoch(&miner_key, epoch); + + let is_naka_epoch = epoch.uses_nakamoto_blocks(); + for block in blocks { + self.chain.consume_pre_naka_prepare_phase(); + results.push(self.chain.append_block(block, is_naka_epoch)); + } + } + results + } +} + +/// A high-level test harness for running consensus-critical smart contract tests. /// -/// ```rust,ignore -/// contract_call_consensus_test!( -/// my_test, -/// contract_name: "my-contract", -/// contract_code: "(define-public (get-message) (ok \"hello\"))", -/// function_name: "get-message", -/// function_args: &[], -/// ); -/// ``` -macro_rules! contract_call_consensus_test { - ( - $name:ident, - contract_name: $contract_name:expr, - contract_code: $contract_code:expr, - function_name: $function_name:expr, - function_args: $function_args:expr, - $(deploy_epochs: $deploy_epochs:expr,)? - $(call_epochs: $call_epochs:expr,)? - ) => { - #[test] - fn $name() { - let contract_name = $contract_name; +/// This struct enables end-to-end testing of Clarity smart contracts under varying epoch conditions, +/// including different Clarity language versions and block rule sets. It automates: +/// +/// - Contract deployment in specified epochs (with epoch-appropriate Clarity versions) +/// - Function execution in subsequent or same epochs +/// - Block-by-block execution with precise control over transaction ordering and nonces +/// - Snapshot testing of execution outcomes via [`ExpectedResult`] +/// +/// It integrates: +/// - [`ConsensusChain`] for chain simulation and block production +/// - [`TestTxFactory`] for deterministic transaction generation +/// +/// NOTE: The **majority of logic and state computation occurs during construction to enable a deterministic TestChainstate** (`new()`): +/// - All contract names are generated and versioned +/// - Block counts per epoch are precomputed +/// - Epoch order is finalized +/// - Transaction sequencing is fully planned +pub struct ContractConsensusTest<'a> { + /// Factory for generating signed, nonce-managed transactions. + tx_factory: TestTxFactory, + /// Underlying chainstate used for block execution and consensus checks. + 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>, + /// Mapping of epoch → list of `contract_names` that should be called in that epoch. + contract_calls_per_epoch: HashMap>, + /// Source code of the Clarity contract being deployed and called. + contract_code: String, + /// Name of the public function to invoke during the call phase. + function_name: String, + /// Arguments to pass to `function_name` on every call. + function_args: Vec, + /// Sorted, deduplicated set of all epochs involved. + /// Used to iterate through test phases in chronological order. + all_epochs: BTreeSet, +} - // Handle deploy_epochs parameter (default to all epochs >= 3.0 if not provided) - let deploy_epochs = StacksEpochId::ALL_GTE_30; - $(let deploy_epochs = $deploy_epochs;)? +impl ContractConsensusTest<'_> { + /// Creates a new [`ContractConsensusTest`] instance. + /// + /// Initializes the test environment to: + /// - Deploy `contract_code` under `contract_name` in each `deploy_epochs` + /// - Call `function_name` with `function_args` in each `call_epochs` + /// - Track all contract instances per epoch and Clarity version + /// - Precompute block counts per epoch for stable chain simulation + /// + /// # Arguments + /// + /// * `test_name` - Unique identifier for the test run (used in logging and snapshots) + /// * `initial_balances` - Initial STX balances for principals (e.g., faucet, users) + /// * `deploy_epochs` - List of epochs where contract deployment should occur + /// * `call_epochs` - List of epochs where function calls should be executed + /// * `contract_name` - Base name for deployed contracts (versioned suffixes added automatically) + /// * `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 + /// + /// - If `deploy_epochs` is empty. + /// - If any `call_epoch` is less than the minimum `deploy_epoch`. + #[allow(clippy::too_many_arguments)] + pub fn new( + test_name: &str, + initial_balances: Vec<(PrincipalData, u64)>, + deploy_epochs: &[StacksEpochId], + call_epochs: &[StacksEpochId], + contract_name: &str, + 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), + "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" + ); - // Handle call_epochs parameter (default to EPOCHS_TO_TEST if not provided) - let call_epochs = EPOCHS_TO_TEST; - $(let call_epochs = $call_epochs;)? + // 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> = + 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 contract_test = ContractConsensusTest::new(function_name!()); - let result = contract_test.run( - contract_name, - $contract_code, - $function_name, - $function_args, - deploy_epochs, - call_epochs, + 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 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_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 + for &version in clarity_versions { + let version_tag = version.to_string().replace(' ', ""); + let name = format!("{contract_name}-{epoch_name}-{version_tag}"); + contract_deploys_per_epoch + .entry(*epoch) + .or_default() + .push((name.clone(), version)); + contract_names.push(name.clone()); + num_blocks += 1; + } + } + + if call_epochs.contains(epoch) { + // Each call is a separate TestBlock + for name in &contract_names { + // Each call is a separate TestBlock + contract_calls_per_epoch + .entry(*epoch) + .or_default() + .push(name.clone()); + num_blocks += 1; + } + } + if num_blocks > 0 { + num_blocks_per_epoch.insert(*epoch, num_blocks); + } + } + + Self { + tx_factory: TestTxFactory::new(CHAIN_ID_TESTNET), + chain: ConsensusChain::new(test_name, initial_balances, num_blocks_per_epoch), + contract_addr: to_addr(&FAUCET_PRIV_KEY), + contract_deploys_per_epoch, + contract_calls_per_epoch, + contract_code: contract_code.to_string(), + function_name: function_name.to_string(), + function_args: function_args.to_vec(), + setup_contracts_per_epoch, + all_epochs, + } + } + + /// Generates a transaction, appends it to a new test block, and executes the block. + /// + /// If the transaction succeeds, this function automatically increments the sender's + /// nonce for subsequent transactions. + /// + /// # Arguments + /// + /// - `tx_spec`: The transaction specification to generate and execute. + /// - `is_naka_block`: Whether this block is mined under Nakamoto consensus rules. + /// + /// # Returns + /// + /// The [`ExpectedResult`] of block execution (success/failure with VM output) + fn append_tx_block(&mut self, tx_spec: &TestTxSpec, is_naka_block: bool) -> ExpectedResult { + let tx = self.tx_factory.generate_tx(tx_spec); + let block = TestBlock { + transactions: vec![tx], + }; + + let result = self.chain.append_block(block, is_naka_block); + + if let ExpectedResult::Success(_) = result { + self.tx_factory.increase_nonce_for_tx(tx_spec); + } + + result + } + + /// Deploys prerequisite contracts scheduled for the given epoch. + /// 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; + }; + + let is_naka_block = epoch.uses_nakamoto_blocks(); + 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, ); + 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 + ); + } + } + }); + } + + /// Deploys all contract versions scheduled for the given epoch. + /// + /// For each Clarity version supported in the epoch: + /// - Generates a unique contract name (e.g., `my-contract-Epoch30-Clarity3`) + /// - Deploys in a **separate block** + /// - Uses `None` for Clarity version in pre-2.1 epochs (behaviour defaults to Clarity 1) + /// + /// # Returns + /// A vector of [`ExpectedResult`] values, one per deployment block. + fn deploy_contracts(&mut self, epoch: StacksEpochId) -> Vec { + let Some(contract_names) = self.contract_deploys_per_epoch.get(&epoch) else { + warn!("No contract deployments found for {epoch}."); + return vec![]; + }; + + let is_naka_block = epoch.uses_nakamoto_blocks(); + contract_names + .clone() + .iter() + .map(|(name, version)| { + let clarity_version = if epoch < StacksEpochId::Epoch21 { + // Old epochs have no concept of clarity version. It defaults to + // clarity version 1 behaviour. + None + } else { + Some(*version) + }; + self.chain.consume_pre_naka_prepare_phase(); + self.append_tx_block( + &TestTxSpec::ContractDeploy { + sender: &FAUCET_PRIV_KEY, + name, + code: &self.contract_code.clone(), + clarity_version, + }, + is_naka_block, + ) + }) + .collect() + } + + /// Executes the test function on **all** contracts deployed in the given epoch. + /// + /// Each call occurs in a **separate block** to isolate side effects and enable + /// fine-grained snapshot assertions. All prior deployments (even from earlier epochs) + /// are callable if they exist in the chain state. + /// + /// # Arguments + /// + /// - `epoch`: The epoch in which to perform contract calls. + /// + /// # Returns + /// + /// A Vec<['ExpectedResult`]> with one entry per function call + fn call_contracts(&mut self, epoch: StacksEpochId) -> Vec { + let Some(contract_names) = self.contract_calls_per_epoch.get(&epoch) else { + warn!("No contract calls found for {epoch}."); + return vec![]; + }; - insta::assert_ron_snapshot!(result); + let is_naka_block = epoch.uses_nakamoto_blocks(); + contract_names + .clone() + .iter() + .map(|contract_name| { + self.chain.consume_pre_naka_prepare_phase(); + self.append_tx_block( + &TestTxSpec::ContractCall { + sender: &FAUCET_PRIV_KEY, + contract_addr: &self.contract_addr.clone(), + contract_name, + function_name: &self.function_name.clone(), + args: &self.function_args.clone(), + }, + is_naka_block, + ) + }) + .collect() + } + + /// Executes the full consensus test: deploy in [`Self::contract_deploys_per_epoch`], call in [`Self::contract_calls_per_epoch`]. + /// + /// Processes epochs in **sorted order** using [`Self::all_epochs`]. For each epoch: + /// - Advances the chain into the target epoch + /// - Deploys contracts (if scheduled) + /// - Executes function calls (if scheduled) + /// + /// # Execution Order Example + /// + /// Given at test instantiation: + /// ```rust,ignore + /// deploy_epochs = [Epoch20, Epoch30] + /// call_epochs = [Epoch30, Epoch31] + /// ``` + /// + /// The sequence is: + /// 1. Enter Epoch 2.0 → Deploy `contract-v1` + /// 2. Enter Epoch 3.0 → Deploy `contract-v1`, `contract-v2`, `contract-v3` + /// 3. Enter Epoch 3.0 → Call function on all 4 deployed contracts + /// 4. Enter Epoch 3.1 → Call function on all 4 deployed contracts + /// + /// # Returns + /// + /// A Vec<['ExpectedResult`]> with the outcome of each block for snapshot testing. + pub fn run(mut self) -> Vec { + let mut results = Vec::new(); + + // Process epochs in order + for epoch in self.all_epochs.clone() { + // Use the miner as the sender to prevent messing with the block transaction nonces of the deployer/callers + let private_key = self.chain.test_chainstate.miner.nakamoto_miner_key(); + + // Advance the chain into the target epoch + self.chain + .test_chainstate + .advance_into_epoch(&private_key, 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)); } - }; -} -/// Generates a consensus test for contract deployment across multiple Stacks epochs. -/// -/// This macro automates deploying a contract across different Stacks epochs and -/// Clarity versions. It is primarily used for consensus-critical testing of contract -/// deployment behavior. -/// -/// # Behavior -/// -/// - **Deployment:** Deploys `contract_code` in each epoch specified by `deploy_epochs` -/// for all applicable [`ClarityVersion`]s. -/// - **Structure:** Each deployment is executed in its own block, ensuring clear -/// separation between transactions. -/// -/// # Arguments -/// -/// * `$name` — Name of the generated test function. -/// * `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`]. -/// -/// # Example -/// -/// ```rust,ignore -/// contract_deploy_consensus_test!( -/// deploy_test, -/// contract_name: "my-contract", -/// contract_code: "(define-public (init) (ok true))", -/// ); -/// ``` -macro_rules! contract_deploy_consensus_test { - // Handle the case where deploy_epochs is not provided - ( - $name:ident, - contract_name: $contract_name:expr, - contract_code: $contract_code:expr, - ) => { - contract_deploy_consensus_test!( - $name, - contract_name: $contract_name, - contract_code: $contract_code, - deploy_epochs: EPOCHS_TO_TEST, - ); - }; - ( - $name:ident, - contract_name: $contract_name:expr, - contract_code: $contract_code:expr, - deploy_epochs: $deploy_epochs:expr, - ) => { - contract_call_consensus_test!( - $name, - 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 - ); - }; + results + } } /// The type of transaction to create. @@ -533,553 +1551,245 @@ impl TestTxFactory { function_name: &str, args: &[ClarityValue], ) -> StacksTransaction { - let address = StacksAddress::p2pkh(false, &StacksPublicKey::from_private(sender)); - let nonce = self.nonce_counter.entry(address).or_insert(0); - let tx_bytes = make_contract_call( - sender, - *nonce, - 200, - self.default_chain_id, - contract_addr, - contract_name, - function_name, - args, - ); - StacksTransaction::consensus_deserialize(&mut tx_bytes.as_slice()).unwrap() - } -} - -fn epoch_3_0_onwards(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, - network_epoch: PEER_VERSION_EPOCH_2_5, - }, - StacksEpoch { - epoch_id: StacksEpochId::Epoch30, - start_height: first_burnchain_height, - end_height: first_burnchain_height + 1, - block_limit: BLOCK_LIMIT_MAINNET_21, - network_epoch: PEER_VERSION_EPOCH_3_0, - }, - StacksEpoch { - epoch_id: StacksEpochId::Epoch31, - start_height: first_burnchain_height + 1, - end_height: first_burnchain_height + 2, - block_limit: BLOCK_LIMIT_MAINNET_21, - network_epoch: PEER_VERSION_EPOCH_3_1, - }, - StacksEpoch { - epoch_id: StacksEpochId::Epoch32, - start_height: first_burnchain_height + 2, - end_height: first_burnchain_height + 3, - block_limit: BLOCK_LIMIT_MAINNET_21, - network_epoch: PEER_VERSION_EPOCH_3_2, - }, - StacksEpoch { - epoch_id: StacksEpochId::Epoch33, - start_height: first_burnchain_height + 3, - end_height: STACKS_EPOCH_MAX, - block_limit: BLOCK_LIMIT_MAINNET_21, - network_epoch: PEER_VERSION_EPOCH_3_3, - }, - ]) -} - -/// Custom serializer for `Option` to improve snapshot readability. -/// This avoids large diffs in snapshots due to code body changes and focuses on key fields. -fn serialize_opt_tx_payload( - value: &Option, - serializer: S, -) -> Result -where - S: Serializer, -{ - let changed = match value { - None => "BitcoinTx".to_string(), - Some(TransactionPayload::TokenTransfer(sender, amount, memo)) => { - format!("TokenTransfer(from: {sender}, amount: {amount}, memo: {memo})") - } - Some(TransactionPayload::SmartContract( - TransactionSmartContract { name, code_body }, - clarity_version, - )) => { - format!("SmartContract(name: {name}, code_body: [..], clarity_version: {clarity_version:?})") - } - Some(TransactionPayload::ContractCall(TransactionContractCall { - address, - contract_name, - function_name, - function_args, - })) => { - format!("ContractCall(address: {address}, contract_name: {contract_name}, function_name: {function_name}, function_args: [{function_args:?}])") - } - Some(payload) => { - format!("{payload:?}") - } - }; - serializer.serialize_str(&changed) -} - -/// Serialize an optional string field appending a non-consensus breaking info message. -fn serialize_opt_string_ncb(value: &Option, serializer: S) -> Result -where - S: Serializer, -{ - let original = match value.as_deref() { - Some(str) => format!("Some({str})"), - None => "None".to_string(), - }; - let changed = format!("{original} [NON-CONSENSUS BREAKING]"); - serializer.serialize_str(&changed) -} - -/// Represents the expected output of a transaction in a test. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub struct ExpectedTransactionOutput { - /// The transaction that was executed. - /// `None` for bitcoin transactions. - #[serde(serialize_with = "serialize_opt_tx_payload")] - pub tx: Option, - /// The possible Clarity VM error message associated to the transaction (non-consensus breaking) - #[serde(serialize_with = "serialize_opt_string_ncb")] - pub vm_error: Option, - /// The expected return value of the transaction. - pub return_type: ClarityValue, - /// The expected execution cost of the transaction. - pub cost: ExecutionCost, -} - -/// Represents the expected outputs for a block's execution. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub struct ExpectedBlockOutput { - /// The expected block marf - pub marf_hash: TrieHash, - /// The epoch in which the test block was expected to be evaluated - pub evaluated_epoch: StacksEpochId, - /// The expected outputs for each transaction, in input order. - pub transactions: Vec, - /// The total execution cost of the block. - pub total_block_cost: ExecutionCost, -} - -/// Represents the expected result of a consensus test. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub enum ExpectedResult { - /// The test should succeed with the specified outputs. - Success(ExpectedBlockOutput), - /// The test should fail with an error matching the specified string - /// Cannot match on the exact Error directly as they do not implement - /// Serialize/Deserialize or PartialEq - Failure(String), -} - -impl ExpectedResult { - fn create_from( - result: Result, - marf_hash: TrieHash, - ) -> Self { - match result { - Ok(epoch_receipt) => { - let transactions: Vec = epoch_receipt - .tx_receipts - .into_iter() - .map(|r| { - let tx = match r.transaction { - TransactionOrigin::Stacks(tx) => Some(tx.payload), - TransactionOrigin::Burn(..) => None, - }; - ExpectedTransactionOutput { - tx, - return_type: r.result, - cost: r.execution_cost, - vm_error: r.vm_error, - } - }) - .collect(); - ExpectedResult::Success(ExpectedBlockOutput { - marf_hash, - evaluated_epoch: epoch_receipt.evaluated_epoch, - transactions, - total_block_cost: epoch_receipt.anchored_block_cost, - }) - } - Err(e) => ExpectedResult::Failure(e.to_string()), - } - } -} - -/// Represents a block to be appended in a test and its expected result. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub struct TestBlock { - /// Transactions to include in the block - pub transactions: Vec, -} - -/// Represents a consensus test with chainstate. -pub struct ConsensusTest<'a> { - pub chain: TestChainstate<'a>, -} - -impl ConsensusTest<'_> { - /// Creates a new `ConsensusTest` with the given test name and initial balances. - pub fn new(test_name: &str, initial_balances: Vec<(PrincipalData, u64)>) -> Self { - // Set up chainstate to start at Epoch 3.0 - let mut boot_plan = NakamotoBootPlan::new(test_name) - // These are the minimum values found for the fastest test execution. - // - // If changing these values, ensure the following conditions are met: - // 1. Min 6 reward blocks (test framework limitation). - // 2. Epoch 3.0 starts in the reward phase. - // 3. Tests bypass mainnet's prepare_length >= 3 (allowing 1). - // - Current boot sequence: - // - Cycle 3: Signers at height 27 register for 12 reward cycles - // - Cycle 4: Epoch 3.0 starts at height 30 - // Tests generate 1 bitcoin block per epoch transition after 3.0 - // staying within the registration window - .with_pox_constants(7, 1) - .with_initial_balances(initial_balances) - .with_private_key(FAUCET_PRIV_KEY.clone()); - let epochs = epoch_3_0_onwards( - (boot_plan.pox_constants.pox_4_activation_height - + boot_plan.pox_constants.reward_cycle_length - + 1) as u64, - ); - boot_plan = boot_plan.with_epochs(epochs); - let chain = boot_plan.boot_nakamoto_chainstate(None); - - Self { chain } - } - - /// Advances the chainstate to the specified epoch. Creating a tenure change block per burn block height - pub fn advance_to_epoch(&mut self, target_epoch: StacksEpochId) { - let burn_block_height = self.chain.get_burn_block_height(); - let mut current_epoch = - SortitionDB::get_stacks_epoch(self.chain.sortdb().conn(), burn_block_height) - .unwrap() - .unwrap() - .epoch_id; - assert!(current_epoch <= target_epoch, "Chainstate is already at a higher epoch than the target. Current epoch: {current_epoch}. Target epoch: {target_epoch}"); - while current_epoch < target_epoch { - let (burn_ops, mut tenure_change, miner_key) = self - .chain - .begin_nakamoto_tenure(TenureChangeCause::BlockFound); - let (_, header_hash, consensus_hash) = self.chain.next_burnchain_block(burn_ops); - let vrf_proof = self.chain.make_nakamoto_vrf_proof(miner_key); - - tenure_change.tenure_consensus_hash = consensus_hash.clone(); - tenure_change.burn_view_consensus_hash = consensus_hash.clone(); - let tenure_change_tx = self.chain.miner.make_nakamoto_tenure_change(tenure_change); - let coinbase_tx = self.chain.miner.make_nakamoto_coinbase(None, vrf_proof); - - let blocks_and_sizes = self - .chain - .make_nakamoto_tenure(tenure_change_tx, coinbase_tx, Some(0)) - .unwrap(); - assert_eq!( - blocks_and_sizes.len(), - 1, - "Mined more than one Nakamoto block" - ); - let burn_block_height = self.chain.get_burn_block_height(); - current_epoch = - SortitionDB::get_stacks_epoch(self.chain.sortdb().conn(), burn_block_height) - .unwrap() - .unwrap() - .epoch_id; - } - } - - /// Appends a single block to the chain and returns the result. - /// - /// This method takes a [`TestBlock`] containing a list of transactions, constructs - /// a fully valid [`NakamotoBlock`], processes it against the current chainstate. - /// - /// # Arguments - /// - /// * `block` - The test block to be processed and appended to the chain. - /// - /// # Returns - /// - /// A [`ExpectedResult`] with the outcome of the block processing. - pub fn append_block(&mut self, block: TestBlock) -> ExpectedResult { - debug!("--------- Running block {block:?} ---------"); - let (nakamoto_block, block_size) = self.construct_nakamoto_block(block); - let mut sortdb = self.chain.sortdb.take().unwrap(); - let mut stacks_node = self.chain.stacks_node.take().unwrap(); - let chain_tip = - NakamotoChainState::get_canonical_block_header(stacks_node.chainstate.db(), &sortdb) - .unwrap() - .unwrap(); - let pox_constants = PoxConstants::test_default(); - let sig_hash = nakamoto_block.header.signer_signature_hash(); - debug!( - "--------- Processing block {sig_hash} ---------"; - "block" => ?nakamoto_block - ); - let expected_marf = nakamoto_block.header.state_index_root; - let res = TestStacksNode::process_pushed_next_ready_block( - &mut stacks_node, - &mut sortdb, - &mut self.chain.miner, - &chain_tip.consensus_hash, - &mut self.chain.coord, - nakamoto_block.clone(), - ); - debug!( - "--------- Processed block: {sig_hash} ---------"; - "block" => ?nakamoto_block + let address = StacksAddress::p2pkh(false, &StacksPublicKey::from_private(sender)); + let nonce = self.nonce_counter.entry(address).or_insert(0); + let tx_bytes = make_contract_call( + sender, + *nonce, + 200, + self.default_chain_id, + contract_addr, + contract_name, + function_name, + args, ); - let remapped_result = res.map(|receipt| receipt.unwrap()); - // Restore chainstate for the next block - self.chain.sortdb = Some(sortdb); - self.chain.stacks_node = Some(stacks_node); - ExpectedResult::create_from(remapped_result, expected_marf) + StacksTransaction::consensus_deserialize(&mut tx_bytes.as_slice()).unwrap() } +} - /// Executes a full test plan by processing blocks across multiple epochs. - /// - /// This function serves as the primary test runner. It iterates through the - /// provided epochs in chronological order, automatically advancing the - /// chainstate to the start of each epoch. It then processes all [`TestBlock`]'s - /// associated with that epoch and collects their results. - /// - /// # Arguments - /// - /// * `epoch_blocks` - A map where keys are [`StacksEpochId`]s and values are the - /// sequence of blocks to be executed during that epoch. - /// - /// # Returns - /// - /// A `Vec` with the outcome of each block for snapshot testing. - pub fn run( - mut self, - epoch_blocks: HashMap>, - ) -> Vec { - // Validate blocks - for (epoch_id, blocks) in epoch_blocks.iter() { - assert!( - !matches!( - *epoch_id, - StacksEpochId::Epoch10 - | StacksEpochId::Epoch20 - | StacksEpochId::Epoch2_05 - | StacksEpochId::Epoch21 - | StacksEpochId::Epoch22 - | StacksEpochId::Epoch23 - | StacksEpochId::Epoch24 - | StacksEpochId::Epoch25 - ), - "Pre-Nakamoto Tenures are not Supported" - ); - assert!( - !blocks.is_empty(), - "Each epoch must have at least one block" +/// Generates a consensus test body for executing a contract function across multiple Stacks epochs. +/// +/// This macro automates both contract deployment and function invocation across different +/// epochs and Clarity versions. +/// It simplifies the setup of consensus-critical tests involving versioned smart contracts. +/// +/// # Behavior +/// +/// - **Deployment:** Deploys `contract_code` in each epoch specified in `deploy_epochs` +/// for every applicable [`ClarityVersion`]. +/// - **Execution:** Calls `function_name` in each epoch from `call_epochs` on all previously +/// deployed contract instances. +/// - **Structure:** Each deployment and function call is executed in its own block, ensuring +/// clear separation between transactions. +/// +/// # Arguments +/// +/// * `contract_name` — The name of the contract. +/// * `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 ≥ 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 +/// +/// ```rust,ignore +/// #[test] +/// fn test_my_contract_call_consensus() { +/// contract_call_consensus_test!( +/// contract_name: "my-contract", +/// 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\"))", +/// )], +/// ); +/// } +/// ``` +macro_rules! contract_call_consensus_test { + ( + contract_name: $contract_name:expr, + contract_code: $contract_code:expr, + function_name: $function_name:expr, + 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,)? + ) => { + { + // Handle deploy_epochs parameter (default to all epochs >= 2.0 if not provided) + let deploy_epochs = &clarity::types::StacksEpochId::ALL[1..]; + $(let deploy_epochs = $deploy_epochs;)? + + // 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 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![], + deploy_epochs, + call_epochs, + $contract_name, + $contract_code, + $function_name, + $function_args, + exclude_clarity_versions, + setup_contracts, ); + let result = contract_test.run(); + insta::assert_ron_snapshot!(result); } + }; +} +pub(crate) use contract_call_consensus_test; - let mut sorted_epochs: Vec<_> = epoch_blocks.into_iter().collect(); - sorted_epochs.sort_by_key(|(epoch_id, _)| *epoch_id); - - let mut results = vec![]; - - for (epoch, blocks) in sorted_epochs { - debug!( - "--------- Processing epoch {epoch:?} with {} blocks ---------", - blocks.len() +/// Generates a consensus test body for contract deployment across multiple Stacks epochs. +/// +/// This macro automates deploying a contract across different Stacks epochs and +/// Clarity versions. It is primarily used for consensus-critical testing of contract +/// deployment behavior. +/// +/// # Behavior +/// +/// - **Deployment:** Deploys `contract_code` in each epoch specified by `deploy_epochs` +/// for all applicable [`ClarityVersion`]s. +/// - **Structure:** Each deployment is executed in its own block, ensuring clear +/// separation between transactions. +/// +/// # Arguments +/// +/// * `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 +/// +/// ```rust,ignore +/// #[test] +/// fn test_my_contract_deploy_consensus() { +/// contract_deploy_consensus_test!( +/// deploy_test, +/// contract_name: "my-contract", +/// contract_code: "(define-public (init) (ok true))", +/// ); +/// } +/// ``` +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,)? + ) => { + { + 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 + $(exclude_clarity_versions: $exclude_clarity_versions,)? + $(setup_contracts: $setup_contracts,)? ); - self.advance_to_epoch(epoch); - - for block in blocks { - results.push(self.append_block(block)); - } } - results - } - - /// Constructs a Nakamoto block with the given [`TestBlock`] configuration. - fn construct_nakamoto_block(&mut self, test_block: TestBlock) -> (NakamotoBlock, usize) { - let chain_tip = NakamotoChainState::get_canonical_block_header( - self.chain.stacks_node.as_ref().unwrap().chainstate.db(), - self.chain.sortdb.as_ref().unwrap(), - ) - .unwrap() - .unwrap(); - let cycle = self.chain.get_reward_cycle(); - let burn_spent = SortitionDB::get_block_snapshot_consensus( - self.chain.sortdb_ref().conn(), - &chain_tip.consensus_hash, - ) - .unwrap() - .map(|sn| sn.total_burn) - .unwrap(); - let mut block = NakamotoBlock { - header: NakamotoBlockHeader { - version: 1, - chain_length: chain_tip.stacks_block_height + 1, - burn_spent, - consensus_hash: chain_tip.consensus_hash.clone(), - parent_block_id: chain_tip.index_block_hash(), - tx_merkle_root: Sha512Trunc256Sum::from_data(&[]), - state_index_root: TrieHash::from_empty_data(), - timestamp: 1, - miner_signature: MessageSignature::empty(), - signer_signature: vec![], - pox_treatment: BitVec::ones(1).unwrap(), - }, - txs: test_block.transactions, - }; - - let tx_merkle_root = { - let txid_vecs: Vec<_> = block - .txs - .iter() - .map(|tx| tx.txid().as_bytes().to_vec()) - .collect(); - MerkleTree::::new(&txid_vecs).root() - }; - block.header.tx_merkle_root = tx_merkle_root; + }; +} +pub(crate) use contract_deploy_consensus_test; - // Set the MARF root hash or use an all-zero hash in case of failure. - // NOTE: It is expected to fail when trying computing the marf for invalid block/transactions. - let marf_result = self.compute_block_marf_root_hash(block.header.timestamp, &block.txs); - block.header.state_index_root = match marf_result { - Ok(marf) => marf, - Err(_) => TrieHash::from_bytes(&[0; 32]).unwrap(), - }; +/// 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, +} - self.chain.miner.sign_nakamoto_block(&mut block); - let mut signers = self.chain.config.test_signers.clone().unwrap_or_default(); - signers.sign_nakamoto_block(&mut block, cycle); - let block_len = block.serialize_to_vec().len(); - (block, block_len) +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, + } } - /// Computes the MARF root hash for a block. - /// - /// This function is intended for use in success test cases only, where all - /// transactions are valid. In other scenarios, the computation may fail. - /// - /// The implementation is deliberately minimal: it does not cover every - /// possible situation (such as new tenure handling), but it should be - /// sufficient for the scope of our test cases. - fn compute_block_marf_root_hash( - &mut self, - block_time: u64, - block_txs: &[StacksTransaction], - ) -> Result { - let node = self.chain.stacks_node.as_mut().unwrap(); - let sortdb = self.chain.sortdb.as_ref().unwrap(); - let burndb_conn = sortdb.index_handle_at_tip(); - let chainstate = &mut node.chainstate; + /// Override the epoch where this setup contract should deploy. + pub fn with_epoch(mut self, epoch: StacksEpochId) -> Self { + self.deploy_epoch = Some(epoch); + self + } - let chain_tip = NakamotoChainState::get_canonical_block_header(chainstate.db(), sortdb) - .unwrap() - .unwrap(); + /// 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 + } +} - let (chainstate_tx, clarity_instance) = chainstate.chainstate_tx_begin().unwrap(); - let burndb_conn = sortdb.index_handle_at_tip(); +// Just a namespace for utilities for writing consensus tests +pub struct ConsensusUtils; - let mut clarity_tx = StacksChainState::chainstate_block_begin( - &chainstate_tx, - clarity_instance, - &burndb_conn, - &chain_tip.consensus_hash, - &chain_tip.anchored_header.block_hash(), - &MINER_BLOCK_CONSENSUS_HASH, - &MINER_BLOCK_HEADER_HASH, - ); - let result = Self::inner_compute_block_marf_root_hash( - &mut clarity_tx, - block_time, - block_txs, - chain_tip.burn_header_height, +impl ConsensusUtils { + pub fn new_deploy_tx( + nonce: u64, + contract_name: &str, + contract_code: &str, + clarity_version: Option, + ) -> StacksTransaction { + let deploy_tx = make_contract_publish_versioned( + &FAUCET_PRIV_KEY, + nonce, + contract_code.len() as u64 * 100, + CHAIN_ID_TESTNET, + contract_name, + contract_code, + clarity_version, ); - clarity_tx.rollback_block(); - result + StacksTransaction::consensus_deserialize(&mut deploy_tx.as_slice()).unwrap() } - /// This is where the real MARF computation happens. - /// It is extrapolated into an _inner_ method to simplify rollback handling, - /// ensuring that rollback can be applied consistently on both success and failure - /// in the _outer_ method. - fn inner_compute_block_marf_root_hash( - clarity_tx: &mut ClarityTx, - block_time: u64, - block_txs: &[StacksTransaction], - burn_header_height: u32, - ) -> Result { - clarity_tx - .connection() - .as_free_transaction(|clarity_tx_conn| { - clarity_tx_conn.with_clarity_db(|db| { - db.setup_block_metadata(Some(block_time))?; - Ok(()) - }) - }) - .map_err(|e| e.to_string())?; - - StacksChainState::process_block_transactions(clarity_tx, block_txs, 0) - .map_err(|e| e.to_string())?; - - NakamotoChainState::finish_block(clarity_tx, None, false, burn_header_height) - .map_err(|e| e.to_string())?; - - Ok(clarity_tx.seal()) + pub fn new_call_tx(nonce: u64, contract_name: &str, funct_name: &str) -> StacksTransaction { + let call_tx = make_contract_call( + &FAUCET_PRIV_KEY, + nonce, + 200, + CHAIN_ID_TESTNET, + &to_addr(&FAUCET_PRIV_KEY), + contract_name, + funct_name, + &[], + ); + StacksTransaction::consensus_deserialize(&mut call_tx.as_slice()).unwrap() } } @@ -1093,7 +1803,7 @@ fn test_append_empty_blocks() { epoch_blocks.insert(*epoch, empty_test_blocks.clone()); } - let result = ConsensusTest::new(function_name!(), vec![]).run(epoch_blocks); + let result = ConsensusTest::new(function_name!(), vec![], epoch_blocks).run(); insta::assert_ron_snapshot!(result); } @@ -1137,35 +1847,51 @@ fn test_append_stx_transfers_success() { tx }) .collect(); - epoch_blocks.insert(*epoch, vec![TestBlock { transactions }]); } - let result = ConsensusTest::new(function_name!(), initial_balances).run(epoch_blocks); + let result = ConsensusTest::new(function_name!(), initial_balances, epoch_blocks).run(); insta::assert_ron_snapshot!(result); } -// Example of using the `contract_call_consensus_test!` macro -// Deploys a contract to each epoch, for each Clarity version, -// then calls a function in that contract and snapshots the results. -contract_call_consensus_test!( - successfully_deploy_and_call, - contract_name: "foo_contract", - contract_code: FOO_CONTRACT, - function_name: "bar", - function_args: &[ClarityValue::UInt(1)], -); - -// Example of using the `contract_deploy_consensus_test!` macro -// Deploys a contract that exceeds the maximum allowed stack depth -// and verifies that deployment fails with the expected error. -contract_deploy_consensus_test!( - chainstate_error_expression_stack_depth_too_deep, - contract_name: "test-exceeds", - contract_code: &{ - let exceeds_repeat_factor = AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64); - let tx_exceeds_body_start = "{ a : ".repeat(exceeds_repeat_factor as usize); - let tx_exceeds_body_end = "} ".repeat(exceeds_repeat_factor as usize); - format!("{tx_exceeds_body_start}u1 {tx_exceeds_body_end}") - }, -); +/// Example of using the `contract_call_consensus_test!` macro +/// Deploys a contract to each epoch, for each Clarity version, +/// then calls a function in that contract and snapshots the results. +#[test] +fn test_successfully_deploy_and_call() { + contract_call_consensus_test!( + contract_name: "foo_contract", + contract_code: FOO_CONTRACT, + function_name: "bar", + function_args: &[ClarityValue::UInt(1)], + ); +} + +/// Example of using the `contract_deploy_consensus_test!` macro +/// Deploys a contract to all epoch, for each Clarity version +#[test] +fn test_successfully_deploy() { + contract_deploy_consensus_test!( + contract_name: "foo_contract", + contract_code: FOO_CONTRACT, + ); +} + +#[test] +/// Test that the supertype list is accepted in >= Epoch 2.4, +/// but is rejected in all earlier Epochs +fn problematic_supertype_list() { + contract_deploy_consensus_test!( + contract_name: "problematic", + contract_code: "(define-data-var my-list (list 10 { a: int }) (list { a: 1 })) + (var-set my-list + (unwrap! (as-max-len? + (append (var-get my-list) + { a: 2, b: 2 }) + u10) + (err 1))) + (print (var-get my-list)) + ", + deploy_epochs: &StacksEpochId::ALL[1..], + ); +} diff --git a/stackslib/src/chainstate/tests/mod.rs b/stackslib/src/chainstate/tests/mod.rs index 7b2dcfdb5cc..cedefae82de 100644 --- a/stackslib/src/chainstate/tests/mod.rs +++ b/stackslib/src/chainstate/tests/mod.rs @@ -13,9 +13,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . pub mod consensus; +mod parse_tests; +mod runtime_analysis_tests; +mod static_analysis_tests; use std::fs; +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, +}; use clarity::types::chainstate::{ BlockHeaderHash, BurnchainHeaderHash, StacksAddress, StacksBlockId, }; @@ -49,13 +58,16 @@ use crate::chainstate::nakamoto::tests::get_account; use crate::chainstate::nakamoto::tests::node::{get_nakamoto_parent, TestStacker}; use crate::chainstate::nakamoto::{NakamotoBlock, NakamotoChainState, StacksDBIndexed}; use crate::chainstate::stacks::address::PoxAddress; -use crate::chainstate::stacks::boot::test::{get_parent_tip, make_pox_4_lockup_chain_id}; +use crate::chainstate::stacks::boot::test::make_pox_4_lockup_chain_id; use crate::chainstate::stacks::db::{StacksChainState, *}; use crate::chainstate::stacks::tests::*; use crate::chainstate::stacks::{Error as ChainstateError, StacksMicroblockHeader, *}; -use crate::core::{EpochList, StacksEpoch, StacksEpochExtension, BOOT_BLOCK_HASH}; +use crate::core::{ + EpochList, StacksEpoch, StacksEpochExtension, BLOCK_LIMIT_MAINNET_21, BOOT_BLOCK_HASH, +}; use crate::net::relay::Relayer; use crate::net::test::TestEventObserver; +use crate::net::tests::NakamotoBootPlan; use crate::util_lib::boot::{boot_code_test_addr, boot_code_tx_auth}; use crate::util_lib::signed_structured_data::pox4::{ make_pox_4_signer_key_signature, Pox4SignatureTopic, @@ -363,55 +375,122 @@ impl<'a> TestChainstate<'a> { } } - // Advances a TestChainstate to the Nakamoto epoch - pub fn advance_to_nakamoto_epoch(&mut self, private_key: &StacksPrivateKey, nonce: &mut usize) { - let addr = StacksAddress::p2pkh(false, &StacksPublicKey::from_private(private_key)); - let default_pox_addr = - PoxAddress::from_legacy(AddressHashMode::SerializeP2PKH, addr.bytes().clone()); + /// Advances the chainstate to the specified epoch boundary by creating a tenure change block per burn block height. + /// Panics if already past the target epoch activation height. + pub fn advance_to_epoch_boundary( + &mut self, + private_key: &StacksPrivateKey, + target_epoch: StacksEpochId, + ) { + let mut burn_block_height = self.get_burn_block_height(); + let mut target_height = self + .config + .epochs + .as_ref() + .expect("Epoch configuration missing") + .iter() + .find(|e| e.epoch_id == target_epoch) + .expect("Target epoch not found") + .start_height; + + assert!( + burn_block_height <= target_height, + "Already advanced past target epoch ({target_epoch}) activation height ({target_height}). Current burn block height: {burn_block_height}." + ); + target_height = target_height.saturating_sub(1); - let mut sortition_height = self.get_burn_block_height(); - debug!("\n\n======================"); - debug!("PoxConstants = {:#?}", &self.config.burnchain.pox_constants); - debug!("tip = {sortition_height}"); - debug!("========================\n\n"); + debug!("Advancing to epoch {target_epoch} boundary at {target_height}. Current burn block height: {burn_block_height}"); let epoch_25_height = self .config .epochs .as_ref() - .unwrap() + .expect("Epoch configuration missing") .iter() - .find(|e| e.epoch_id == StacksEpochId::Epoch25) - .unwrap() - .start_height; + .find_map(|e| { + if e.epoch_id == StacksEpochId::Epoch25 { + Some(e.start_height) + } else { + None + } + }) + .unwrap_or(u64::MAX); let epoch_30_height = self .config .epochs .as_ref() - .unwrap() + .expect("Epoch configuration missing") .iter() - .find(|e| e.epoch_id == StacksEpochId::Epoch30) - .unwrap() - .start_height; + .find_map(|e| { + if e.epoch_id == StacksEpochId::Epoch30 { + Some(e.start_height) + } else { + None + } + }) + .unwrap_or(u64::MAX); - // Advance to just past PoX-4 instantiation - let mut blocks_produced = false; - while sortition_height <= epoch_25_height { - self.tenure_with_txs(&[], nonce); - sortition_height = self.get_burn_block_height(); - blocks_produced = true; + let epoch_30_reward_cycle = self + .config + .burnchain + .block_height_to_reward_cycle(epoch_30_height) + .unwrap_or(u64::MAX); + + let mut mined_pox_4_lockup = false; + while burn_block_height < target_height { + if burn_block_height < epoch_30_height - 1 { + let current_reward_cycle = self.get_reward_cycle(); + // Before we can mine pox 4 lockup, make sure we mine at least one block. + // If we have mined the lockup already, just mine a regular tenure + // Note, we cannot mine a pox 4 lockup, if it isn't activated yet + // And must mine it in the reward cycle directly prior to the Nakamoto + // activated reward cycle + if !mined_pox_4_lockup + && burn_block_height > self.config.current_block + && burn_block_height + 1 >= epoch_25_height + && current_reward_cycle + 1 == epoch_30_reward_cycle + { + debug!("Mining pox-4 lockup"); + self.mine_pox_4_lockup(private_key); + mined_pox_4_lockup = true; + } else { + debug!("Mining pre-nakamoto tenure"); + let stacks_block = self.mine_pre_nakamoto_tenure_with_txs(&[]); + let (stacks_tip_ch, stacks_tip_bh) = + SortitionDB::get_canonical_stacks_chain_tip_hash(self.sortdb().conn()) + .expect("Failed to get canonical chain tip"); + let stacks_tip = StacksBlockId::new(&stacks_tip_ch, &stacks_tip_bh); + assert_eq!(stacks_block, stacks_tip); + } + } else { + debug!("Mining post-nakamoto tenure"); + self.mine_nakamoto_tenure(); + } + burn_block_height = self.get_burn_block_height(); } + } - // Ensure at least one block is produced before PoX-4 lockups - if !blocks_produced { - self.tenure_with_txs(&[], nonce); - sortition_height = self.get_burn_block_height(); - } + /// This must be called after pox 4 activation and at or past the Epoch 2.5 boundary + fn mine_pox_4_lockup(&mut self, private_key: &StacksPrivateKey) { + let sortition_height = self.get_burn_block_height(); + let epoch_25_height = self + .config + .epochs + .as_ref() + .unwrap() + .iter() + .find(|e| e.epoch_id == StacksEpochId::Epoch25) + .unwrap() + .start_height; + assert!( + sortition_height + 1 >= epoch_25_height, + "Cannot mine pox-4 lockups if not at or past Epoch 2.5 boundary" + ); - debug!("\n\n======================"); - debug!("Make PoX-4 lockups"); - debug!("========================\n\n"); + let addr = StacksAddress::p2pkh(false, &StacksPublicKey::from_private(private_key)); + let default_pox_addr = + PoxAddress::from_legacy(AddressHashMode::SerializeP2PKH, addr.bytes().clone()); let reward_cycle = self .config @@ -460,49 +539,69 @@ impl<'a> TestChainstate<'a> { }) .collect(); - let stacks_block = self.tenure_with_txs(&stack_txs, nonce); + let stacks_block = self.mine_pre_nakamoto_tenure_with_txs(&stack_txs); let (stacks_tip_ch, stacks_tip_bh) = SortitionDB::get_canonical_stacks_chain_tip_hash(self.sortdb().conn()).unwrap(); let stacks_tip = StacksBlockId::new(&stacks_tip_ch, &stacks_tip_bh); assert_eq!(stacks_block, stacks_tip); + } - debug!("\n\n======================"); - debug!("Advance to the Prepare Phase"); - debug!("========================\n\n"); - - // Advance to the prepare phase - while !self.config.burnchain.is_in_prepare_phase(sortition_height) { - let (stacks_tip_ch, stacks_tip_bh) = - SortitionDB::get_canonical_stacks_chain_tip_hash(self.sortdb().conn()).unwrap(); - let old_tip = StacksBlockId::new(&stacks_tip_ch, &stacks_tip_bh); - let stacks_block = self.tenure_with_txs(&[], nonce); - let (stacks_tip_ch, stacks_tip_bh) = - SortitionDB::get_canonical_stacks_chain_tip_hash(self.sortdb().conn()).unwrap(); - let stacks_tip = StacksBlockId::new(&stacks_tip_ch, &stacks_tip_bh); - assert_ne!(old_tip, stacks_tip); - sortition_height = self.get_burn_block_height(); - } + /// Mines a new bitcoin block with a new tenure block-commit, using it to mine the start of a new Stacks Nakmoto tenure, + /// It will mine subsequently mine the coinbase and tenure change Stacks txs. + /// NOTE: mines a total of one Bitcoin block and one Stacks block. + fn mine_nakamoto_tenure(&mut self) { + let burn_block_height = self.get_burn_block_height(); + let (burn_ops, mut tenure_change, miner_key) = + self.begin_nakamoto_tenure(TenureChangeCause::BlockFound); + let (_, header_hash, consensus_hash) = self.next_burnchain_block(burn_ops); + let vrf_proof = self.make_nakamoto_vrf_proof(miner_key); + + tenure_change.tenure_consensus_hash = consensus_hash.clone(); + tenure_change.burn_view_consensus_hash = consensus_hash.clone(); + let tenure_change_tx = self.miner.make_nakamoto_tenure_change(tenure_change); + let coinbase_tx = self.miner.make_nakamoto_coinbase(None, vrf_proof); + + let blocks_and_sizes = self + .make_nakamoto_tenure(tenure_change_tx, coinbase_tx, Some(0)) + .unwrap(); + assert_eq!( + blocks_and_sizes.len(), + 1, + "Mined more than one Nakamoto block" + ); + } - debug!("\n\n======================"); - debug!("Advance to Epoch 3.0"); - debug!("========================\n\n"); - - // Advance to Epoch 3.0 - while sortition_height < epoch_30_height - 1 { - let (stacks_tip_ch, stacks_tip_bh) = - SortitionDB::get_canonical_stacks_chain_tip_hash(self.sortdb().conn()).unwrap(); - let old_tip = StacksBlockId::new(&stacks_tip_ch, &stacks_tip_bh); - self.tenure_with_txs(&[], nonce); - let (stacks_tip_ch, stacks_tip_bh) = - SortitionDB::get_canonical_stacks_chain_tip_hash(self.sortdb().conn()).unwrap(); - let stacks_tip = StacksBlockId::new(&stacks_tip_ch, &stacks_tip_bh); - assert_ne!(old_tip, stacks_tip); - sortition_height = self.get_burn_block_height(); + /// Advance a TestChainstate into the provided epoch. + /// Does nothing if chainstate is already in the target epoch. Panics if it is past the epoch. + pub fn advance_into_epoch( + &mut self, + private_key: &StacksPrivateKey, + target_epoch: StacksEpochId, + ) { + let burn_block_height = self.get_burn_block_height(); + let target_height = self + .config + .epochs + .as_ref() + .expect("Epoch configuration missing") + .iter() + .find(|e| e.epoch_id == target_epoch) + .expect("Target epoch not found") + .start_height; + assert!(burn_block_height <= target_height, "We cannot advance backwards. Examine your bootstrap setup. Current burn block height: {burn_block_height}. Target height: {target_height}"); + // Don't bother advancing to the boundary if we are already at it. + if burn_block_height < target_height { + self.advance_to_epoch_boundary(private_key, target_epoch); + if target_epoch < StacksEpochId::Epoch30 { + self.mine_pre_nakamoto_tenure_with_txs(&[]); + } else { + self.mine_nakamoto_tenure(); + } } - - debug!("\n\n======================"); - debug!("Welcome to Nakamoto!"); - debug!("========================\n\n"); + let burn_block_height = self.get_burn_block_height(); + debug!( + "Advanced into epoch {target_epoch}. Current burn block height: {burn_block_height}" + ); } pub fn get_burnchain_db(&self, readwrite: bool) -> BurnchainDB { @@ -1044,38 +1143,65 @@ impl<'a> TestChainstate<'a> { self.stacks_node.as_ref().unwrap() } - /// Make a tenure with the given transactions. Creates a coinbase tx with the given nonce, and then increments - /// the provided reference. - pub fn tenure_with_txs( + /// Mines a pre-naka tenure with the given transactions. Creates a coinbase tx. Processes the tenure + /// NOTE: mines one burnchain block and one Stacks block. + fn mine_pre_nakamoto_tenure_with_txs(&mut self, txs: &[StacksTransaction]) -> StacksBlockId { + let (burn_ops, stacks_block, microblocks) = self.make_pre_nakamoto_tenure_with_txs(txs); + + let (_, _, consensus_hash) = self.next_burnchain_block(burn_ops); + + self.process_stacks_epoch_at_tip(&stacks_block, µblocks); + + StacksBlockId::new(&consensus_hash, &stacks_block.block_hash()) + } + + /// Make a pre-naka tenure with the given transactions + pub fn make_pre_nakamoto_tenure_with_txs( &mut self, txs: &[StacksTransaction], - coinbase_nonce: &mut usize, - ) -> StacksBlockId { + ) -> ( + Vec, + StacksBlock, + Vec, + ) { let microblock_privkey = self.miner.next_microblock_privkey(); let microblock_pubkeyhash = Hash160::from_node_public_key(&StacksPublicKey::from_private(µblock_privkey)); - let tip = SortitionDB::get_canonical_burn_chain_tip(self.sortdb.as_ref().unwrap().conn()) - .unwrap(); let burnchain = self.config.burnchain.clone(); - - let (burn_ops, stacks_block, microblocks) = self.make_tenure( + self.make_tenure( |ref mut miner, ref mut sortdb, ref mut chainstate, vrf_proof, ref parent_opt, ref parent_microblock_header_opt| { - let parent_tip = get_parent_tip(parent_opt, chainstate, sortdb); - let coinbase_tx = make_coinbase(miner, *coinbase_nonce); + let tip = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn()).unwrap(); + let parent_tip = StacksChainState::get_anchored_block_header_info( + chainstate.db(), + &tip.canonical_stacks_tip_consensus_hash, + &tip.canonical_stacks_tip_hash, + ) + .unwrap() + .unwrap_or_else(|| { + StacksChainState::get_genesis_header_info(chainstate.db()).unwrap() + }); + + let coinbase_tx = make_coinbase(miner, tip.block_height.try_into().unwrap()); let mut block_txs = vec![coinbase_tx]; block_txs.extend_from_slice(txs); + let snapshot = sortdb + .index_handle_at_tip() + .get_block_snapshot(&parent_tip.burn_header_hash) + .unwrap() + .unwrap(); + let block_builder = StacksBlockBuilder::make_regtest_block_builder( &burnchain, &parent_tip, vrf_proof, - tip.total_burn, + snapshot.total_burn, µblock_pubkeyhash, ) .unwrap(); @@ -1084,21 +1210,98 @@ impl<'a> TestChainstate<'a> { block_builder, chainstate, &sortdb.index_handle(&tip.sortition_id), - block_txs, + block_txs.clone(), ) .unwrap(); + assert_eq!(anchored_block.txs.len(), block_txs.len()); (anchored_block, vec![]) }, + ) + } + + /// Calculate blockstack ops for the given stacks and burn blocks + pub fn calculate_block_ops( + &mut self, + sortition_tip: &BlockSnapshot, + burn_block: &mut TestBurnchainBlock, + last_key: &LeaderKeyRegisterOp, + stacks_block: &StacksBlock, + microblocks: Vec, + parent_block_snapshot_opt: Option<&BlockSnapshot>, + ) -> Vec { + let mut sortdb = self.sortdb.take().unwrap(); + let mut stacks_node = self.stacks_node.take().unwrap(); + + let mut block_commit_op = stacks_node.make_tenure_commitment( + &sortdb, + burn_block, + &mut self.miner, + stacks_block, + microblocks, + 1000, + last_key, + parent_block_snapshot_opt, ); - let (_, _, consensus_hash) = self.next_burnchain_block(burn_ops); - self.process_stacks_epoch_at_tip(&stacks_block, µblocks); + // patch up block-commit -- these blocks all mine off of genesis + if stacks_block.header.parent_block == BlockHeaderHash([0u8; 32]) { + block_commit_op.parent_block_ptr = 0; + block_commit_op.parent_vtxindex = 0; + } - *coinbase_nonce += 1; + let leader_key_op = stacks_node.add_key_register(burn_block, &mut self.miner); - StacksBlockId::new(&consensus_hash, &stacks_block.block_hash()) - } + // patch in reward set info + let recipients = get_next_recipients( + &sortition_tip, + &mut stacks_node.chainstate, + &mut sortdb, + &self.config.burnchain, + &OnChainRewardSetProvider::new(), + ) + .unwrap_or_else(|e| panic!("Failure fetching recipient set: {e:?}")); + block_commit_op.commit_outs = match recipients { + Some(info) => { + let mut recipients = info + .recipients + .into_iter() + .map(|x| x.0) + .collect::>(); + if recipients.len() == 1 { + recipients.push(PoxAddress::standard_burn_address(false)); + } + recipients + } + None => { + if self + .config + .burnchain + .is_in_prepare_phase(burn_block.block_height) + { + vec![PoxAddress::standard_burn_address(false)] + } else { + vec![ + PoxAddress::standard_burn_address(false), + PoxAddress::standard_burn_address(false), + ] + } + } + }; + // Put everything back + self.stacks_node = Some(stacks_node); + self.sortdb = Some(sortdb); + debug!( + "Block commit at height {} has {} recipients: {:?}", + block_commit_op.block_height, + block_commit_op.commit_outs.len(), + &block_commit_op.commit_outs + ); + vec![ + BlockstackOperationType::LeaderKeyRegister(leader_key_op), + BlockstackOperationType::LeaderBlockCommit(block_commit_op), + ] + } /// Make a tenure, using `tenure_builder` to generate a Stacks block and a list of /// microblocks. pub fn make_tenure( @@ -1125,8 +1328,11 @@ impl<'a> TestChainstate<'a> { let mut burn_block = TestBurnchainBlock::new(&tip, 0); let mut stacks_node = self.stacks_node.take().unwrap(); - let parent_block_opt = stacks_node.get_last_anchored_block(&self.miner); - let parent_sortition_opt = parent_block_opt.as_ref().and_then(|parent_block| { + let parent_block_opt = stacks_node + .anchored_blocks + .iter() + .find(|block| block.block_hash() == tip.canonical_stacks_tip_hash); + let parent_sortition_opt = parent_block_opt.and_then(|parent_block| { let ic = sortdb.index_conn(); SortitionDB::get_block_snapshot_for_winning_stacks_block( &ic, @@ -1137,7 +1343,7 @@ impl<'a> TestChainstate<'a> { }); let parent_microblock_header_opt = - get_last_microblock_header(&stacks_node, &self.miner, parent_block_opt.as_ref()); + get_last_microblock_header(&stacks_node, &self.miner, parent_block_opt); let last_key = stacks_node.get_last_key(&self.miner); let network_id = self.config.network_id; @@ -1157,82 +1363,21 @@ impl<'a> TestChainstate<'a> { &mut sortdb, &mut stacks_node.chainstate, &proof, - parent_block_opt.as_ref(), + parent_block_opt, parent_microblock_header_opt.as_ref(), ); - let mut block_commit_op = stacks_node.make_tenure_commitment( - &sortdb, + self.stacks_node = Some(stacks_node); + self.sortdb = Some(sortdb); + let block_ops = self.calculate_block_ops( + &tip, &mut burn_block, - &mut self.miner, + &last_key, &stacks_block, microblocks.clone(), - 1000, - &last_key, parent_sortition_opt.as_ref(), ); - - // patch up block-commit -- these blocks all mine off of genesis - if stacks_block.header.parent_block == BlockHeaderHash([0u8; 32]) { - block_commit_op.parent_block_ptr = 0; - block_commit_op.parent_vtxindex = 0; - } - - let leader_key_op = stacks_node.add_key_register(&mut burn_block, &mut self.miner); - - // patch in reward set info - let recipients = get_next_recipients( - &tip, - &mut stacks_node.chainstate, - &mut sortdb, - &self.config.burnchain, - &OnChainRewardSetProvider::new(), - ) - .unwrap_or_else(|e| panic!("Failure fetching recipient set: {e:?}")); - block_commit_op.commit_outs = match recipients { - Some(info) => { - let mut recipients = info - .recipients - .into_iter() - .map(|x| x.0) - .collect::>(); - if recipients.len() == 1 { - recipients.push(PoxAddress::standard_burn_address(false)); - } - recipients - } - None => { - if self - .config - .burnchain - .is_in_prepare_phase(burn_block.block_height) - { - vec![PoxAddress::standard_burn_address(false)] - } else { - vec![ - PoxAddress::standard_burn_address(false), - PoxAddress::standard_burn_address(false), - ] - } - } - }; - test_debug!( - "Block commit at height {} has {} recipients: {:?}", - block_commit_op.block_height, - block_commit_op.commit_outs.len(), - &block_commit_op.commit_outs - ); - - self.stacks_node = Some(stacks_node); - self.sortdb = Some(sortdb); - ( - vec![ - BlockstackOperationType::LeaderKeyRegister(leader_key_op), - BlockstackOperationType::LeaderBlockCommit(block_commit_op), - ], - stacks_block, - microblocks, - ) + (block_ops, stacks_block, microblocks) } pub fn get_burn_block_height(&self) -> u64 { @@ -1518,4 +1663,308 @@ impl<'a> TestChainstate<'a> { self.stacks_node = Some(stacks_node); Ok(block_data) } + + /// Create an epoch list for testing Epoch 2.5 onwards + pub fn epoch_2_5_onwards(first_burnchain_height: u64) -> EpochList { + info!( + "StacksEpoch 2.5 onwards unit test first_burnchain_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_5, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch30, + start_height: first_burnchain_height, + end_height: first_burnchain_height + 1, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch31, + start_height: first_burnchain_height + 1, + end_height: first_burnchain_height + 2, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_1, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch32, + start_height: first_burnchain_height + 2, + end_height: first_burnchain_height + 3, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_2, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch33, + start_height: first_burnchain_height + 3, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_3, + }, + ]) + } + + pub fn all_epochs(first_burnchain_height: u64) -> EpochList { + info!("StacksEpoch all_epochs 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 + 1, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_2_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch2_05, + start_height: first_burnchain_height + 1, + end_height: first_burnchain_height + 2, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_2_05, + }, + StacksEpoch { + // Give a few extra blocks for pre naka blocks + // Since we may want to create multiple stacks blocks + // per epoch (especially for clarity version testing) + epoch_id: StacksEpochId::Epoch21, + start_height: first_burnchain_height + 2, + end_height: first_burnchain_height + 4, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_2_1, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch22, + start_height: first_burnchain_height + 4, + end_height: first_burnchain_height + 8, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_2_2, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch23, + start_height: first_burnchain_height + 8, + end_height: first_burnchain_height + 12, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_2_3, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch24, + start_height: first_burnchain_height + 12, + end_height: first_burnchain_height + 16, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_2_4, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch25, + // Give an extra couple burn blocks for epoch 25 to activate pox-4 + start_height: first_burnchain_height + 16, + end_height: first_burnchain_height + 22, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_2_5, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch30, + start_height: first_burnchain_height + 22, + end_height: first_burnchain_height + 23, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_0, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch31, + start_height: first_burnchain_height + 23, + end_height: first_burnchain_height + 24, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_1, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch32, + start_height: first_burnchain_height + 24, + end_height: first_burnchain_height + 25, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_2, + }, + StacksEpoch { + epoch_id: StacksEpochId::Epoch33, + start_height: first_burnchain_height + 25, + end_height: STACKS_EPOCH_MAX, + block_limit: BLOCK_LIMIT_MAINNET_21.clone(), + network_epoch: PEER_VERSION_EPOCH_3_2, + }, + ]) + } +} + +#[test] +/// Tests that we can instantiate a chainstate from nothing and advance sequentially through every epoch +fn advance_through_all_epochs() { + let privk = StacksPrivateKey::random(); + let mut boot_plan = NakamotoBootPlan::new(function_name!()) + .with_pox_constants(7, 1) + .with_private_key(privk.clone()); + let first_burnchain_height = (boot_plan.pox_constants.pox_4_activation_height + + boot_plan.pox_constants.reward_cycle_length + + 1) as u64; + + let epochs = TestChainstate::all_epochs(first_burnchain_height); + boot_plan = boot_plan.with_epochs(epochs); + let mut chainstate = boot_plan.to_chainstate(None, Some(first_burnchain_height)); + 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::Epoch20); + + // Make sure we can advance through every single epoch. + for target_epoch in [ + StacksEpochId::Epoch2_05, + StacksEpochId::Epoch21, + StacksEpochId::Epoch22, + StacksEpochId::Epoch23, + StacksEpochId::Epoch24, + StacksEpochId::Epoch25, + StacksEpochId::Epoch30, + StacksEpochId::Epoch31, + StacksEpochId::Epoch32, + StacksEpochId::Epoch33, + ] { + chainstate.advance_to_epoch_boundary(&privk, target_epoch); + 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!(current_epoch < target_epoch); + let next_epoch = + SortitionDB::get_stacks_epoch(chainstate.sortdb().conn(), burn_block_height + 1) + .unwrap() + .unwrap() + .epoch_id; + assert_eq!(next_epoch, target_epoch); + } +} + +#[test] +/// Tests that we can instantiate a chainstate from nothing and +/// bootstrap to nakamoto +fn advance_to_nakamoto_bootstrapped() { + let privk = StacksPrivateKey::random(); + let mut boot_plan = NakamotoBootPlan::new(function_name!()) + .with_pox_constants(7, 1) + .with_private_key(privk.clone()); + let epochs = TestChainstate::epoch_2_5_onwards( + (boot_plan.pox_constants.pox_4_activation_height + + boot_plan.pox_constants.reward_cycle_length + + 1) as u64, + ); + boot_plan = boot_plan.with_epochs(epochs); + let mut chainstate = boot_plan.to_chainstate(None, None); + chainstate.advance_to_epoch_boundary(&privk, StacksEpochId::Epoch30); + 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::Epoch25); + let next_epoch = + SortitionDB::get_stacks_epoch(chainstate.sortdb().conn(), burn_block_height + 1) + .unwrap() + .unwrap() + .epoch_id; + assert_eq!(next_epoch, StacksEpochId::Epoch30); +} + +#[test] +/// Tests that we can instantiate a chainstate from nothing and +/// bootstrap directly from nakamoto and across it +fn advance_through_nakamoto_bootstrapped() { + let privk = StacksPrivateKey::random(); + let mut boot_plan = NakamotoBootPlan::new(function_name!()) + .with_pox_constants(7, 1) + .with_private_key(privk.clone()); + let epochs = TestChainstate::epoch_2_5_onwards( + (boot_plan.pox_constants.pox_4_activation_height + + boot_plan.pox_constants.reward_cycle_length + + 1) as u64, + ); + let activation_height = boot_plan.pox_constants.pox_4_activation_height; + 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); + 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); + let next_epoch = + SortitionDB::get_stacks_epoch(chainstate.sortdb().conn(), burn_block_height + 1) + .unwrap() + .unwrap() + .epoch_id; + assert_eq!(next_epoch, StacksEpochId::Epoch33); } diff --git a/stackslib/src/chainstate/tests/parse_tests.rs b/stackslib/src/chainstate/tests/parse_tests.rs new file mode 100644 index 00000000000..c5aae11701a --- /dev/null +++ b/stackslib/src/chainstate/tests/parse_tests.rs @@ -0,0 +1,547 @@ +// Copyright (C) 2025 Stacks Open Internet Foundation +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! This module contains consensus tests related to Clarity Parse errors. + +use std::collections::HashMap; + +use clarity::vm::ast::errors::ParseErrorKind; +use clarity::vm::ast::parser::v2::{MAX_CONTRACT_NAME_LEN, MAX_NESTING_DEPTH, MAX_STRING_LEN}; +use clarity::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; +use clarity::vm::types::MAX_VALUE_SIZE; +use clarity::vm::MAX_CALL_STACK_DEPTH; + +use crate::chainstate::tests::consensus::{ + clarity_versions_for_epoch, contract_deploy_consensus_test, ConsensusTest, ConsensusUtils, + TestBlock, EPOCHS_TO_TEST, +}; +use crate::core::BLOCK_LIMIT_MAINNET_21; + +/// Generates a coverage classification report for a specific [`ParseErrorKind`] variant. +/// +/// This method exists purely for **documentation and tracking purposes**. +/// It helps maintainers understand which error variants have been: +/// +/// - ✅ **Tested** — verified through consensus tests. +/// - ⚙️ **Ignored** — not tested on purpose. (e.g. parser v1 errors). +/// - 🚫 **Unreachable** — not testable from consensus test side for reasons. +#[allow(dead_code)] +fn variant_coverage_report(variant: ParseErrorKind) { + enum VariantCoverage { + // Cannot occur through valid execution. The string is to explain the reason. + Unreachable_Functionally(&'static str), + // Unexpected error, that should never happen + Unreachable_ExpectLike, + // Defined but never used + Unreachable_NotUsed, + // Not tested on purpose. The string is to explain the reason. + Ignored(&'static str), + // Covered by consensus tests. The func lists is for to link the variant with the related tests + Tested(Vec), + } + + use ParseErrorKind::*; + use VariantCoverage::*; + + _ = match variant { + // Costs + CostOverflow => Unreachable_ExpectLike, + CostBalanceExceeded(_, _) => Tested(vec![test_cost_balance_exceeded]), + MemoryBalanceExceeded(_, _) => Unreachable_NotUsed, + CostComputationFailed(_) => Unreachable_ExpectLike, + ExecutionTimeExpired => Unreachable_NotUsed, + + TooManyExpressions => Unreachable_ExpectLike, + ExpressionStackDepthTooDeep => Tested(vec![ + test_stack_depth_too_deep_case_2_list_only_parsing, + test_stack_depth_too_deep_case_2_list_only_parsing, + test_stack_depth_too_deep_case_3_list_only_checker, + ]), + VaryExpressionStackDepthTooDeep => Tested(vec![test_vary_stack_depth_too_deep_checker]), + FailedParsingIntValue(_) => Tested(vec![test_failed_parsing_int_value]), + CircularReference(_) => Tested(vec![test_circular_reference]), + NameAlreadyUsed(_) => Tested(vec![test_named_already_used]), + TraitReferenceNotAllowed => Tested(vec![test_trait_ref_not_allowed]), + ImportTraitBadSignature => Tested(vec![test_import_trait_bad_signature]), + DefineTraitBadSignature => Tested(vec![test_define_trait_bad_signature]), + ImplTraitBadSignature => Tested(vec![test_impl_trait_bad_signature]), + TraitReferenceUnknown(_) => Tested(vec![test_trait_reference_unknown]), + Lexer(LexerError) => Tested(vec![test_lexer_unknown_symbol]), + ContractNameTooLong(String) => Tested(vec![test_contract_name_too_long]), + ExpectedClosing(Token) => Tested(vec![test_expected_closing]), + ExpectedContractIdentifier => Tested(vec![test_expected_contract_identifier]), + ExpectedTraitIdentifier => Tested(vec![test_expected_trait_identifier]), + ExpectedWhitespace => Tested(vec![test_expected_white_space]), + FailedParsingUIntValue(_) => Tested(vec![test_failed_parsing_uint_value]), + IllegalTraitName(_) => Unreachable_Functionally("prevented by Lexer checks returning `Lexer` variant"), + InvalidPrincipalLiteral => Tested(vec![test_invalid_principal_literal]), + InvalidBuffer => Unreachable_Functionally("prevented by both Lexer checks, and StacksTransaction::consensus_serialize with MAX_TRANSACTION_LEN (panic)"), + NameTooLong(_) => Tested(vec![test_name_too_long]), + UnexpectedToken(_) => Tested(vec![test_unexpected_token]), + TupleColonExpectedv2 => Tested(vec![test_tuple_colon_expected_v2]), + TupleCommaExpectedv2 => Tested(vec![test_tuple_comma_expected_v2]), + TupleValueExpected => Tested(vec![test_tuple_value_expected]), + IllegalClarityName(_) => Unreachable_Functionally("prevented by Lexer checks returning `Lexer` variant"), + IllegalASCIIString(_) => Tested(vec![test_illegal_ascii_string]), + IllegalContractName(_) => Unreachable_Functionally("prevented by Lexer checks returning `Lexer` variant or Parser by MAX_CONTRACT_NAME_LEN returning `ContractNameTooLong` variant"), + NoteToMatchThis(_) => Unreachable_Functionally("It is reachable, but only visible in diagnostic mode as it comes as a later diagnostic error"), + UnexpectedParserFailure => Unreachable_ExpectLike, + InterpreterFailure => Unreachable_ExpectLike, // currently cause block rejection + + // V1 + FailedCapturingInput + | SeparatorExpected(_) + | SeparatorExpectedAfterColon(_) + | ProgramTooLarge + | IllegalVariableName(_) + | FailedParsingBuffer(_) + | FailedParsingHexValue(_, _) + | FailedParsingPrincipal(_) + | FailedParsingField(_) + | FailedParsingRemainder(_) + | ClosingParenthesisUnexpected + | ClosingParenthesisExpected + | ClosingTupleLiteralUnexpected + | ClosingTupleLiteralExpected + | TupleColonExpected(_) + | TupleCommaExpected(_) + | TupleItemExpected(_) + | CommaSeparatorUnexpected + | ColonSeparatorUnexpected + | InvalidCharactersDetected + | InvalidEscaping => Ignored("parser v1 is deprecated and maybe removed in the next future."), + } +} + +/// ParserError: [`ParseErrorKind::CostBalanceExceeded`] +/// Caused by: exceeding runtime cost limit [`BLOCK_LIMIT_MAINNET_21`] during contract deploy parsing +/// Outcome: block rejected +/// Note: This cost error is remapped as [`crate::chainstate::stacks::Error::CostOverflowError`] +#[test] +fn test_cost_balance_exceeded() { + const RUNTIME_LIMIT: u64 = BLOCK_LIMIT_MAINNET_21.runtime as u64; + // Arbitrary parameters determined through empirical testing + const CONTRACT_FUNC_INVOCATIONS: u64 = 29_022; + const CALL_RUNTIME_COST: u64 = 249_996_284; + const CALLS_NEEDED: u64 = RUNTIME_LIMIT / CALL_RUNTIME_COST - 1; + + let costly_contract_code = { + let mut code = String::from( + "(define-constant msg 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f)\n\ + (define-constant sig 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40)\n\ + (define-constant key 0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0df)\n\ + (define-read-only (costly-func)\n (begin\n", + ); + for _ in 0..CONTRACT_FUNC_INVOCATIONS { + code.push_str(" (secp256k1-verify msg sig key)\n"); + } + code.push_str(" true))"); + code + }; + + let large_contract_code = &{ + let mut code = String::new(); + for i in 0..50_000u64 { + code.push_str(&format!("(define-public (gen-fn-{i}) (ok {i}))\n", i = i)); + } + code + }; + + let mut result = vec![]; + for each_epoch in EPOCHS_TO_TEST { + for &each_clarity_ver in clarity_versions_for_epoch(*each_epoch) { + let mut nonce = 0; + let mut txs = vec![]; + + // Create a contract that will be costly to execute + txs.push(ConsensusUtils::new_deploy_tx( + nonce, + "costly-contract", + &costly_contract_code, + None, + )); + + // Create contract calls that push the runtime cost to a considerably high value + while nonce < CALLS_NEEDED { + nonce += 1; + txs.push(ConsensusUtils::new_call_tx( + nonce, + "costly-contract", + "costly-func", + )); + } + + // Create a large contract that push the runtime cost close to the limit + nonce += 1; + txs.push(ConsensusUtils::new_deploy_tx( + nonce, + "runtime-close", + large_contract_code, + None, + )); + + // Create a large contract that exceeds the runtime cost limit during parsing + // NOTE: This is the only transaction relevant for demonstrating the runtime cost exceeding the limit during parsing. + // Previous transactions are included only for test setup. Hence, clarity version is used here. + nonce += 1; + txs.push(ConsensusUtils::new_deploy_tx( + nonce, + "runtime-exceeded", + large_contract_code, + Some(each_clarity_ver), + )); + + let block = TestBlock { transactions: txs }; + + let epoch_blocks = HashMap::from([(*each_epoch, vec![block])]); + + let each_result = ConsensusTest::new(function_name!(), vec![], epoch_blocks).run(); + result.extend(each_result); + } + } + + insta::assert_ron_snapshot!(result); +} + +/// ParserError: [`ParseErrorKind::ExpressionStackDepthTooDeep`] +/// Caused by: nested contract body exceeding stack depth limit on parsing tuples +/// Outcome: block rejected +#[test] +fn test_stack_depth_too_deep_case_1_tuple_only_parsing() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: &{ + // In parse v2, open brace '{' have a stack count of 2. + let count = MAX_NESTING_DEPTH / 2 + 1; + let body_start = "{ a : ".repeat(count as usize); + let body_end = "} ".repeat(count as usize); + format!("{body_start}u1 {body_end}") + }, + ); +} + +/// ParserError: [`ParseErrorKind::ExpressionStackDepthTooDeep`] +/// Caused by: nested contract body exceeding stack depth limit on parsing lists +/// Outcome: block rejected +#[test] +fn test_stack_depth_too_deep_case_2_list_only_parsing() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: &{ + // In parse v2, open parenthesis '(' have a stack count of 1. + let count = MAX_NESTING_DEPTH; + let body_start = "(list ".repeat(count as usize); + let body_end = ")".repeat(count as usize); + format!("{body_start}u1 {body_end}") + }, + ); +} + +/// ParserError: [`ParseErrorKind::ExpressionStackDepthTooDeep`] +/// Caused by: nested contract body exceeding stack depth limit on checking lists ast +/// Outcome: block rejected +#[test] +fn test_stack_depth_too_deep_case_3_list_only_checker() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: &{ + // In parse v2, open parenthesis '(' have a stack count of 1. + let count = AST_CALL_STACK_DEPTH_BUFFER + MAX_CALL_STACK_DEPTH as u64; + let body_start = "(list ".repeat(count as usize); + let body_end = ")".repeat(count as usize); + format!("{body_start}u1 {body_end}") + }, + ); +} + +/// ParserError: [`ParseErrorKind::VaryExpressionStackDepthTooDeep`] +/// Caused by: nested contract body exceeding stack depth limit on checking vary list/tuple ast +/// Outcome: block rejected +#[test] +fn test_vary_stack_depth_too_deep_checker() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: &{ + let count = AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64) - 1; + let body_start = "(list ".repeat(count as usize); + let body_end = ")".repeat(count as usize); + format!("{{ a: {body_start}u1 {body_end} }}") + }, + ); +} + +/// ParserError: [`ParseErrorKind::FailedParsingIntValue`] +/// Caused by: number bigger than i128 +/// Outcome: block accepted +#[test] +fn test_failed_parsing_int_value() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(define-data-var my-int int 340282366920938463463374607431768211455)", + ); +} + +/// ParserError [`ParseErrorKind::FailedParsingUIntValue`] +/// Caused by: number bigger than u128 +/// Outcome: block accepted +#[test] +fn test_failed_parsing_uint_value() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(define-data-var my-uint uint u999340282366920938463463374607431768211455)", + ); +} + +/// ParserError [`ParseErrorKind::CircularReference`] +/// Caused by: interdependent functions +/// Outcome: block accepted +#[test] +fn test_circular_reference() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: " + (define-constant my-a my-b) + (define-constant my-b my-a) + ", + ); +} + +/// ParserError [`ParseErrorKind::NameAlreadyUsed`] +/// Caused by: trait name conflicts only +/// Outcome: block accepted +#[test] +fn test_named_already_used() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: " + (define-trait trait-1 ( + (get-1 (uint) (response uint uint)))) + (define-trait trait-1 ( + (get-1 (int) (response uint uint)))) + ", + ); +} + +/// ParserError [`ParseErrorKind::TraitReferenceNotAllowed`] +/// Caused by: trait reference can not be stored +/// Outcome: block accepted +#[test] +fn test_trait_ref_not_allowed() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: " + (define-trait trait-1 ( + (get-1 (uint) (response uint uint)))) + (define-map kv-store { key: uint } { value: }) + ", + ); +} + +/// ParserError [`ParseErrorKind::ImportTraitBadSignature`] +/// Caused by: trait import with bad signature (missing trait name or identifier) +/// Outcome: block accepted +#[test] +fn test_import_trait_bad_signature() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(use-trait)", + ); +} + +/// ParserError [`ParseErrorKind::DefineTraitBadSignature`] +/// Caused by: trait define with bad signature (missing trait name or definition) +/// Outcome: block accepted +#[test] +fn test_define_trait_bad_signature() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(define-trait)", + ); +} + +/// ParserError [`ParseErrorKind::ImplTraitBadSignature`] +/// Caused by: trait implementation with bad signature (missing trait identifier) +/// Outcome: block accepted +#[test] +fn test_impl_trait_bad_signature() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(impl-trait)", + ); +} + +/// ParserError [`ParseErrorKind::TraitReferenceUnknown`] +/// Caused by: referencing an undeclared trait +/// Outcome: block accepted +#[test] +fn test_trait_reference_unknown() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(+ 1 )", + ); +} + +/// ParserError: [`ParseErrorKind::Lexer`] +/// Caused by: unknown symbol +/// Outcome: block accepted +#[test] +fn test_lexer_unknown_symbol() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(define-data-var my-uint uint _)", + ); +} + +/// ParserError: [`ParseErrorKind::ExpectedClosing`] +/// Caused by: missing closing parenthesis +/// Outcome: block accepted +#[test] +fn test_expected_closing() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(", + ); +} + +/// ParserError: [`ParseErrorKind::ExpectedWhitespace`] +/// Caused by: missing space before expression +/// Outcome: block accepted +#[test] +fn test_expected_white_space() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + //miss space between (get-one) and (ok u1) + contract_code: "(define-public (get-one)(ok u1))", + ); +} + +/// ParserError: [`ParseErrorKind::UnexpectedToken`] +/// Caused by: unexpected token in the expression (rightest paranthesis) +/// Outcome: block accepted +#[test] +fn test_unexpected_token() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(define-public (get-one) (ok u1)) )", + ); +} + +/// ParserError: [`ParseErrorKind::NameTooLong`] +/// Caused by: identifier longer than [`MAX_STRING_LEN`] +/// Outcome: block accepted +#[test] +fn test_name_too_long() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: &{ + let name = "n".repeat(MAX_STRING_LEN + 1); + format!("(define-public ({name}) (ok u1))") + }, + ); +} + +/// ParserError: [`ParseErrorKind::InvalidPrincipalLiteral`] +/// Caused by: valid principal chars but wrong format (due to the starting "AAA") +/// Outcome: block accepted +#[test] +fn test_invalid_principal_literal() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(define-constant my-principal 'AAAST3J2GVMMM2R07ZFBJDWTYEYAR8FZH5WKDTFJ9AHA)", + ); +} + +/// ParserError: [`ParseErrorKind::ExpectedContractIdentifier`] +/// Caused by: missing name in contract identifier (nothing after the dot '.') +/// Outcome: block accepted +#[test] +fn test_expected_contract_identifier() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(define-constant my-contract-id 'ST3J2GVMMM2R07ZFBJDWTYEYAR8FZH5WKDTFJ9AHA.)", + ); +} + +/// ParserError: [`ParseErrorKind::ExpectedTraitIdentifier`] +/// Caused by: missing name in trait identifier (nothing after the dot '.') +/// Outcome: block accepted +#[test] +fn test_expected_trait_identifier() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "(define-constant my-trait-id 'ST3J2GVMMM2R07ZFBJDWTYEYAR8FZH5WKDTFJ9AHA.contract.)", + ); +} + +/// ParserError: [`ParseErrorKind::TupleColonExpectedv2`] +/// Caused by: missing colon between field name and value in tuple definition +/// Outcome: block accepted +#[test] +fn test_tuple_colon_expected_v2() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "{ a 1 }", + ); +} + +/// ParserError: [`ParseErrorKind::TupleCommaExpectedv2`] +/// Caused by: missing comma between fields in tuple definition +/// Outcome: block accepted +#[test] +fn test_tuple_comma_expected_v2() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "{ a : 1 b : 2 }", + ); +} + +/// ParserError: [`ParseErrorKind::TupleValueExpected`] +/// Caused by: missing value for field in tuple definition +/// Outcome: block accepted +#[test] +fn test_tuple_value_expected() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: "{ a : ", + ); +} + +/// ParserError: [`ParseErrorKind::ContractNameTooLong`] +/// Caused by: contract name longer than [`MAX_CONTRACT_NAME_LEN`] +/// Outcome: block accepted +#[test] +fn test_contract_name_too_long() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: &{ + let name = "a".repeat(MAX_CONTRACT_NAME_LEN + 1); + format!("(define-constant my-contract-id 'ST3J2GVMMM2R07ZFBJDWTYEYAR8FZH5WKDTFJ9AHA.{name})") + }, + ); +} + +/// ParserError: [`ParseErrorKind::IllegalASCIIString`] +/// Caused by: string longer than [`MAX_VALUE_SIZE`] +/// Outcome: block accepted +#[test] +fn test_illegal_ascii_string() { + contract_deploy_consensus_test!( + contract_name: "my-contract", + contract_code: &{ + let string = "a".repeat(MAX_VALUE_SIZE as usize + 1); + format!("(define-constant my-str \"{string}\")") + }, + ); +} diff --git a/stackslib/src/chainstate/tests/runtime_analysis_tests.rs b/stackslib/src/chainstate/tests/runtime_analysis_tests.rs new file mode 100644 index 00000000000..b6d95ff7d43 --- /dev/null +++ b/stackslib/src/chainstate/tests/runtime_analysis_tests.rs @@ -0,0 +1,774 @@ +// Copyright (C) 2025 Stacks Open Internet Foundation +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! This module contains consensus tests related to Clarity CheckErrorKind errors that happens during runtime analysis. + +use std::collections::HashMap; + +use clarity::types::StacksEpochId; +#[allow(unused_imports)] +use clarity::vm::analysis::CheckErrorKind; +use clarity::vm::types::{QualifiedContractIdentifier, MAX_TYPE_DEPTH}; +use clarity::vm::{ClarityVersion, Value as ClarityValue}; + +use crate::chainstate::tests::consensus::{ + contract_call_consensus_test, contract_deploy_consensus_test, ConsensusTest, ConsensusUtils, + SetupContract, TestBlock, EPOCHS_TO_TEST, FAUCET_ADDRESS, FAUCET_PRIV_KEY, +}; +use crate::core::test_util::to_addr; +use crate::core::BLOCK_LIMIT_MAINNET_21; + +/// TODO: Documentation to be added to the enum +/// - PublicFunctionNotReadOnly: Functionally Unreachable. Environment::inner_execute_contract is invoked with read_only = false on the relevant code path, causing PublicFunctionNotReadOnly check to be skipped. +/// - NoSuchPublicFunction: Tested. Possible only during contract call. On contract deploy checked during static analysis +/// - CircularReference: Tested. Possible only during contract call. On contract deploy checked during parsing. +/// - PublicFunctionMustReturnResponse: Functionally Unreachable. On contract deploy checked during static analysis. +/// - BadFunctionName: Functionally Unreachable. On contract deploy checked during static analysis. +/// - DefineFunctionBadSignature: Functionally Unreachable. On contract deploy checked during static analysis. +/// - NoSuchMap: Functionally Unreachable. On contract deploy checked during static analysis. (At runtime, just used for loading cost functions on block begin) +/// - NoSuchDataVariable: Functionally Unreachable. On contract deploy checked during static analysis. (At runtime, just used for loading cost functions on block begin and for handle prepare phase) +/// - EmptyTuplesNotAllowed: Functionally Unreachable. On contract deploy checked during static analysis. (At runtime, just used for loading cost functions on block begin) +/// - NoSuchTupleField: Functionally Unreachable. On contract deploy checked during static analysis. + +/// CheckErrorKind: [`CheckErrorKind::CostBalanceExceeded`] +/// Caused by: exceeding the cost analysis budget during contract initialization. +/// The contract repeatedly performs `var-get` lookups on a data variable, +/// forcing the type checker to fetch the variable enough times to exceed +/// the read-count limit in [`BLOCK_LIMIT_MAINNET_21`]. +/// Outcome: block rejected. +#[test] +fn check_error_cost_balance_exceeded_cdeploy() { + contract_deploy_consensus_test!( + contract_name: "cost-balance-exceeded", + contract_code: &format!(" + (define-data-var foo int 1) + (begin + {} + )", + "(var-get foo)\n".repeat(BLOCK_LIMIT_MAINNET_21.read_count as usize + 1) + ), + ); +} + +/// CheckErrorKind: [`CheckErrorKind::CostBalanceExceeded`] +/// Caused by: exceeding the cost analysis budget during contract initialization. +/// The contract repeatedly performs `var-get` lookups on a data variable, +/// forcing the type checker to fetch the variable enough times to exceed +/// the read-count limit in [`BLOCK_LIMIT_MAINNET_21`]. +/// Outcome: block rejected. +#[test] +fn check_error_cost_balance_exceeded_ccall() { + contract_call_consensus_test!( + contract_name: "cost-balance-exceeded", + contract_code: &format!(" + (define-data-var foo int 1) + (define-public (trigger-error) + (ok (begin + {} + u0)))", + "(var-get foo)\n".repeat(BLOCK_LIMIT_MAINNET_21.read_count as usize + 1) + ), + function_name: "trigger-error", + function_args: &[], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchPublicFunction`] +/// Caused by: Attempted to invoke a private function from outside the contract. +/// Outcome: block accepted +#[test] +fn check_error_kind_no_such_public_function_ccall() { + contract_call_consensus_test!( + contract_name: "target-contract", + contract_code: "(define-private (get-one) (ok u1))", + function_name: "get-one", + function_args: &[], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NameAlreadyUsed`] +/// Caused by: name is already used by a standard clarity function. +/// Outcome: block rejected. +#[test] +fn check_error_kind_name_already_used_cdeploy() { + contract_deploy_consensus_test!( + contract_name: "name-already-used", + contract_code: "(define-private (ft-get-supply) 1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NameAlreadyUsed`] +/// Caused by: a `let` binding attempts to shadow the reserved keyword `stacks-block-height`. +/// The analyzer accepts the contract, but binding happens only when the public +/// function executes, so the runtime raises `NameAlreadyUsed`. +/// Outcome: block accepted. +#[test] +fn check_error_kind_name_already_used_ccall() { + contract_call_consensus_test!( + contract_name: "name-already-used", + contract_code: " + (define-public (trigger-error) + (let ((ft-get-supply u0)) + (ok ft-get-supply)))", + function_name: "trigger-error", + function_args: &[], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ValueTooLarge`] +/// Caused by: `(as-max-len? …)` wraps a buffer whose serialized size plus the optional wrapper +/// exceeds `MAX_VALUE_SIZE`. Static analysis allows this construction, but initialization fails +/// at runtime when `Value::some` detects the oversized payload. +/// Outcome: block accepted. +#[test] +fn check_error_kind_value_too_large_cdeploy() { + contract_deploy_consensus_test!( + contract_name: "value-too-large", + contract_code: r#" + (define-private (make-buff-256) + (let ((b16 0x00112233445566778899aabbccddeeff) + (b32 (concat b16 b16)) + (b64 (concat b32 b32)) + (b128 (concat b64 b64)) + (b256 (concat b128 b128))) + b256)) + + (define-private (make-buff-4096) + (let ((b256 (make-buff-256)) + (b512 (concat b256 b256)) + (b1024 (concat b512 b512)) + (b2048 (concat b1024 b1024)) + (b4096 (concat b2048 b2048))) + b4096)) + + (define-private (make-buff-65536) + (let ((b4096 (make-buff-4096)) + (b8192 (concat b4096 b4096)) + (b16384 (concat b8192 b8192)) + (b32768 (concat b16384 b16384)) + (b65536 (concat b32768 b32768))) + b65536)) + + (define-private (make-buff-1048576) + (let ((b65536 (make-buff-65536)) + (b131072 (concat b65536 b65536)) + (b262144 (concat b131072 b131072)) + (b524288 (concat b262144 b262144)) + (b1048576 (concat b524288 b524288))) + b1048576)) + + (begin + (unwrap-panic (as-max-len? (make-buff-1048576) u1048576)) + u0) + "#, + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ValueTooLarge`] +/// Caused by: `(as-max-len? …)` wraps a buffer whose serialized size plus the optional wrapper +/// exceeds `MAX_VALUE_SIZE`. Static analysis allows this construction, but initialization fails +/// at runtime when `Value::some` detects the oversized payload. +/// Outcome: block accepted. +#[test] +fn check_error_kind_value_too_large_ccall() { + contract_call_consensus_test!( + contract_name: "value-too-large", + contract_code: r#" + (define-private (make-buff-256) + (let ((b16 0x00112233445566778899aabbccddeeff) + (b32 (concat b16 b16)) + (b64 (concat b32 b32)) + (b128 (concat b64 b64)) + (b256 (concat b128 b128))) + b256)) + + (define-private (make-buff-4096) + (let ((b256 (make-buff-256)) + (b512 (concat b256 b256)) + (b1024 (concat b512 b512)) + (b2048 (concat b1024 b1024)) + (b4096 (concat b2048 b2048))) + b4096)) + + (define-private (make-buff-65536) + (let ((b4096 (make-buff-4096)) + (b8192 (concat b4096 b4096)) + (b16384 (concat b8192 b8192)) + (b32768 (concat b16384 b16384)) + (b65536 (concat b32768 b32768))) + b65536)) + + (define-private (make-buff-1048576) + (let ((b65536 (make-buff-65536)) + (b131072 (concat b65536 b65536)) + (b262144 (concat b131072 b131072)) + (b524288 (concat b262144 b262144)) + (b1048576 (concat b524288 b524288))) + b1048576)) + + (define-public (trigger-error) + (ok (begin + (unwrap-panic (as-max-len? (make-buff-1048576) u1048576)) + u0))) + "#, + function_name: "trigger-error", + function_args: &[], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TypeSignatureTooDeep`] +/// Caused by: inserting into a map whose value type already has depth `MAX_TYPE_DEPTH`. +/// The runtime wraps stored entries in an optional, pushing the depth past the limit. +/// Outcome: block accepted. +#[test] +fn check_error_kind_type_signature_too_deep_cdeploy() { + contract_deploy_consensus_test!( + contract_name: "type-depth-runtime", + contract_code: &{ + let optional_layers: usize = MAX_TYPE_DEPTH as usize - 2; + + let mut value_type = String::new(); + for _ in 0..optional_layers { + value_type.push_str("(optional "); + } + value_type.push_str("uint"); + for _ in 0..optional_layers { + value_type.push(')'); + } + + let mut let_bindings = String::from("(v0 u0)"); + for i in 1..=optional_layers { + let_bindings.push_str("\n "); + let_bindings.push_str(&format!("(v{i} (some v{}))", i - 1)); + } + let final_var = format!("v{optional_layers}"); + + format!( + "(define-map deep {{ key: uint }} {{ data: {value_type} }}) + (define-constant deep-value + (let ( + {let_bindings} + ) + {final_var})) + (begin + (map-insert deep (tuple (key u0)) (tuple (data deep-value))) + u0)" + ) + }, + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TypeSignatureTooDeep`] +/// Caused by: inserting into a map whose value type already has depth `MAX_TYPE_DEPTH`. +/// The runtime wraps stored entries in an optional, pushing the depth past the limit. +/// Outcome: block accepted. +#[test] +fn check_error_kind_type_signature_too_deep_ccall() { + contract_call_consensus_test!( + contract_name: "type-depth-runtime", + contract_code: &{ + let optional_layers: usize = MAX_TYPE_DEPTH as usize - 2; + + let mut value_type = String::new(); + for _ in 0..optional_layers { + value_type.push_str("(optional "); + } + value_type.push_str("uint"); + for _ in 0..optional_layers { + value_type.push(')'); + } + + let mut let_bindings = String::from("(v0 u0)"); + for i in 1..=optional_layers { + let_bindings.push_str("\n "); + let_bindings.push_str(&format!("(v{i} (some v{}))", i - 1)); + } + let final_var = format!("v{optional_layers}"); + + format!( + "(define-map deep {{ key: uint }} {{ data: {value_type} }}) + (define-constant deep-value + (let ( + {let_bindings} + ) + {final_var})) + (define-public (trigger-error) + (ok (begin + (map-insert deep (tuple (key u0)) (tuple (data deep-value))) + u0)))") + }, + function_name: "trigger-error", + function_args: &[], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TypeValueError`] +/// Caused by: passing a value of the wrong type to a function. +/// Outcome: block accepted. +#[test] +fn check_error_kind_type_value_error_cdeploy() { + contract_deploy_consensus_test!( + contract_name: "check-error-kind", + contract_code: " + ;; `as-max-len?` widens `0x` to type `(buff 33)` even though it contains 0 bytes. + ;; This passes the analyzer but fails at runtime when `principal-of` enforces + ;; the exact length, raising `CheckErrorKind::TypeValueError`. + (principal-of? (unwrap-panic (as-max-len? 0x u33)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TypeValueError`] +/// Caused by: passing a value of the wrong type to a function. +/// Outcome: block accepted. +#[test] +fn check_error_kind_type_value_error_ccall() { + contract_call_consensus_test!( + contract_name: "check-error-kind", + contract_code: "(define-public (trigger-error (x uint)) (ok true))", + function_name: "trigger-error", + function_args: &[ClarityValue::Bool(true)], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ContractCallExpectName`] +/// Caused by: the trait reference is stored as a constant, so the runtime never +/// binds it in `LocalContext::callable_contracts` and `special_contract_call` +/// cannot resolve the callee. +/// Outcome: block accepted. +/// Note: This test only works for Clarity 2 and later. +/// Clarity 1 will not be able to upload contract-3. +#[test] +fn check_error_kind_contract_call_expect_name_cdeploy() { + let contract_1 = SetupContract::new( + "contract-1", + "(define-trait simple-trait ( + (ping () (response bool uint))))", + ); + + let contract_2 = SetupContract::new( + "contract-2", + "(impl-trait .contract-1.simple-trait) + (define-public (ping) + (ok true))", + ); + + contract_deploy_consensus_test!( + contract_name: "contract-3", + contract_code: " + (use-trait simple-trait .contract-1.simple-trait) + + ;; Evaluated during initialization; runtime cannot resolve the callable. + (define-constant default-target .contract-2) + + (contract-call? default-target ping)", + exclude_clarity_versions: &[ClarityVersion::Clarity1], + setup_contracts: &[contract_1, contract_2], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ContractCallExpectName`] +/// Caused by: the trait reference is stored as a constant, so the runtime never +/// binds it in `LocalContext::callable_contracts` and `special_contract_call` +/// cannot resolve the callee. +/// Outcome: block accepted. +/// Note: This test only works for Clarity 2 and later. +/// Clarity 1 will not be able to upload contract-3. +#[test] +fn check_error_kind_contract_call_expect_name_ccall() { + let contract_1 = SetupContract::new( + "contract-1", + "(define-trait simple-trait ( + (ping () (response bool uint))))", + ); + + let contract_2 = SetupContract::new( + "contract-2", + "(impl-trait .contract-1.simple-trait) + (define-public (ping) + (ok true))", + ); + + contract_call_consensus_test!( + contract_name: "contract-3", + contract_code: " + (use-trait simple-trait .contract-1.simple-trait) + + ;; Trait reference stored as a constant. + (define-constant default-target .contract-2) + + (define-public (trigger-error) + (contract-call? default-target ping))", + function_name: "trigger-error", + function_args: &[], + deploy_epochs: EPOCHS_TO_TEST, + call_epochs: EPOCHS_TO_TEST, + exclude_clarity_versions: &[ClarityVersion::Clarity1], + setup_contracts: &[contract_1, contract_2], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UnionTypeValueError`] +/// Caused by: evaluating `to-ascii?` with a `(contract )` argument while the contract +/// is being initialized. The static analysis accepts the form, but the runtime encounters a +/// `CallableContract` value and the runtime rejects it with the union type error. +/// Outcome: block accepted. +/// Note: This test only works for Clarity 4 and later. +/// Clarity 1, 2, 3 will return a [`StaticCheckErrorKind::UnknownFunction`]. +#[test] +fn check_error_kind_union_type_value_error_cdeploy() { + let contract_1 = SetupContract::new( + "contract-1", + "(define-public (dummy) + (ok true))", + ); + + contract_deploy_consensus_test!( + contract_name: "contract-2", + contract_code: " + (define-trait trait-1 ( + (dummy () (response bool uint)))) + + (define-public (foo (contract )) + (to-ascii? contract)) + + (define-constant trigger-error + (foo .contract-1))", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + setup_contracts: &[contract_1], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UnionTypeValueError`] +/// Caused by: executing `to-ascii?` inside a public function with a `(contract )` +/// argument. Deployment succeeds, but calling `trigger-runtime-error` binds a +/// `CallableContract` value and the runtime rejects it with the union type error. +/// Outcome: block accepted. +/// Note: This test only works for Clarity 4 and later. +/// Clarity 1, 2, 3 will return a [`StaticCheckErrorKind::UnknownFunction`]. +#[test] +fn check_error_kind_union_type_value_error_ccall() { + let contract_1 = SetupContract::new( + "contract-1", + "(define-public (dummy) + (ok true))", + ); + + contract_call_consensus_test!( + contract_name: "contract-2", + contract_code: " + (define-trait trait-1 ( + (dummy () (response bool uint)))) + + (define-public (foo (contract )) + (to-ascii? contract)) + + (define-public (trigger-runtime-error) + (foo .contract-1))", + function_name: "trigger-runtime-error", + function_args: &[], + deploy_epochs: &StacksEpochId::ALL[11..], // Epochs 3.3 and later + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + setup_contracts: &[contract_1], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ListTypesMustMatch`] +/// Caused by: Contract initialization creates a constant list that mixes callable values +/// implementing different traits (`trait-a` vs `trait-b`). Runtime sanitization tries to +/// coerce that mixed list into a single entry type and fails with `ListTypesMustMatch`. +/// Outcome: block accepted. +/// Note: The error is only triggered since Clarity 2. In Clarity 1 the tx is valid and accepted. +#[test] +fn check_error_kind_list_types_must_match_cdeploy() { + let contract_1 = SetupContract::new( + "contract-1", + " +(define-trait trait-a ( + (ping () (response bool uint)))) + +(define-trait trait-b ( + (pong () (response bool uint))))", + ); + let contract_2 = SetupContract::new( + "contract-2", + " +;; Implements both trait interfaces defined in contract-3 and exposes a +;; helper that returns a list mixing the two callable types. + +(use-trait trait-a .contract-1.trait-a) +(use-trait trait-b .contract-1.trait-b) + +(impl-trait .contract-1.trait-a) +(impl-trait .contract-1.trait-b) + +(define-public (ping) + (ok true)) + +(define-public (pong) + (ok true)) + +(define-public (make-callables (first ) (second )) + ;; Returning mixedgenous callable references forces the runtime to + ;; sanitize a `ListUnionType` value. + (ok (list first second)))", + ); + + contract_deploy_consensus_test!( + contract_name: "contract-3", + contract_code: " +;; Contract under test: during initialization it defines a constant list that +;; mixes callable references to two distinct traits. That at runtime triggers a +;; `ListTypesMustMatch` error. + +(use-trait trait-a .contract-1.trait-a) +(use-trait trait-b .contract-1.trait-b) + +(define-private (as-trait-a (target )) target) +(define-private (as-trait-b (target )) target) + +(define-constant mixed-callables + (list + (as-trait-a .contract-2) + (as-trait-b .contract-2))) + +(define-public (noop) + (ok u0)) +", + setup_contracts: &[contract_1, contract_2], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ReturnTypesMustMatch`] +/// Caused by: dynamic dispatch through a trait argument returns a value whose type does not +/// conform to the trait specification. +/// Outcome: block accepted. +#[test] +fn check_error_kind_return_types_must_match_ccall() { + let trait_contract = SetupContract::new( + "trait-contract", + "(define-trait simple-trait ( + (get-1 (uint) (response uint uint))))", + ); + + let target_contract = + SetupContract::new("target-contract", "(define-public (get-1 (x uint)) (ok 1))"); + + let target_identifier = QualifiedContractIdentifier::parse(&format!( + "{}.target-contract", + to_addr(&FAUCET_PRIV_KEY) + )) + .unwrap(); + + contract_call_consensus_test!( + contract_name: "dispatching-contract", + contract_code: " + (use-trait simple-trait .trait-contract.simple-trait) + (define-public (wrapped-get-1 (contract )) + (contract-call? contract get-1 u0))", + function_name: "wrapped-get-1", + function_args: &[ClarityValue::from(target_identifier)], + setup_contracts: &[trait_contract, target_contract], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedContractPrincipalValue`] +/// Caused by: Supplying tx-sender to with-ft inside as-contract? forces eval_allowance to inspect a standard principal +/// Outcome: block accepted. +/// Note: This test only works for Clarity 4 and later. 'as-contract?' is not supported in earlier versions. +#[test] +fn check_error_kind_expected_contract_principal_value_cdeploy() { + contract_deploy_consensus_test!( + contract_name: "contract", + contract_code: r#" + (define-constant trigger-error + (as-contract? + ((with-ft tx-sender "token" u0)) + true))"#, + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedContractPrincipalValue`] +/// Caused by: Supplying tx-sender to with-ft inside as-contract? forces eval_allowance to inspect a standard principal +/// Outcome: block accepted. +/// Note: This test only works for Clarity 4 and later. 'as-contract?' is not supported in earlier versions. +#[test] +fn check_error_kind_expected_contract_principal_value_ccall() { + contract_call_consensus_test!( + contract_name: "contract", + contract_code: r#" + (define-public (trigger-error) + (as-contract? + ((with-ft tx-sender "token" u0)) + true))"#, + function_name: "trigger-error", + function_args: &[], + deploy_epochs: &StacksEpochId::ALL[11..], // Epochs 3.3 and later + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::IncorrectArgumentCount`] +/// Caused by: passing the wrong number of arguments to a function. +/// Outcome: block accepted. +#[test] +fn check_error_kind_incorrect_argument_count_ccall() { + contract_call_consensus_test!( + contract_name: "check-error-kind", + contract_code: "(define-public (trigger-error (x uint)) (ok true))", + function_name: "trigger-error", + function_args: &[ClarityValue::Bool(true), ClarityValue::Bool(true)], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UndefinedFunction`] +/// Caused by: invoking a public function name that is not defined in the contract. +/// Outcome: block accepted (transaction aborts with the runtime error). +#[test] +fn check_error_kind_undefined_function_ccall() { + contract_call_consensus_test!( + contract_name: "undef-fn-call", + contract_code: " + (define-public (noop) + (ok true))", + function_name: "missing-func", + function_args: &[], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchContract`] +/// Caused by: calling a contract that does not exist. +/// Outcome: block accepted. +#[test] +fn check_error_kind_no_such_contract_ccall() { + let mut nonce = 0; + + let mut epochs_blocks = HashMap::new(); + + for epoch in EPOCHS_TO_TEST { + let call_tx = ConsensusUtils::new_call_tx( + nonce, + "non-existent-contract", + "this-function-does-not-exist", + ); + epochs_blocks + .entry(*epoch) + .or_insert(vec![]) + .push(TestBlock { + transactions: vec![call_tx], + }); + + nonce += 1; + } + + let result = ConsensusTest::new(function_name!(), vec![], epochs_blocks).run(); + insta::assert_ron_snapshot!(result); +} + +/// CheckErrorKind: [`CheckErrorKind::CouldNotDetermineType`] +/// Caused by: reading a constant that was created in a pre-2.4 epoch without +/// value sanitization. The constant stores a mixed list of callable +/// references which cannot be sanitized once sanitization is enforced. +/// Outcome: block accepted. +/// Note: This test only works in Clarity 2 deployed in Epoch 2.3. +#[test] +fn check_error_kind_could_not_determine_type_ccall() { + let trait_contract = SetupContract::new( + "contract-traits", + " + (define-trait trait-a ( + (ping () (response bool uint)))) + (define-trait trait-b ( + (pong () (response bool uint))))", + ) + .with_epoch(StacksEpochId::Epoch23); + + let trait_impl = SetupContract::new( + "trait-impl", + " + (use-trait trait-a .contract-traits.trait-a) + (use-trait trait-b .contract-traits.trait-b) + + (impl-trait .contract-traits.trait-a) + (impl-trait .contract-traits.trait-b) + + (define-public (ping) (ok true)) + (define-public (pong) (ok true))", + ) + .with_epoch(StacksEpochId::Epoch23); + + contract_call_consensus_test!( + contract_name: "mixed-constant", + contract_code: " + (use-trait trait-a .contract-traits.trait-a) + (use-trait trait-b .contract-traits.trait-b) + + (define-private (cast-a (target )) target) + (define-private (cast-b (target )) target) + + (define-constant mixed + (list + (cast-a .trait-impl) + (cast-b .trait-impl))) + + (define-public (trigger-error) + (ok mixed))", + function_name: "trigger-error", + function_args: &[], + deploy_epochs: &[StacksEpochId::Epoch23], + call_epochs: &StacksEpochId::ALL[6..], // Epochs 2.4 and later + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity3, ClarityVersion::Clarity4], + setup_contracts: &[trait_contract, trait_impl], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::CircularReference`] +/// Caused by: circular reference forcing a contract calling itself using a contract call. +/// Outcome: block accepted +#[test] +fn check_error_kind_circular_reference_ccall() { + let trait_contract = SetupContract::new( + "trait-contract", + "(define-trait trait-1 ( + (get-1 (uint) (response uint uint))))", + ); + + let dispatching_contract = SetupContract::new( + "dispatch-contract", + "(use-trait trait-1 .trait-contract.trait-1) + (define-public (wrapped-get-1 (contract )) + (contract-call? contract get-1 u0)) + (define-public (get-1 (x uint)) (ok u1))", + ); + + let dispatch_principal = + QualifiedContractIdentifier::parse(&format!("{}.dispatch-contract", *FAUCET_ADDRESS)) + .unwrap(); + + // The main contract is required because `contract_call_consensus_test!` needs a deployed contract. + // As a result, `dispatch-contract` cannot be used directly, because need to be passed as `function_args`, + // and the consensus test mangles the `contract_name`. + let main_contract = "(use-trait trait-1 .trait-contract.trait-1) + (define-public (main-get-1 (contract )) + (contract-call? .dispatch-contract wrapped-get-1 contract))"; + + contract_call_consensus_test!( + contract_name: "main-contract", + contract_code: main_contract, + function_name: "main-get-1", + function_args: &[ClarityValue::from(dispatch_principal)], + setup_contracts: &[trait_contract, dispatching_contract], + ); +} diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__append_empty_blocks.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__append_empty_blocks.snap index dc230e5b03f..8a91b917a05 100644 --- a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__append_empty_blocks.snap +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__append_empty_blocks.snap @@ -3,6 +3,8 @@ source: stackslib/src/chainstate/tests/consensus.rs expression: result --- [ - Failure("Invalid Nakamoto block: failed static transaction checks"), - Failure("Invalid Nakamoto block: failed static transaction checks"), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Nakamoto block: failed static transaction checks", + )), ] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__append_stx_transfers_success.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__append_stx_transfers_success.snap index 4e4f738e68f..d95e209f299 100644 --- a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__append_stx_transfers_success.snap +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__append_stx_transfers_success.snap @@ -4,65 +4,7 @@ expression: result --- [ Success(ExpectedBlockOutput( - marf_hash: "095b12065b5aa5f0cc29dc004b16507be9fb7964a1d656e891a232931db1810a", - evaluated_epoch: Epoch32, - transactions: [ - ExpectedTransactionOutput( - tx: "TokenTransfer(from: ST000000000000000000002AMW42H, amount: 1000, memo: 00000000000000000000000000000000000000000000000000000000000000000000)", - vm_error: "None [NON-CONSENSUS BREAKING]", - return_type: Response(ResponseData( - committed: true, - data: Bool(true), - )), - cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 0, - read_count: 0, - runtime: 0, - ), - ), - ExpectedTransactionOutput( - tx: "TokenTransfer(from: ST000000000000000000002AMW42H, amount: 1000, memo: 00000000000000000000000000000000000000000000000000000000000000000000)", - vm_error: "None [NON-CONSENSUS BREAKING]", - return_type: Response(ResponseData( - committed: true, - data: Bool(true), - )), - cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 0, - read_count: 0, - runtime: 0, - ), - ), - ExpectedTransactionOutput( - tx: "TokenTransfer(from: ST000000000000000000002AMW42H, amount: 1000, memo: 00000000000000000000000000000000000000000000000000000000000000000000)", - vm_error: "None [NON-CONSENSUS BREAKING]", - return_type: Response(ResponseData( - committed: true, - data: Bool(true), - )), - cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 0, - read_count: 0, - runtime: 0, - ), - ), - ], - total_block_cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 0, - read_count: 0, - runtime: 0, - ), - )), - Success(ExpectedBlockOutput( - marf_hash: "180457415b54799e13905b076af575c96c77614e13e26f8211aa32e7cb1e893e", + marf_hash: "0c7c8299ff0df20dd19ed61ccf72111f137c9c0e7d97d8175f417a5025ff776c", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__chainstate_error_expression_stack_depth_too_deep.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__chainstate_error_expression_stack_depth_too_deep.snap deleted file mode 100644 index b35f1d4c795..00000000000 --- a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__chainstate_error_expression_stack_depth_too_deep.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: stackslib/src/chainstate/tests/consensus.rs -expression: result ---- -[ - Failure("Invalid Stacks block 4283815e1f66aa52f455cfe8a415c8ff1c3d28794b83a08384534e30650554e2: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))"), - Failure("Invalid Stacks block b97c37a0da184764a8eb0769d6c8a9af0a6c98b0e6c950423d324286a349bf0c: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))"), - Failure("Invalid Stacks block 121b03507be0248b0abd05ccf93403e3c50bd8969e8b1c4d2d3f215fd6243576: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))"), - Failure("Invalid Stacks block 0cb105df328cc9565f4817071f27374a10d73f1fd88a2a91ccf2885b41bef3e3: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))"), - Failure("Invalid Stacks block 516690436438389acc8b58ea7bbbd0a04d844f4f69f8d1ea0500458d9fa8e4d7: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))"), - Failure("Invalid Stacks block 96d7c8d5ce7b5452a16079b20a97effd3d3c839e0d97af86484df1f5e48c2b74: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))"), - Failure("Invalid Stacks block 57ed3ad80ddb289a20f936cc27ad6c07640b5f3f5acfbfcda39a900dc38735f3: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))"), -] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__problematic_supertype_list.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__problematic_supertype_list.snap new file mode 100644 index 00000000000..0f377b586b3 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__problematic_supertype_list.snap @@ -0,0 +1,514 @@ +--- +source: stackslib/src/chainstate/tests/consensus.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch20, + error: "Invalid Stacks block e4f5403f78a7c0d7f040672dd0bcebc4e3e0f8fc8d419cf33c7dfba55dd1c35e: ClarityError(Interpreter(Internal(DBError(\"Deserialization expected the type of the input to be: (tuple (a int))\"))))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch2_05, + error: "Invalid Stacks block 8e329998079e27672c58fa95e0317813a1edb00ad01fee0b359c87c164cfb0b4: ClarityError(Interpreter(Internal(DBError(\"Deserialization expected the type of the input to be: (tuple (a int))\"))))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch21, + error: "Invalid Stacks block e277f0df135d6850184f4754fa6053df2e5ccefcb26ed69894eab586466ac497: ClarityError(Interpreter(Internal(DBError(\"Deserialization expected the type of the input to be: (tuple (a int))\"))))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch21, + error: "Invalid Stacks block 35a0ee98240a47abff48a0c1c009344a08237c294a72977f14cf77aedc41f565: ClarityError(Interpreter(Internal(DBError(\"Deserialization expected the type of the input to be: (tuple (a int))\"))))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch22, + error: "Invalid Stacks block c86f289e78effedd08f6926db73d3aa0114ba040da5d73225683991766cacce2: ClarityError(Interpreter(Internal(DBError(\"Deserialization expected the type of the input to be: (tuple (a int))\"))))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch22, + error: "Invalid Stacks block 615af982f1469b54df54affb55febbe81c292307f6d59f280a122e3e34ca7b4c: ClarityError(Interpreter(Internal(DBError(\"Deserialization expected the type of the input to be: (tuple (a int))\"))))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch23, + error: "Invalid Stacks block 59827e315e264cc8125121eb81728e83032ad370420080efce6f29fc43f92ecf: ClarityError(Interpreter(Internal(DBError(\"Deserialization expected the type of the input to be: (tuple (a int))\"))))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch23, + error: "Invalid Stacks block 3a45cd1ab7a32f984f350a6d712c61f9f10715d1c4d627080b6f2f423a1f9ef5: ClarityError(Interpreter(Internal(DBError(\"Deserialization expected the type of the input to be: (tuple (a int))\"))))", + )), + Success(ExpectedBlockOutput( + marf_hash: "4d3b273f43c155e2f3351bc5dc314bc188cccec18fe225f9dab1ae8637f9065f", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1285170e85ccfddbec22d79057a916420ce00377ce7593af0ee5c3bd2b5a3421", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "eb27bc1477c794c8de52eb7a778f43fb61ccf98bfd4c72daa3f8ca1c2e67e3c1", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0613d3eaedaa94ecb14655f7fcbbaa9351210274c95b3fd5d2e0dc3cc81d7f22", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ccdbfa844d62be3dfa322ef2262fc12f5a8fc37bae650a17949007c43d06dc09", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9dda5cb210aeed2124f7b87a1ffa665de8b824fa111729a0355a0e42c2761235", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5757a5e40f68d71a7be9444ad48c4e84cc959d5e4298ada51b27db54e61fd131", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4c947bfc4bb64c5a0821f507a3f274e4dd2a20db8a4070d9837de2063e7ca1fb", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7454c6e7a12f9bd57f3e980964273faacca06af3781a1a1f7de235543379df63", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5ce93e6afc1d48c69d047ea09027a7bc31513a42dba4d744d2c37dfb90b2ce09", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2a7cb4e37ca6f3ad991b6ddd3bb06262a819e77b6b258ee4fdbefc9bbaecae00", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "60987a6895f7d9a2e9ecbac6a32982c93e5338b490c6ef0be26296a52c8ea5c4", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f5e7acbb927f5719834811557295c4578c82ba216f4176cd854fa2a090c4b89d", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a3009caf2849e7676cc345a2fa5655f95912651be8a7c4a6286701048f67e6a3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40473, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "af1e66aa007ce59f0e3c3167355ebab4595827b12fbc4acd1451a3a56312db81", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4865d92c5f1c8013d84b0246f15a67d0393e35def46dd2d4b72e27525c451717", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "dfac789da7da9ae3adb0f9ad640229520db1856b1a0760e6ea19bfbcd19926e3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: problematic-Epoch3_3-Clarity4, 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: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 581, + write_count: 5, + read_length: 85, + read_count: 4, + runtime: 40472, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__successfully_deploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__successfully_deploy.snap new file mode 100644 index 00000000000..e9dff3b4b1a --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__successfully_deploy.snap @@ -0,0 +1,118 @@ +--- +source: stackslib/src/chainstate/tests/consensus.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "4db4dbe80892aa8e740e65dd655ef880ef1c8b6653d2eafea150bcf0309c7ad9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "19c0a8b31702b6fc10348e55bb5051dd8ee9df81691611532c390651d813c3b8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "aaae367af98a33fef665209b9de4a15d32438e68ab22ea1eff7129f233daa093", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2a05fd68c81d4b61d546555a5835f374b7cb359fbe11789640b042a9a355401b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity4, 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: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__successfully_deploy_and_call.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__successfully_deploy_and_call.snap index 9827a42a1df..e6e7473f353 100644 --- a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__successfully_deploy_and_call.snap +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__consensus__successfully_deploy_and_call.snap @@ -4,7 +4,343 @@ expression: result --- [ Success(ExpectedBlockOutput( - marf_hash: "a590886094b514abf4406e1a5c3a26978e4b7e8dd159aa310382be65b632db1a", + marf_hash: "c740de32d7b9273518899f798a6c66ea543dc67c4df2c97f428e37cf86f36857", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 1175000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 1175000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c197b006221151c65e298beaf88adcc9532f8b494b7f7564b8ef60fb217a4eb5", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 315491, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 315491, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9d4f0f3f3c5f997ac76ad16841cae6ac56d612bb3f133d9056cd912476800b34", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5328a02c128403d3db80ee1c6dce0068c28c2d0afdfea8d6c90b148a1ac8c67f", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8d96af516bb1f0e860cb4b79c37cdcd076c6bc1f407f9be5bb4e98f05f1f9288", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "51f00668865be69fe14a6a05b978fb5ea342e35b641c5ca0b2c1b10139a3b813", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fd38a7465f6099c774401da7a2bafa8472276d94217e6805da64a45f1df0362e", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e4856cf600de3be502ca5304518ce857660593916da52065991cd7c30ff875d8", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e5dbddbf24acae9a3a968f4a1faef8a86eab3d2291341b5e86c2dc0fc9809805", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "90d86c6f4f1a6d83d382d50c74403102fb98a756b8a1cc7472f8211004781319", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "49f818293b8600e6090369fda5858489782839f70d776b2c4c9878d3c22fc1bd", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "db2e8a479f299ee0ff248a4ef525f6fc6120228bb924bf7ab4c7e099c8960d02", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "aa85c7c19b0b4f1dc440b0ad587bc41c9432239e821090a680e53ffb02ffd055", evaluated_epoch: Epoch30, transactions: [ ExpectedTransactionOutput( @@ -32,7 +368,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "dc0aabf612da63b0140560522efdb8ce896660315cdd2fa09adbf9369da7abb7", + marf_hash: "7b1b8040546ed88587ba49b2501e6778146a392c4d1b541f32d2d1682851aeff", evaluated_epoch: Epoch30, transactions: [ ExpectedTransactionOutput( @@ -60,7 +396,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "82e841d52ca2e9d1c226cf961006eff1e6257ce6c714cbeb198f05536708a7b3", + marf_hash: "e627a7368876f00826689f9fcacf7317e175554d53f04bb78a86626734c4e790", evaluated_epoch: Epoch30, transactions: [ ExpectedTransactionOutput( @@ -88,7 +424,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "3c02272c7a6681809ba820cd27eae4cf6a947ffbb94472c19858a54e8f3ae262", + marf_hash: "8508ebdf59fb7ba448a7d7af4cb52c14b4c56d04041df5194a390b9f169b4b60", evaluated_epoch: Epoch31, transactions: [ ExpectedTransactionOutput( @@ -116,7 +452,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "29aad28c9ea29def9bca1065d0aa00e2fd3c55777382f3200f17a4a3d6367a31", + marf_hash: "a881c2045046b13690cc9f3006d3389fe034793b1d26246bf47ca845de8dd459", evaluated_epoch: Epoch31, transactions: [ ExpectedTransactionOutput( @@ -144,7 +480,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "50a8d6594da285e03915111a3d405675069606fbd45f263c0da68b8ed2def295", + marf_hash: "8a41f43ea521e11f4913537e59179df19da1757c1ae4b6fd4e197432464e716b", evaluated_epoch: Epoch31, transactions: [ ExpectedTransactionOutput( @@ -172,7 +508,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "969f0c7e8124e21997bb02259043885d0f0b6825244832b3bd02e15079b02358", + marf_hash: "48742918dce6dea0d163d92140c8431518fc295000cf9170ec67a349054e0581", evaluated_epoch: Epoch32, transactions: [ ExpectedTransactionOutput( @@ -200,7 +536,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "2afc4a781e1f87d793e3e876fbb7eb90b00c34d34f88b03ed04adebf7e1d2a34", + marf_hash: "f4d9c634f76c9c842ecb476fc54fefd89f4511b7aa93d9dd84606ae3e8e89b84", evaluated_epoch: Epoch32, transactions: [ ExpectedTransactionOutput( @@ -228,7 +564,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "e8bbd5ff2cfab0812da17d25cdb468e87da8ca43b3dd6bf0cb20f5ffb9b5c434", + marf_hash: "c1178ed8dbdad0aa16b61f7f7093540374230071f54e48e97d5a97f025fad067", evaluated_epoch: Epoch32, transactions: [ ExpectedTransactionOutput( @@ -256,39 +592,123 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "8e1fa3c731374492b0d95090c1df2a37016685a2e8aa0d8838392f325c363da8", - evaluated_epoch: Epoch32, + marf_hash: "e1b182f5109ae5d5d7ebb26eb6c95dfcc58b98f495863689f68141b2fae715da", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_0-Clarity1, function_name: bar, function_args: [[UInt(1)]])", + tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, - data: UInt(1), + data: Bool(true), )), cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 103, - read_count: 3, - runtime: 499, + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, ), ), ], total_block_cost: ExecutionCost( - write_length: 0, - write_count: 0, - read_length: 103, - read_count: 3, - runtime: 499, + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, ), )), Success(ExpectedBlockOutput( - marf_hash: "18433deeefcbf8171b64dbe2e954662884dc87276df423111a24bbd0b3ee7f8d", - evaluated_epoch: Epoch32, + marf_hash: "cb6aa0960e15a80518d4b5b275c6c810ad0fc7d12542afaae03042b12d74f4fc", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_0-Clarity2, function_name: bar, function_args: [[UInt(1)]])", + tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d0968d2de2d262981affadb3084a95236ae6e5542c97062a7163f7e1629a87e8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e292c2db747705575195dd40eed99e5fd0379d000e9333f327cfe787af77c0f0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity4, 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: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 121, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 11968, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cf98be19e4e431ff2030fcef843fd941d13b5e99d3eb19337b67ecfcfff8464e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_0-Clarity1, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, @@ -312,11 +732,11 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "e78662e11643b6bb442bc661e4b5e6e885563144f51c2a77268f67c5db3f3584", - evaluated_epoch: Epoch32, + marf_hash: "2ccdc0de951b25d5459d041cd8d6711c32e401fbf3402ba77944c21829eff6fa", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_0-Clarity3, function_name: bar, function_args: [[UInt(1)]])", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_05-Clarity1, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, @@ -340,11 +760,11 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "73f22023951bb8a04e5ccb7c569b979fcaa5a56590c14442a5dcfab5ea5607b5", - evaluated_epoch: Epoch32, + marf_hash: "b264158c7465a32e8bec7d5f705104b9fc0031071d0454284852fa5b63a88309", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_1-Clarity1, function_name: bar, function_args: [[UInt(1)]])", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_1-Clarity1, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, @@ -368,11 +788,11 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "027a3d14203b456780ea26eafecd9ab5261b7601ad711793772c7c6e0fa02e59", - evaluated_epoch: Epoch32, + marf_hash: "d578ed6261fec5f84ee2d76d45478eefb76656cb615e396d5db78e83f109e1ae", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_1-Clarity2, function_name: bar, function_args: [[UInt(1)]])", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_1-Clarity2, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, @@ -396,11 +816,11 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "57409ac5f17d76a2fb7bb5a96f6df5eda1d3689a23c626f7fbc104addf1cf32f", - evaluated_epoch: Epoch32, + marf_hash: "171ca3c0e1eab568dee2f46a54d04fbee63790d74ac591a50727fc9546cd98c9", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_1-Clarity3, function_name: bar, function_args: [[UInt(1)]])", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_2-Clarity1, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, @@ -424,11 +844,11 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "e5a30cda5e2d36eac5711d89e95b1ed54242fbf7ceb4c85c7bf9306766fd9ca0", - evaluated_epoch: Epoch32, + marf_hash: "5d95d5ffc12ccd6c30e682acd19fefc94d2c294aed1dfffa8474796148501043", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_2-Clarity1, function_name: bar, function_args: [[UInt(1)]])", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_2-Clarity2, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, @@ -452,11 +872,11 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "a3bcc31b429da98ee5235387601d803cb305a3db4af5fdb7ba9c3f5bcc0d41b2", - evaluated_epoch: Epoch32, + marf_hash: "69b467c67ba9a3e57dd423aab2df50a8460c4807260bb018871c217c22475929", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_2-Clarity2, function_name: bar, function_args: [[UInt(1)]])", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_3-Clarity1, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, @@ -480,11 +900,11 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "ef8e8f6580de93248e1d1cc2f87bbdbefb3ddb86d403c2101b4620c5449365c9", - evaluated_epoch: Epoch32, + marf_hash: "952a7d2c55fbd2453d033e3fbc92314e481be8e1fff78cde70d2f1a37ccd5d35", + evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch3_2-Clarity3, function_name: bar, function_args: [[UInt(1)]])", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_3-Clarity2, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, @@ -508,119 +928,119 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "a4d7a7e6071908e2780d665ce73f1fc248a06419857e1148af6a289b178f7562", + marf_hash: "57659d971d1e7a1683c57f47e88ab4f00f064e4b7e7aa72f4d95e113bfb358ff", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_4-Clarity1, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, - data: Bool(true), + data: UInt(1), )), cost: ExecutionCost( - write_length: 121, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 11968, + write_length: 0, + write_count: 0, + read_length: 103, + read_count: 3, + runtime: 499, ), ), ], total_block_cost: ExecutionCost( - write_length: 121, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 11968, + write_length: 0, + write_count: 0, + read_length: 103, + read_count: 3, + runtime: 499, ), )), Success(ExpectedBlockOutput( - marf_hash: "f93629deb181a073d7f1f7f26c1b4d2eaf844cff08f74c2fd9881fa19c4d8408", + marf_hash: "2660d037bfba3d24ca01e94d372c1caa53522068d03f159d00310b8145bb86e3", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_4-Clarity2, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, - data: Bool(true), + data: UInt(1), )), cost: ExecutionCost( - write_length: 121, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 11968, + write_length: 0, + write_count: 0, + read_length: 103, + read_count: 3, + runtime: 499, ), ), ], total_block_cost: ExecutionCost( - write_length: 121, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 11968, + write_length: 0, + write_count: 0, + read_length: 103, + read_count: 3, + runtime: 499, ), )), Success(ExpectedBlockOutput( - marf_hash: "0a43d8c0d910d9a2ca58b723c4533c63e1c32ca90dce7fab5cfe9216c5e34432", + marf_hash: "28a46a294ff13b647e7bb903b76f7f8cf44b34228b295601fd4b5f205f69a6c4", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_5-Clarity1, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, - data: Bool(true), + data: UInt(1), )), cost: ExecutionCost( - write_length: 121, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 11968, + write_length: 0, + write_count: 0, + read_length: 103, + read_count: 3, + runtime: 499, ), ), ], total_block_cost: ExecutionCost( - write_length: 121, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 11968, + write_length: 0, + write_count: 0, + read_length: 103, + read_count: 3, + runtime: 499, ), )), Success(ExpectedBlockOutput( - marf_hash: "ec3fa2b2fa5766499c2ee43c70c59c09d65ab9d04b04bcecf86117224243ebf7", + marf_hash: "179f4e2ffbe1fe856deaaf97021d6dd1f1e1c0e387015770a35616a0094ad052", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( - tx: "SmartContract(name: foo_contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: foo_contract-Epoch2_5-Clarity2, function_name: bar, function_args: [[UInt(1)]])", vm_error: "None [NON-CONSENSUS BREAKING]", return_type: Response(ResponseData( committed: true, - data: Bool(true), + data: UInt(1), )), cost: ExecutionCost( - write_length: 121, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 11968, + write_length: 0, + write_count: 0, + read_length: 103, + read_count: 3, + runtime: 499, ), ), ], total_block_cost: ExecutionCost( - write_length: 121, - write_count: 2, - read_length: 1, - read_count: 1, - runtime: 11968, + write_length: 0, + write_count: 0, + read_length: 103, + read_count: 3, + runtime: 499, ), )), Success(ExpectedBlockOutput( - marf_hash: "d3451f558343a34dc1013cacf3f9c07d04f76bf84e1f5ff7a5738230364c453f", + marf_hash: "fbf4348dcf45aa77d182277582b9cfba93ba080aa3c1ddeb547dbeffb8c5df99", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -648,7 +1068,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "56f27df16675d8dbe666f8d0793c8f31fe8a7616436f0638041dad6aaf12ffd7", + marf_hash: "9511b65c6d140358a10a44fc37d08f58050696af17a9a2e947790c48ecb07f64", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -676,7 +1096,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "61ed7b44320cc7100664c4732d431d0e3103869bbb8e7b095a2a2cb256b32f41", + marf_hash: "27b74798e890268aa9fc835cb7945fc2f787d21a5124aead150c15bb5177b69b", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -704,7 +1124,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "3dd0da4b5c81ddb60394adc0078f07951b94be164b0acbb3dc18dd7a824f38b3", + marf_hash: "ed2139395e8de4f21f5a89facbc0e56a525e9b5b1d2e38df4d2aa7a96e17149c", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -732,7 +1152,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "d615a756f0feeda86821fc3df4176ac8ad81403fc4d8cc905cbe23e32eeb97a2", + marf_hash: "aaee8e8391063eb1789cc3b0841142df9f2aac16174ed25382b3703b6cd4f0d7", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -760,7 +1180,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "13274516ac921e85a216911865d829fde2a03ec6069f184aea8d872cd2d68691", + marf_hash: "e5869c066bc278e47c3c4db5f7ae31d07dac5068bb81bd76feba00d263b662c5", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -788,7 +1208,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "03f0b38ef9c1689d6b6d94c6dafb3559aeca63b3e4a20e2b3095afe470e228a1", + marf_hash: "2caf0c267558d8db1097bdf6f48bcdf777a9b61f519de1de4e65852db63dfbfd", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -816,7 +1236,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "bddb1e348ec4af76001dd26054a5b15f7ee73734a33a96d1f42b8d070401f3d0", + marf_hash: "c674e9ce6b703fa907905b1d70150b1f09bb94c7187e9bee991b9dde64e3998f", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -844,7 +1264,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "b36b6a71291844658462fd63b1404505dac195ab6d1e0f617ce741b6763bc002", + marf_hash: "051eb0a610a1315a47c900ef2148afe925efa73a67c4aea14ebb01e3cdc1e818", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -872,7 +1292,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "1509e7208cbc57f11f7130e9a723d88a55bd7dd7d1db21bfebde27694f82a3c9", + marf_hash: "7e8d985678bc58b727e0aaa689e9e2fa473245d2a47602829ee4aa6a3b3f5256", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -900,7 +1320,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "b35dd5af7b0489b95ad09fc4a4a0cd824e0722d54dcfefb97331062ccad7d411", + marf_hash: "a8650c08a70442a614f9a5b9d1bab1231c6b21639dee51290d5231c94dce2c6c", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -928,7 +1348,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "f93386433ae622b3ccbac5c4f8fca3de479af09ee16ad7935a521b68f5a3713f", + marf_hash: "3f09fd3852e02ef4d8ba512b037b4a1ea419335099122e2c402e2b1770c308c7", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( @@ -956,7 +1376,7 @@ expression: result ), )), Success(ExpectedBlockOutput( - marf_hash: "3717b93edcec46ca2e785a0709ffd725ff078b2cdf3ddc8b7fa0eb9a2bb8e4d0", + marf_hash: "4270a21c51d2eb88e08cb9bd9d09fcb0226e9a7af586cf9a13d7c466d777c789", evaluated_epoch: Epoch33, transactions: [ ExpectedTransactionOutput( diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__circular_reference.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__circular_reference.snap new file mode 100644 index 00000000000..7b9d2025557 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__circular_reference.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "e9cf17dd19ed5719376cfc21c55b4b4ed56de5052a359cd99fb0e5e08d4a09eb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(detected interdependent functions (my-a, my-b)) [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: 2838, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2838, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b434debffc1b1a762e7da6ea7f50a13cb951d3032cf78b20c95a6934ce174749", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(detected interdependent functions (my-a, my-b)) [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: 2838, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2838, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "18129d4579667a778909d96934825cf8f14769e8b28f737d8ab25d9962f5f80a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(detected interdependent functions (my-a, my-b)) [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: 2838, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2838, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "99f42521e1e38eb97160bf7be0c45fd24de8ad18bf5d936777a945d7f48d3360", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(detected interdependent functions (my-a, my-b)) [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: 2838, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2838, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__contract_name_too_long.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__contract_name_too_long.snap new file mode 100644 index 00000000000..ffbc16227ce --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__contract_name_too_long.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "201655f038eed9c876785f9d7250af6b1e8f70ca65fafc90fee3feaf63b1776f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(contract name \'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\' is too long) [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: 3240, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3240, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e763f94f35a1e2057699b52ffc46551294ae8546ca61ed92071da32174d68a93", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(contract name \'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\' is too long) [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: 3240, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3240, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f699cc74060db489a9ce31ffa902342de765d2c21e39911a21bed218e83fbf88", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(contract name \'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\' is too long) [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: 3240, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3240, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d9d102d58b5b2252e684d1b2394f5176bfd5670bfce678db2c4d071d4a95e953", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(contract name \'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\' is too long) [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: 3240, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3240, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__cost_balance_exceeded.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__cost_balance_exceeded.snap new file mode 100644 index 00000000000..6fc704edcd0 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__cost_balance_exceeded.snap @@ -0,0 +1,22 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 3bd4519cb89a7151a1602f4e0d171b106ab80197c17a978ad0fefc79ad01fa70: CostOverflowError(ExecutionCost { write_length: 3589069, write_count: 4, read_length: 19309683, read_count: 59, runtime: 4948255138 }, ExecutionCost { write_length: 3589069, write_count: 4, read_length: 19309683, read_count: 59, runtime: 5004355279 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block e066275ee8f37230b8496164b13071d5e1015e59405451337fb01e0ecf88e92e: CostOverflowError(ExecutionCost { write_length: 3589069, write_count: 4, read_length: 19309683, read_count: 59, runtime: 4948255138 }, ExecutionCost { write_length: 3589069, write_count: 4, read_length: 19309683, read_count: 59, runtime: 5004355279 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 2894132b57566ba9e28fdd55b4b57c85fcd470ac6a8839d93eea957fa1d7445a: CostOverflowError(ExecutionCost { write_length: 3589069, write_count: 4, read_length: 19309683, read_count: 59, runtime: 4948255138 }, ExecutionCost { write_length: 3589069, write_count: 4, read_length: 19309683, read_count: 59, runtime: 5004355279 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block b08f0b5cd9d192252bbd9f7804bae1b2e7582ebb6fdec867d0cb64e258a2547e: CostOverflowError(ExecutionCost { write_length: 3589069, write_count: 4, read_length: 19309683, read_count: 59, runtime: 4948255138 }, ExecutionCost { write_length: 3589069, write_count: 4, read_length: 19309683, read_count: 59, runtime: 5004355279 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__define_trait_bad_signature.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__define_trait_bad_signature.snap new file mode 100644 index 00000000000..441ee62049c --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__define_trait_bad_signature.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "4d6d9b225b5b7fcc829f1f666414b78656f77b9776e09065d03da5447305b311", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some((define-trait ...) expects a trait name and a trait definition) [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: 531, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 531, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e95e1e638ec67fa2176f86ed85cfcb820272c3813be2f047f771f685edae4976", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some((define-trait ...) expects a trait name and a trait definition) [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: 531, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 531, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ba3614243bbbac4e91d320a4988899a9f7489ac9f7020efb6bf556a44dd0374a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some((define-trait ...) expects a trait name and a trait definition) [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: 531, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 531, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d6c5f03740e884ef0fa7ab4ce7fa8cc31185d85d5708fa2ac138154e75106616", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some((define-trait ...) expects a trait name and a trait definition) [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: 531, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 531, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_closing.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_closing.snap new file mode 100644 index 00000000000..0624568d336 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_closing.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "b0e6ff368f1c0e52cc82329e78176676c074cefdeb1fc2c43a843e2b339673dd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(expected closing \')\') [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: 108, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 108, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b47adb01fe08a4004120b829fce874b116e5390a17565b177d6f3d8bd46a19da", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(expected closing \')\') [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: 108, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 108, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "86501d06f5fb6292a272aa848e604115ea135bc9e8faa7b67c85bb7ca5df8e9c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(expected closing \')\') [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: 108, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 108, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fe29586b555a2aa3cb82502bbc1a4df43ce1c96bb02d5c105c54d2f51bba067e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(expected closing \')\') [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: 108, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 108, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_contract_identifier.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_contract_identifier.snap new file mode 100644 index 00000000000..3936a17aac6 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_contract_identifier.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "fc84433c9b52b0d4803c8fe840b1c9215f0c735f589c5d6b64ca8c4fe00bbacf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(expected contract identifier) [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: 2133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "175aa41432cd9bdb153c2da15380b7d41a2e7ef4d18adf6532ee6aacbde3990e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(expected contract identifier) [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: 2133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f8af5944b9b6c37df882d00bc6173cc0011c397006df70b6ee998bfd2738d879", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(expected contract identifier) [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: 2133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7f4051601c533eab08bde3982abcca208dbea5d4895af8f4c5558dc63a618612", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(expected contract identifier) [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: 2133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2133, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_trait_identifier.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_trait_identifier.snap new file mode 100644 index 00000000000..c85e43f66bf --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_trait_identifier.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3e74c16a03b30f200a53276325e94fce8280f2e7745a293e5c4254a545b7b3d2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(expected trait identifier) [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: 2295, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2295, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4b25f85894b7bc47d7ea4a62d37c64126524436494e26de6f33941926dbe2f3f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(expected trait identifier) [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: 2295, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2295, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a142b2fbea9abbaee39ca1892b9449e8c5a9331baf7dcc5f820cf0d1f7fa7e54", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(expected trait identifier) [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: 2295, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2295, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fffba3a0950eeb72029a450c4dab3f549cf9d1fbc244b3620cb064708c97cda9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(expected trait identifier) [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: 2295, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2295, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_white_space.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_white_space.snap new file mode 100644 index 00000000000..de46ec99c08 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__expected_white_space.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3390089ac0826e8e5677d5093fa3d0db6081e88e6a1763017efc763d3cb96b16", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(expected whitespace before expression) [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: 945, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 945, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "22bde8e53de558ddb39f2fc218838ece0a08a21284d0cc62c7df511fd724d5df", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(expected whitespace before expression) [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: 945, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 945, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4a20b0efd6c9764b7f0526bd2ae82a9d2c9581f3d8610f6fe46cddaafbf26284", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(expected whitespace before expression) [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: 945, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 945, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cf5244d253bc394b1447ca488e25307a48e9229ebee1e50e9b76fd1001a77126", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(expected whitespace before expression) [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: 945, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 945, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__failed_parsing_int_value.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__failed_parsing_int_value.snap new file mode 100644 index 00000000000..524ab482c72 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__failed_parsing_int_value.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ea6ade24195c1472fe0282801119855eb60720ad0d01562ecf8c3fd3cfa00f42", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(Failed to parse int literal \'340282366920938463463374607431768211455\') [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: 1917, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1917, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "790d4b553797ac4e91e0ef9a2eb84eb77c3dbfb6052c7ba28ad3d01b3e7e3025", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(Failed to parse int literal \'340282366920938463463374607431768211455\') [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: 1917, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1917, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a224642c660498c83dc40f3d21959f06747f48f493f2e1a5320005c23e5499af", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(Failed to parse int literal \'340282366920938463463374607431768211455\') [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: 1917, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1917, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7766065bdd67c5297cbdc8aa7f83d059a3e35089cb4ee2a2da01fb90249ef01f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(Failed to parse int literal \'340282366920938463463374607431768211455\') [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: 1917, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1917, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__failed_parsing_uint_value.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__failed_parsing_uint_value.snap new file mode 100644 index 00000000000..bf57c03f90a --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__failed_parsing_uint_value.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "0baa8536816ea19016addf5641e710546c1337086d00ae90446b95d3cc4fab61", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(Failed to parse uint literal \'u999340282366920938463463374607431768211455\') [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: 2079, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2079, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "67d97aecb42da086f036917ea7e64c99b1bf219c95b8203bf83d50376b93fe6e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(Failed to parse uint literal \'u999340282366920938463463374607431768211455\') [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: 2079, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2079, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fbf143f6f9eb3f0f25033be67d86796ab42d8db3ac4d2558d2f1195d04df144a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(Failed to parse uint literal \'u999340282366920938463463374607431768211455\') [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: 2079, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2079, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e6b8edf6fec8da921efe96d6cacea247c900901b6b758711ba3e8d6e6da7f9e4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(Failed to parse uint literal \'u999340282366920938463463374607431768211455\') [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: 2079, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2079, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__illegal_ascii_string.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__illegal_ascii_string.snap new file mode 100644 index 00000000000..ef8df31a6ae --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__illegal_ascii_string.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "5865f1dda3ab0b0d4397d462d4147f4b9f9611ae743aeb5850d215ad89f6f537", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(illegal ascii string \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...[1048577]\") [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: 28312389, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 28312389, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2f1e187a69156d498891e69d74759a8e72d31ac0af280949031e7bb05d56065d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(illegal ascii string \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...[1048577]\") [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: 28312389, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 28312389, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c932ac3bafac4a25f223b9763df0474d7654347b30699ea329341987a4464896", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(illegal ascii string \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...[1048577]\") [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: 28312389, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 28312389, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a5aab61fea752043da044e177f3eedddfda02ba01b82814328c0d4af0b55c699", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(illegal ascii string \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...[1048577]\") [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: 28312389, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 28312389, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__impl_trait_bad_signature.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__impl_trait_bad_signature.snap new file mode 100644 index 00000000000..aedef062697 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__impl_trait_bad_signature.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "26a7cf9478898f9b24f8aca56188ac912a1e505770bf0c0f15f8a1deeab06c54", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some((impl-trait ...) expects a trait identifier) [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: 477, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 477, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "df709ff7840fbeaf57a4e8ac17bfa3fdd540e2b2447b4458dc642b051daf905f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some((impl-trait ...) expects a trait identifier) [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: 477, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 477, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6c60ba3db635837ae86f8756d7ccd3440fdc06bcbd2342ef3c60f925bdaeb247", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some((impl-trait ...) expects a trait identifier) [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: 477, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 477, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4d00726d13d692f37b97e72e77327a92ac409aa7b9dd06711806bdabe3d3294e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some((impl-trait ...) expects a trait identifier) [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: 477, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 477, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__import_trait_bad_signature.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__import_trait_bad_signature.snap new file mode 100644 index 00000000000..abb29a0849a --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__import_trait_bad_signature.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "f861d1b07a035317213c9f24c82378786af892e1a58e84f2fec0d25d3f1dd10b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some((use-trait ...) expects a trait name and a trait identifier) [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: 450, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 450, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7e2e07887a0a50f39ce8dc973f3652a3f46fec031976c3ddfc4cab6e7483ea4f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some((use-trait ...) expects a trait name and a trait identifier) [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: 450, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 450, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6546780810940e5861341a902750656d4402c006694e74e97253b9db859e48b5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some((use-trait ...) expects a trait name and a trait identifier) [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: 450, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 450, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "288dc9ca5aa569e6719411f61f3e6480c665b168d87d3e24867935bcf540b359", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some((use-trait ...) expects a trait name and a trait identifier) [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: 450, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 450, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__invalid_principal_literal.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__invalid_principal_literal.snap new file mode 100644 index 00000000000..9b0452e045d --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__invalid_principal_literal.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "fc84433c9b52b0d4803c8fe840b1c9215f0c735f589c5d6b64ca8c4fe00bbacf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(invalid principal literal) [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: 2133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "130efb98e76bd4bf5bf92932e5bf8b4f95e67f0a95d999beabeeaa83da1b7487", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(invalid principal literal) [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: 2133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a11404c6ec6599f185ab498175a378257b96456511d2c0d25a05c10fc6d8a464", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(invalid principal literal) [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: 2133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6b46e9a703d1fe8e4550ff47c0730535e712d759f962aed5cd7dcd6e74dea163", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(invalid principal literal) [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: 2133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2133, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__lexer_unknown_symbol.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__lexer_unknown_symbol.snap new file mode 100644 index 00000000000..4f156c3667e --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__lexer_unknown_symbol.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3390089ac0826e8e5677d5093fa3d0db6081e88e6a1763017efc763d3cb96b16", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(unknown symbol, \'_\') [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: 945, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 945, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0508eaacbb030d7ab8c559144680c55c225346589489205d34ca9974546c5dfa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(unknown symbol, \'_\') [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: 945, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 945, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "23cc160f0a2dc1ad2ea70dde315d656080d68e0d6f466bbcccceb9c6d918f8e6", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(unknown symbol, \'_\') [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: 945, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 945, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "98c655bf2ffb60660ecc0c813be906bdcc12c67d75665be06d9cd3af0ca372bc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(unknown symbol, \'_\') [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: 945, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 945, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__name_too_long.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__name_too_long.snap new file mode 100644 index 00000000000..5c8289dbc85 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__name_too_long.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3aac990e8eccaab09849db1eefbe3d8a8081bb4f6e0edc3816ecc158c98ebbf1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(illegal name (too long), \'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\') [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: 4266, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 4266, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "779812c18c5bfa5d5bc46f96f51baf4a9a92deb9650ea15f94a304985a2fe325", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(illegal name (too long), \'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\') [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: 4266, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 4266, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "baf12dfecf1699828b24d392667142d18e34151033098fd0935d9b6131a0568d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(illegal name (too long), \'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\') [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: 4266, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 4266, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9b2169f953038ca16c09963f461d4264337a6b477295327a671a0b71344436a1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(illegal name (too long), \'nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\') [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: 4266, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 4266, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__named_already_used.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__named_already_used.snap new file mode 100644 index 00000000000..16a54974d26 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__named_already_used.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "d51eeb1776df0d01d50f3abcfbaed53615d09be6a7c9703ff4f7cdc6d3cd940d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(defining \'trait-1\' conflicts with previous value) [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: 5256, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 5256, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0943b44aadead7da7b4d21d28f2d77ff35b3d2e88cfedda75d36cfc2857167e7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(defining \'trait-1\' conflicts with previous value) [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: 5256, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 5256, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3266c063c8e57f517354f04400c9366f2cc315d2ae504a1a7ebdff375d32bfc3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(defining \'trait-1\' conflicts with previous value) [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: 5256, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 5256, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "786622ea118525909afe9a2bddd171ae1316368c67bb3201f5cb171f6aafbbc3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(defining \'trait-1\' conflicts with previous value) [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: 5256, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 5256, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_1_tuple_only_parsing.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_1_tuple_only_parsing.snap new file mode 100644 index 00000000000..a6f049457cd --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_1_tuple_only_parsing.snap @@ -0,0 +1,22 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 6c79e8862a0f2ab828cb5f882c628f47089daf9c9bad65aa7461794609016b0a: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block b9a99e400844f09fb7c3f507ae032907831a7c86227ce0c87bda84d0c07074ab: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 522184bc06a1e815743e4f91ea94ec66e8bdddda03b4946f930d5b6be94635dc: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block fa5d21b679ea8e630f1a21d1487e476534e19793c8dccd4117111bcbe95b9039: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_2_list_only_parsing.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_2_list_only_parsing.snap new file mode 100644 index 00000000000..3e350889a7f --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_2_list_only_parsing.snap @@ -0,0 +1,22 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 33258e8cd8fd278ee235ad6476cbfdbb3308eab3e8d863c0097959a401aa72da: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 227a2b1443264a9d9c64b4a1961fa3b918c68eb091faf35f03c437f8e8ef6ac2: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block a87c72244bc9f2ff3a2cf1d7701566494b42e97d6264c39923f2c9bcf570bca3: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 7804680c060770d44a1f948c1dd5e24ace0387e686709cc1292c668855a6979e: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_3_list_only_checker.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_3_list_only_checker.snap new file mode 100644 index 00000000000..1efd4e45922 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__stack_depth_too_deep_case_3_list_only_checker.snap @@ -0,0 +1,22 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 77dff55506d7ea970b16e613927c6833bc90f3050dcb1e9465fb4bf4b7d532a5: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 107d0b7d94c0c6513576141cdd3d52ca114a8ba911a2ae679259f9a5e75b8234: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block e9368a8434daea84413ad8fbcd7b54a803a29226c661a39b0bfa45a439e566f9: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block ca7068f452dcf6fa11c583f3885ef3263afcc876a46e24cced6438d5e71aae65: ClarityError(Parse(ParseError { err: ExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__trait_ref_not_allowed.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__trait_ref_not_allowed.snap new file mode 100644 index 00000000000..bf29afb11fa --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__trait_ref_not_allowed.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "783efd19215215818004a1a755a4113c8db51a9da987f7156416f77402e70dee", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(trait references can not be stored) [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: 4857, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 4857, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "258e4b786f28e50c6149712f1732fc8edbaadc66045b842569b3f568e69771c8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(trait references can not be stored) [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: 4857, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 4857, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d714917c92b9f2870418a732d7969ae599541ab26d567326fd9693b45dab5041", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(trait references can not be stored) [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: 4857, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 4857, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "80ae9f5208ee1c834abff89104de36db0ac7021cf347c063e4915a9b725857aa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(trait references can not be stored) [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: 4857, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 4857, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__trait_reference_unknown.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__trait_reference_unknown.snap new file mode 100644 index 00000000000..d4795b317a9 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__trait_reference_unknown.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "68e84be6abc605f8b749ffddc651ac1638855423b92fafc696e2838da89dcf88", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(use of undeclared trait ) [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: 585, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 585, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6f1dcf477c079b501c01c0a4ba07f1b5373ee1dc0915dcda84d32c538972beb8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(use of undeclared trait ) [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: 585, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 585, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "845612d650e3a866ed0a3eaa06bc17a1e97f187e5bc754aeb8ef0eeca987edc0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(use of undeclared trait ) [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: 585, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 585, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4f96552d708a5f913c694f15363854992ef4697fefd6a6de486b7d52b93bd4bf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(use of undeclared trait ) [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: 585, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 585, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_colon_expected_v2.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_colon_expected_v2.snap new file mode 100644 index 00000000000..2166b8c97aa --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_colon_expected_v2.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "98eb69ac91e37f908772babde2e079f6da7a1a1e3fcd0e93e84ef8f41499e8c8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(expected \':\' after key in tuple) [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: 270, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 270, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "393754b82f7be25f966e20f32b1aff326f371129e60cad7e5f683322b0aa8c30", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(expected \':\' after key in tuple) [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: 270, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 270, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "04160cb0f698a7915658cfb640915438a4ba628344618718287b4cbb2ba33b0a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(expected \':\' after key in tuple) [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: 270, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 270, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "12db4d5ebaf35bc4d204ef9cc2267f8a43461db2801cab9df76463964d779625", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(expected \':\' after key in tuple) [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: 270, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 270, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_comma_expected_v2.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_comma_expected_v2.snap new file mode 100644 index 00000000000..adbc7bcee43 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_comma_expected_v2.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "68e84be6abc605f8b749ffddc651ac1638855423b92fafc696e2838da89dcf88", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(expected \',\' separating key-value pairs in tuple) [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: 513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3274ca447abd463375efce0a345dfa6d487b8755155b83fb406561652c26b40f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(expected \',\' separating key-value pairs in tuple) [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: 513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d1e7ce24d62ef867a54f907340c1b822463940d831681b827fa61e7838d89b13", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(expected \',\' separating key-value pairs in tuple) [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: 513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2cc4afd5ae420b58a4f56db971adafe6e247340b7b6de2a2b781610b8470accd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(expected \',\' separating key-value pairs in tuple) [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: 513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 513, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_value_expected.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_value_expected.snap new file mode 100644 index 00000000000..a3d22be5943 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__tuple_value_expected.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3dc6b7214944b41004b0fa3c82699c40acbc98ddaea3cbb348145f1cae9e93d8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(expected value expression for tuple) [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: 243, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 243, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2232b94d93cab4838c81aa7cd4f62a80d424f84fb143188f8404738b65d2adda", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(expected value expression for tuple) [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: 243, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 243, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d055d8656b3fd380347ebc8367d59d2ac7ec8178c1ea82ffeade318d62cf989d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(expected value expression for tuple) [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: 243, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 243, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b2887e8416a0ae564f170c622085354d60c003cd08f49f41a6c7241536bad921", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(expected value expression for tuple) [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: 243, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 243, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__unexpected_token.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__unexpected_token.snap new file mode 100644 index 00000000000..044c02c5e77 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__unexpected_token.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ffa3b803b8f265d11fba465d54eccf469db85763d8f9158d759d670d18eb876a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(unexpected \')\') [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: 1026, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1026, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b01b873cab94076bf1a8a752cda27005d332e0338c6ff2abb698609bf74c12fd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(unexpected \')\') [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: 1026, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1026, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "92a6c1edba09bc0efd90785885dfdd736c72c8a6e9413ebdb6ec49d2358cacf5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(unexpected \')\') [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: 1026, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1026, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b1279a667bec1c0a6f59fd5f7a799f5fd568f3ad327858936ae7a449dc2f6862", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: my-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(unexpected \')\') [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: 1026, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1026, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__vary_stack_depth_too_deep_checker.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__vary_stack_depth_too_deep_checker.snap new file mode 100644 index 00000000000..ed8908c0715 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__parse_tests__vary_stack_depth_too_deep_checker.snap @@ -0,0 +1,22 @@ +--- +source: stackslib/src/chainstate/tests/parse_tests.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block d0812ff700244ce536fb1d1c9908ba379a7a2c79d7e6a983f6b0ea8642a4f57c: ClarityError(Parse(ParseError { err: VaryExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block ff55f8bb36335962fefe24efe409683dba05c58fb93eb9f1769308958e4b2fa4: ClarityError(Parse(ParseError { err: VaryExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block d29b337d294ac1f84781068a835a3e6415fd82cb9a6f5c124213619204615dcf: ClarityError(Parse(ParseError { err: VaryExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block a52ef05d970bcd695a4bc19c254ea096edf0e711ab1571dcabb4aa58adf40e7b: ClarityError(Parse(ParseError { err: VaryExpressionStackDepthTooDeep, pre_expressions: None, diagnostic: Diagnostic { level: Error, message: \"AST has too deep of an expression nesting. The maximum stack depth is 64\", spans: [], suggestion: None } }))", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_cost_balance_exceeded_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_cost_balance_exceeded_ccall.snap new file mode 100644 index 00000000000..c4024d838d4 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_cost_balance_exceeded_ccall.snap @@ -0,0 +1,806 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "00d2dfb9b304e3da9831648bacce5cf34e153409b4579b71cdcb23da9f1387fc", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 2446730000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 2446730000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5ed1dda327b90dd93fd26b2faad1d11e7b3dc4774f91137427520cef2eeddbdb", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 41651774, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 41651774, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "17f264e7205f44903f97ea24eb9f18cbfc2a0cc87fecbbfca79e1770b6d4dce7", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "51261ee0ae18c4035b2ddab636484cbb7c1de9949bdf407c5d6ed28952503a8b", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "35e1db8216526bebc3bf620701ef0793631583ebf071413d29b5cab1918ac0b1", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1d2bba8aa62b7b27e19e1d96ad7b359b0cffeeda2078c5f826e6b46a7c06cd81", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d9bd3136f3f930a6f208b3fb44f623874edf5bdb17cf5a97c7af196cbb7022b7", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5534eaac07e3d50bd3833fb1cd4ef7724243ceeb0e35790b2b36dd2f7fce8a2f", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "56e0c84e6607221f02a999e1607471b8a653742e1886e305d4df8de397469496", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ca3c45d618dcaf232f0c5a80abc1601452e818641df640ed5e8b5b16b0691d98", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "71c4f21ad0fd34cf480278c582f2593188d6f714c046c8b814310a9a606a6180", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a6257d55bb28a0a585183c1fc7cbb778ca882c997d647b03c1c7054a72a70853", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "06e5fb05eaa53eaa7ec943597bb70d029dd5b19bbe6b83b3b3c505b7979a33de", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "89322908ee065c1dc4c1c7ab9c0a87a40eeab27f3794d9dfc07aa64aefb8cabb", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c885bdced1097efd688a45984dbe3055e2ea08917dcdd539ba1849911b025f3d", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8c1df9ed18489260405652f596f1dae5df44722324202f253a735685b7fb65a7", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3698ff35ec8eb7ecd5e123b29e960df8dc23474949b3ba837923e96991b0fe14", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5bb8a214451d72e3206f9187d7077f9210d23b70a0fb74784b7f2244bd712668", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7aed8f3362330b0d110607a15831c0e10dc161036fee5164a83751857baa45e9", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8568d1308adc1aeb753934b2e13dc499560bd54462e0a6727e186eb69c8f5fec", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fb5605912e7cffe4698229817c58035837e0567dcfbfc0c5f639b4bf7d914bc0", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d42b70c50b2dd260739734f8488b4e02d97f18ed25e54c93dc985b2755126431", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440985, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fe84ca33333ac73690367473ad3b443826ce71a9dc0212bf99cddb2575100115", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "41321ffe75dab588b9760684ac1d289d20d56c047cd6af3eb7644d19f7a0dfd5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6abf1ae89e1dc1c991ecca8d28f30ebbed7c8449f08820bc5fa1c0873562535f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: cost-balance-exceeded-Epoch3_3-Clarity4, 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: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 255187, + write_count: 4, + read_length: 1, + read_count: 1, + runtime: 10440984, + ), + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block fcde81e695b7318a2eaf641fe6031f37bbabc6a08ce2ed620f679e9e136b5cd3: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block c3f49409c2f4e8e4b5323cac54a78b6e00a9da2583df2ff45783d2c06860f905: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 932b6a61099a2f42a41948df7bd9cb17b4f91915f0d3eb371a8c1cbbc09e6228: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 8c88f0fa8d6de0b385d3441badfb3ebd67cc7cc14ab82cf05e984fda32b7a4d2: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 951b743a4b4d152a3423018e0c0755510c60e061a912daa83f9db7606bfa8cb4: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block e0c0b7d518d20fd5e0f096cf4b7c8e1a5a1a97156c77f6e57092830e71c7b981: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block a19d3fab56c01e506545b424a4dbc3c15ec729415084f790ede179bc9da33648: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block e459ac195e31be40b133ce0f2d4cd57d178ac0a7ff60a3b2f0977ae371ddce87: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 5684f68ca2266962f0add6d33cfb5fc49bc0650c568c3cd6d3199514ac366e2a: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 42e65eb8eb3dd0df7fb1119dcb1d388a8b94dfa5fc7544cc15e4049ef03ea0ad: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block ec66fbbe8aaad0b95be39b115436ecc3e92d6c259be8b6cf1862c8eb4babff43: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 7f7aa4f7ef04cecaff14050367a05c8b66fcf5f74f59d2810d800908a5fe96bd: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block d8558046f7490ddf4d88f430bd7a57ab191821c409bc1ccc3438d352e6e7facf: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 1d25e538a7c4944dc75c0dc623724a17c60f43bea7f795631e48f47a0a463d04: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 758d8da42a092b9bf01737b340e4d44f43a5d68c1b8b86e8020e53ab12d14943: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 6639e6f5d2028c8a5bbc2ecfe546a1237c71cc229713422cdeb17901021a0881: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block a1f60936e00764222fa885154682854bcbb0d73372546d0d225e3ca502b68fa2: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block e3f566634cf25fbaebb9c54151816f248d2145f4a0910cc36ce5d80859d330cb: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 88f3372bbc5d500d4030eba356724d4328b4018d9c87d6035db16cf734b579df: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 08483292338115de4d82acf499477e73be3b695a7ddedf737a4f1d7fe3adeb3d: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 552c056a4d8dd80d9c7c3f95814d909ba1bd312c11f5e99c4e69fd6ed9af6c62: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 4ba60b77afc52efc0bf9967c193a1ab130710a862f184c64249989ceab918694: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block feea388ebfe00f02e3cc0f87866e9ac49567a45a27093d020d080d8b2cf51f67: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 83f567c33c04f2595e9d0637081bf0c4dc511c39d7ac90a680dc08e4d01e4923: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 145c1e2761a19f561ff31f31f7c7ec3e552959de70c47862fc451befd74d2f43: CostOverflowError(ExecutionCost { write_length: 1020748, write_count: 16, read_length: 4, read_count: 4, runtime: 41763937 }, ExecutionCost { write_length: 1020748, write_count: 16, read_length: 480048, read_count: 15001, runtime: 49486199 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_cost_balance_exceeded_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_cost_balance_exceeded_cdeploy.snap new file mode 100644 index 00000000000..d925804b9cb --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_cost_balance_exceeded_cdeploy.snap @@ -0,0 +1,22 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 22f35565535e563262e98f8c1c79886cdd79892342d839082072861db2108303: CostOverflowError(ExecutionCost { write_length: 0, write_count: 0, read_length: 0, read_count: 0, runtime: 0 }, ExecutionCost { write_length: 255117, write_count: 4, read_length: 270001, read_count: 15001, runtime: 17953286 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block a98110cf4eec61626afbd0964f775f1828046f87279c8e49d54752a6bbcb2561: CostOverflowError(ExecutionCost { write_length: 0, write_count: 0, read_length: 0, read_count: 0, runtime: 0 }, ExecutionCost { write_length: 255117, write_count: 4, read_length: 270001, read_count: 15001, runtime: 17953285 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block b01f450c219db2ed86db7365393f2e0cd1c8a493dfd2f08293c8a71d68f5d7b5: CostOverflowError(ExecutionCost { write_length: 0, write_count: 0, read_length: 0, read_count: 0, runtime: 0 }, ExecutionCost { write_length: 255117, write_count: 4, read_length: 270001, read_count: 15001, runtime: 17953285 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 2c9df7260a975f4e10ef7a17f02c3144a6fc29cffd9edb84cc0b6eb3cbcc064e: CostOverflowError(ExecutionCost { write_length: 0, write_count: 0, read_length: 0, read_count: 0, runtime: 0 }, ExecutionCost { write_length: 255117, write_count: 4, read_length: 270001, read_count: 15001, runtime: 17953285 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_circular_reference_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_circular_reference_ccall.snap new file mode 100644 index 00000000000..a67982ada72 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_circular_reference_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "e30314abfb935d3c6852f39d97f226b4cc992c1422b07469e3714e54fdebac9f", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 1990000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 1990000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6c9863b697ad84ad9aceba9fddd5ca1815f6b0ad83a48964e82dfe4f2b78d6c6", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 331496, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 331496, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "18ec20aceca51d1359bc086afdf3860f1af6db15e741e0b3872ca2006ff80634", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2b3ce7b95cb306148a3509049f253e6623afa1e6771f497619e808ec4c7ed121", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2b28d48492c1f67f0a243aa0cfad09967cc384efa23f8badb91e2dd141597c32", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "76c52842806cc8c900b8fa8ba93a7ee3c5967d31bc541fdac2443887bee99c5b", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "05bf03ad111e04d0ed6c7ae694e5ca5c1a6db2572ec4d3a429b9619b9adb1257", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "602d398d33f54504184d66cf86c81649c1592bc02f356ee0c69719e7e214464d", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "10c590f13067f96780170ad16ff4a8cd36f1550582215a5562549ccba4711a4a", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0bb004a4d83cc056e9c4cd2f3d9dbec8cfe7bc1779da39b1a52ddd9d183e6bb7", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "80ae64d7c47943ec291c4eee067254778e8fecd097feb02daa1ba890538c5a09", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "757d7934d62079562e0863fe014e8af6f3d2c7d52c2348d807105ef31962037e", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d5a8b59c9dd88eb5ffcd838811c5c80c829d493ebc23b38a787396c9e07014ac", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e51ca530107403c5e5455d25be3dfaed8060a9c25a6260e0060d994df408480e", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bf0dc79fb7bf6fe11bc4ff9cfa0040da1d9e3a98ea675e07f2bad2b754dbdecc", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ca2a85ced3d83edb61210e62fc768256b64b75da2b7b3579540d8e4105ccee97", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6f0cd5014dee6ad9235d99cefe30a26abe3cc6940eef9ef00a5a3338772e57c3", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e339a689ffc5b994c70d9c8de84cadcb5460c988f852e8efd14b2027f10df2e4", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "39ca28768a8fac0a2068b81f51b07be6b9d3b7da2a91cbbe7ff31d2e34c61a2f", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e04fb35689c9aa27bb5b14dc00564ba5393af0248fa96b3e745b099eb0f7522e", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d98df017ba20705d6befb429dfbdad4db9b784ecf6a5edfbd73e343bef74c50d", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "62414fd8949080f2f0e3e5558db239c4241a644a48c5365db650cd032aabc88f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17125, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fa75742384ded9b86536b9e119e8a7ec59fca93ed323fb685bcd313212118826", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "814af64b70e8b852f40942d34bd11541a885be498f724165eb97c6c65fc4be53", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9df32f8f99f1e38b0ef18c7e5eda754b97bc366e5d85db998d496d557c3445cc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: main-contract-Epoch3_3-Clarity4, 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: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 199, + write_count: 2, + read_length: 11, + read_count: 3, + runtime: 17124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "73ba8730af86dee9c4bfc187ff94d1d30f95b2a18723377895f979a1c0ee723f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_0-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "08282cab2b773d7496f7d4852eb1418deaeb39224e8b225fc5dac310a80e5839", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_05-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "006b448afa9f8eb01cd61599ae46cb81132bcdadbe92dc09c0c05301f75a23f6", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_1-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "51084692d96b3024807eee444dd3c829e2f50372a3a2c9385ff58dbb3c68b506", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_1-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a5240d56edd5d573c77db288fefc08e46e9c5c5b03d98dbfdd6e96c35267bce7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_2-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0c7af3bc4f54a8edb4952aef59e4e2f9de40f71114fd50716d5b723d6ba964b7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_2-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c6c1258be6f8e56c7bfea9f0be8f5be29b8abddf1d2ba157be62bb1d5c138a29", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_3-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9eb12cfa476a720fe91f437af56fac59e76c5ebf13fb7454475208d051f04514", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_3-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0eecfef85d07233f01b829416b141956102f394529ac7345b55205a0af1c7df3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_4-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2299a711bfffb42cd170a780af002b2f26c533d63bb93da35a33a53ad87af6c7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_4-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5b4ad325dc8b0b5678bd137898ab0c42205a225476371f4f9fed0b3c61a857d3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_5-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "510aef9ac36d9a09bd479cae0084e0df40e44947bbb99505bf85f41d042666ad", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch2_5-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "82b65705426c806d92eb0420bf37511abf0576506247956136c81547d8651bf0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_0-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1bf62edbc72cfe5146359918e8a16788d0af2c01c71ad00f9a82a507f5452990", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_0-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e4aa2979b9d22dafc797f4c00367bb241ec641fcbb9b83ba80e215a8bdf4f2ef", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_0-Clarity3, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5185d7d4f9fd7e97ad62504463af0b08642d67e0e5598040289774fef6d8b365", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_1-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "61581cc4de33a71a2ab621f2f955dd7022b6d5e7b0c78c755bd78c7a60fb0990", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_1-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0920d40f32577df1573950e9a92cf20d697348c5c3278aadc42f7312faf7b1a0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_1-Clarity3, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "969e4f340a1b2a6b6487ea3addabfbfab77fcefa0740a523ca90f42ad28ef0dd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_2-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "006aa59ed0acf2553358d3a7eadf948e4d21d1a94609c6a9ff03f218612f1227", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_2-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b4c2cde013b3ad7983cf1f29afb27b824bf72d8f329b57b9cb4f69bf9be25c10", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_2-Clarity3, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2fb14efd9ecf8b9e2ecfe5aacd399a7c1158aef97367c4cb50324966d79f90d5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_3-Clarity1, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 1513, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "64c0cb90f673392434897dd5d05f016ab97e5461a35b14be989ef0e84967bdbb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_3-Clarity2, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4cfa667084c945fdd0826432f4bea252145d7994c7f43f1bb8ca6d865abc35f0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_3-Clarity3, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1e52951aca5a28f3a094691a1558ab9d0ce927d75f4e301f2be07de280edf7b8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: main-contract-Epoch3_3-Clarity4, function_name: main-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"dispatch-contract\") }))]])", + vm_error: "Some(CircularReference([\"dispatch-contract\"])) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 390, + read_count: 6, + runtime: 2322, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_contract_call_expect_name_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_contract_call_expect_name_ccall.snap new file mode 100644 index 00000000000..f218aba97ed --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_contract_call_expect_name_ccall.snap @@ -0,0 +1,180 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "53f9f52f7b61e13b06070417b90dd12e6f3f7f511ae8db2a5887e988d0a5f4a6", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 293, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 20648, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 293, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 20648, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a168b5b25042be30f8748e2b93a7e87745053ffc4b29030009f4f0162929e11f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 293, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 20648, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 293, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 20648, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1cd6404b761b798e09666861107191b3341afd0ea6ea8d08a0f64697d6773b0e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity4, 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: 293, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 20648, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 293, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 20648, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6f96dc2abd3ed8967f4979a99d7218763b6c7f097368745405592cc5b1e4318a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: contract-3-Epoch3_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ContractCallExpectName) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 420, + read_count: 3, + runtime: 654, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 420, + read_count: 3, + runtime: 654, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f7880489de41fafe855dae5698048a3cf5a547b4b715a2b0dc215f6e63dcf62f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: contract-3-Epoch3_3-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ContractCallExpectName) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 420, + read_count: 3, + runtime: 654, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 420, + read_count: 3, + runtime: 654, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3231b50b32de2d15f8f84e2f8197d1ba488b1e52954ccc921b00f8faa403c1eb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: contract-3-Epoch3_3-Clarity4, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ContractCallExpectName) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 420, + read_count: 3, + runtime: 654, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 420, + read_count: 3, + runtime: 654, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_contract_call_expect_name_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_contract_call_expect_name_cdeploy.snap new file mode 100644 index 00000000000..f76ca06afcc --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_contract_call_expect_name_cdeploy.snap @@ -0,0 +1,96 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "1db39215fa26536780994c01b73e2307740af39a2d40dedf7d2d11c86dc59390", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(ContractCallExpectName) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 273, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 19904, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 273, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 19904, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a8459c30613099d3d4859109d2be51076fb96c3b35f261d50211233795cb153f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(ContractCallExpectName) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 273, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 19904, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 273, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 19904, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "be6a784ffff194a48502f3927b37d0e9d7d1c9af9e6d9c97807bbcff97b9854f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(ContractCallExpectName) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 273, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 19904, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 273, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 19904, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_could_not_determine_type_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_could_not_determine_type_ccall.snap new file mode 100644 index 00000000000..a432f9ba75a --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_could_not_determine_type_ccall.snap @@ -0,0 +1,214 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "847643b0f429f82e39efe0557b9028e28e39fb96a44e47a413d025aa3fd49693", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: mixed-constant-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 469, + write_count: 2, + read_length: 15, + read_count: 5, + runtime: 40411, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 469, + write_count: 2, + read_length: 15, + read_count: 5, + runtime: 40411, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1e1c2a70d338329d148e1b417a2cfc785d1e0c26403cae5b97a8b49a34ba1af9", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: mixed-constant-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(CouldNotDetermineType) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "571c0c7f27296ce1732975416706e9502f9c04ec2ca0fd3c9009fcab7f09288f", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: mixed-constant-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(CouldNotDetermineType) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "22b69b427d8707933848097bff4c3c4108a8c28e7b8a42f792bfc2e4bbb4468b", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: mixed-constant-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(CouldNotDetermineType) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e3985286d1b6361bebb65227b3c751394afd010718e802ab838ee9d471d10061", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: mixed-constant-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(CouldNotDetermineType) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "28561492691efc4d14197ee64e9480d2b386a427b472a8dcafa5547c4fe18661", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: mixed-constant-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(CouldNotDetermineType) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e325646aeb312545532ec162e66287dcb0c6027c9c3dc51e2aaa7e65b7cb3a08", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: mixed-constant-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(CouldNotDetermineType) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 720, + read_count: 3, + runtime: 1426, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_expected_contract_principal_value_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_expected_contract_principal_value_ccall.snap new file mode 100644 index 00000000000..b9197e41055 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_expected_contract_principal_value_ccall.snap @@ -0,0 +1,64 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "042c2d4c0277139c8de76ad68d6bdae22a0ad3032dcddf774f983cf19d56c0bb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-Epoch3_3-Clarity4, 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: 168, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 14420, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 168, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 14420, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bccef81ca460f9c06b67be7cd7623a024bc5147483662a4dee97e706956c2065", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: contract-Epoch3_3-Clarity4, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ExpectedContractPrincipalValue(Principal(Standard(StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP))))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 154, + read_count: 3, + runtime: 1267, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 154, + read_count: 3, + runtime: 1267, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_expected_contract_principal_value_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_expected_contract_principal_value_cdeploy.snap new file mode 100644 index 00000000000..d47f8b5720e --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_expected_contract_principal_value_cdeploy.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "4bb61c6c901f6b64e204f2f46fe76c46341e0f51c7f13c647969315276d5a385", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(ExpectedContractPrincipalValue(Principal(Standard(StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP))))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 167, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 15231, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 167, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 15231, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_incorrect_argument_count_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_incorrect_argument_count_ccall.snap new file mode 100644 index 00000000000..b5ad291d6de --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_incorrect_argument_count_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ed3f610a55927c7a7cbf7de6247d5fee574dd1d2b1df3285e90fd34b3baa3c7c", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 581000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 581000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "36468a56a9f9c2e5fb7fcf50af4d4d198f02f886b35d438a0fa2a1c59214bd75", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 305355, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 305355, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1902f6554741528182f212e3f4eba5fe48d6332dc5330406a8a776170e7ddf47", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e6997ee0d6a141d1b9bc77d56be7c358956e348f36515600034d984d67777ad0", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4869c503fa48a3c74301507338d69c94ba157600c6fe7003b9b44038a2398646", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "74eaf2e6572fec90af9d7af749bf80688ee44b2a99111ba26730829cdc6ecc02", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4e4df840e75ec41ff64cba4bd048f1683ab38c8c3584bc242aa3788a13761359", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "95fb45ce59195697b11688256f60fab976b8ac6c67e80ebf41ba1b0d4a8ac6d4", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4488bf9c0e904e0210834de6bf63141aad89b5ecb2ae2f2b8a312e5aa89489a3", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fa414551d7df575c2facd751704618d494dc068475f9f953e0ecdf75c3bddae3", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "641e05f12705974a90264813efc0dbf71617889f212b56cad4f286496aaa0731", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d5332f04a571b0fd6542ec979eecc3163163c9b6aed11dcc08b2f1091b12a2d2", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "08e12eb4cd65abc2655ee1541a772e31764f7c3ac0674931669cc24982db8ba3", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3289b1f436a2a18aa212a8ea6812ed331291020d257cbd0feea68f3a4904c9ce", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "88a7a979a02daa4f6bf956b66f7e359e8fbe772f0bc5a4959d6915a780431b68", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "165b64e1b47dc3d876835d4858f6b2526591184167fcc8f7644e942465b66291", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9a6453316f4cb5acb9651249adf7990e8c207a2fb1fa6d0ee17702b0ac2b2c6b", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f41cfc739aab1f23e4524aa15d573044eadad274f957e3b27b471f76031ca03f", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2958b6d3d3a9744f04ad08845fa80c0de83c8a817f753a89742fb63fa9f132ee", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "499d0c1032ffa2bc6dfb8959d126e6c806124ceb62c29adb15f410462cbfef33", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "72ad797f9a37d3ada890af7b614a14bf80947e80ca63db8bc17f2d6e8a0ccb15", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2e4fa556200c255e7c71a4c6a045406c3334f3dd9f35b5acf49abdf386347e40", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3636c1407ebc9a6465ae0d0c77c67a029729b905bcd4d1ed31fa24dc4b010ef9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6a368e403b287e6ec18eee21ee07ba255c533c78fcfafb505a6acd2cc20ed112", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5fdb4b0d435b03451a27f8078cde76fa8321c005985f7214b48d25cd6ffed1ba", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity4, 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: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ca3686bae931eba40818795f692b3d6d1964a762d236d99d1fd4d305264b79bb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_0-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ea5dae15acd89206e411242284862ea345b6792ae794c945e78cfaff74596283", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_05-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9d45771948d43057bad928f93af967efbc30c3de49f7699c811fa83fa38d1f95", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_1-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c5de01767c583e60213d407cdb82cf9f866a9739aac2b809685ce44d38b55d24", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_1-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f4c1c48c0ac15b53a66354e0bc914a775be57ab29e5c8a3f90b4bd14382cdc42", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_2-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "99564a4325638e3d4dd617e6e716272e6a6f88d2556faf85d4cc24ea65a050ad", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_2-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d3ae201f97af2f2c485adc26a731d78f5568a7bff821b71ccdaeb98328017d43", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_3-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a037247e6bae145436588b16ee1154cb6bfc6cad47705d3fe838a72c6663dd87", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c3759ad48dc4d9150a3ee3d85acbd39f31a49254c068256a524424cb8468c420", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_4-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "69001e47270b189071dd4e97a4324786d5a522d39496f5b8e2ec2d8ee99d989f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_4-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ff99c8d584b7a5c368e158bc902eb4cd09126a6a2031f7cd5d8909b01c80b58c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_5-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "29c3bf328b927260123982166c09794a8cc5cc3991655b3294539fb0b35c3152", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_5-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b4a686e72c7c4e4470eaaaca44b55b683b58dba42f1dc3dc0aa2609caefbe889", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_0-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e1f864bd98506ce34c7d388ab09b517029b1d9e899c0322cc87d9f87c7611c53", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_0-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "af7b42f0ed934c0bd68d99c8d5a51fa051456371e87ad70fa376a3a7b8589a9f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_0-Clarity3, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "31a32b47c4960f431fa6512a15594b01e42d5650b7ab2f7006f93b82c5a768b3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_1-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5c5325975f45c783a5cce9e3713b0e4a37897cc60484956b4332b70887891108", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_1-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "dfc23fc307bd7ee26fd40da58f85ee8e54032291587e2dba4e3cec98740f029a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_1-Clarity3, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f296e6b7074b8f7aaeef2060bed6645ad841be35b997b43685d0e63e47847116", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_2-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8780f00088fbe7772b115b1d73568ce05ffb03954566ff80a1f1e2cd0d2526fb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_2-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "602195690f42943d238c7ad31cb316df6bdcaa8b2f23b4a58fd15952a7a0e335", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_2-Clarity3, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c9c5e24e6f2357b9ac5d66ab1f7222324f276aea3c882a11fb506005f5bb21e7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_3-Clarity1, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1716580b5e6e8f12676a0568a2c783693248d4acd3a610b56987119e4fc8b785", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_3-Clarity2, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "48a158bc5b8d8dad4cc452829235a5e5d892132a1f31a65d17aec2a6c68a9258", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_3-Clarity3, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f1c5474dad8123bde1a4a3aa6acd07abf072c07a1440ba09b5ef528586ddf007", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_3-Clarity4, function_name: trigger-error, function_args: [[Bool(true), Bool(true)]])", + vm_error: "Some(IncorrectArgumentCount(1, 2)) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 175, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_list_types_must_match_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_list_types_must_match_cdeploy.snap new file mode 100644 index 00000000000..cd8e24b4f7e --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_list_types_must_match_cdeploy.snap @@ -0,0 +1,124 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "393f4298c823d16715156edb3b106d5454d902082136e5554dd1c3770c65d412", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 584, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 36124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 584, + write_count: 2, + read_length: 9, + read_count: 3, + runtime: 36124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "db6b4faa9baa96ba49d9f3ae277fb2515d9f1300c225ac880e091b84c5c99ed5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(ListTypesMustMatch) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 584, + write_count: 2, + read_length: 17, + read_count: 5, + runtime: 43668, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 584, + write_count: 2, + read_length: 17, + read_count: 5, + runtime: 43668, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d6f51255c3770308c729d700ee968453009d3ba89c1015c84efbebb5cff5431a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(ListTypesMustMatch) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 584, + write_count: 2, + read_length: 17, + read_count: 5, + runtime: 43668, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 584, + write_count: 2, + read_length: 17, + read_count: 5, + runtime: 43668, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ebee74997f7c7de2466577f92833e7e2ea0296d00b42266e97e6a72050cc128f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-3-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(ListTypesMustMatch) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 584, + write_count: 2, + read_length: 17, + read_count: 5, + runtime: 43668, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 584, + write_count: 2, + read_length: 17, + read_count: 5, + runtime: 43668, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_name_already_used_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_name_already_used_ccall.snap new file mode 100644 index 00000000000..69572bb6565 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_name_already_used_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "f4e0d3a6e404cd12d01203d7147b2b3829289d41205f9970b84e3d18e59af349", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 1302000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 1302000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a57df37781c209efb537895f70ea1ce3526343ee1cb702fb6edbc449e4ddc960", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 317446, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 317446, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3d3c088b53b2fee517e82b5c9a75d5746cd3730ab8fb36ff2518d18298188060", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "11e2297b8bf54190aa919dd2c000b9c6c94aac9932caa3098fa2c8aacedec38a", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "318ded0ace5e713475f73575c25bbd559b983153a77dcb5112a97dde60e8bb98", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "650d1b2e5a75d2cf2444312f954f08b089796651d72fc25217f2608783b14842", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c357d4cb999d8fe308a5ae00a5f11ddcc185f5401b5db2d65fee83ac785da96c", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "febe896ea2c3b0a004b7493141df7dc1ac913adb24ca2691b51656ef9206b467", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8bc99f3d50a09e20b07d772236364e3df5101a266132ad87c8468de572777e40", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f371093f0f8aa0c9b0ba20a9940b7ec8d854695114c184b2dca944ae928aab33", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "134c208c7b0e0851c190e573bfb36cdaca1f0ad14217d94d7e2b2782471eeab1", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9e36ac749e3f62d7940d08383b005d162b9a9db1d14daedbff2619bfe2925d13", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fd3f7692e015812e5ede8ee718aef1ae4f4f61d11564a38a9769512ce371b00d", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "dbe69a5fd2485f13451e35194913e3ee254061bcc0eee09ee18fbd3b5df1fa80", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0287073a128c2221dae29de2b8b1438758c6a5cc9bbc6352dcfeed5e307a5ebb", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7e7638c4c2d4e0b215954d35ca343cfc40e4c81bcee3580bd7f7835f0753279c", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "31961995ee20500f5d3748b6769ffa97bdebeaf99fd7a5f93df339cba83555d3", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f5ead5e4b38baa33ed414ddd3f408ca41670e045148da6529698f750765b91ae", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "27b1b8239658500591e6e059fbf0e3575aa921e45f06eb40ff15777184f5c10c", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "15a62e33a22ff8fb35091044cbf4e54780a216e3c133260c469f22005ce5bccb", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1d400dfe32efad8d6558b009fc4236b82dea9c6cda932787f153f53b2b1e0d74", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "843d10170314537c886ca8fa3695c568dea7046f8bd62f40453a36bfcc56be53", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c4447b62c70bfbec9c7c29044c006e943e0962c664388c3fc8c73c85571faded", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f860b425b0a24d052b25d6504eb6b0308b5775e2eba80ca314ece1fc00ffed25", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d5fafde0659ea6d7ca022db2ebaa43511d604414007283e0d31b1e36061382aa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity4, 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: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 129, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "58de320ee66487b81ee1a0b60657e9bb2518c9834a8478c183988c829336928a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_0-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "12163f02bdfcb39eed04bfd3db5742238203566f4ed7cbd9bc012b5c547ef71b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_05-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b136b9710eb4fb73d09ba61ffbe3d209518dd85b09702489255d103c1541638d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_1-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "181b3507d1497ba65ec047c728a7c515da5374df3452bcb0731755f9d3622fab", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_1-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "93d28c4bdef1ee09ed6604f042d424d7a835dbbce315ac5133c6d57a9e41acae", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_2-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9e727f35017a354bd7754efec998a6ece0b962beb2d90d9e219b820de911328c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_2-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "50ab151d51adc014337495c4b3cd5e217c285a59db06fdbb7f950b96e88f8389", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_3-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "409eea04f777264cfaca9b5f5eb5bdff6bc9c3d815ecffd559e584b5bb639558", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "43fe1d75da1c49d145845641316c165c279cf17c2a2de430081b2c63d7e54e0c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_4-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5c4565617b48310bb24a05b93744423a19b9b8f176db6681584da25a2ebee661", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_4-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5fd9b6cd8ef7829ba3b2a925557ef55091c03cbffba8c4c9937201ccc58426ee", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_5-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9351a0151549f164db995080252d6e1229fc2c145a58d0b3857df56ed5761527", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch2_5-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "882bffb1df6caa8c7a3ae1f4df69e07539091b7c136c6464a74dc6806f1f683e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_0-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "be1af4c976d0f75affc9fe6ed32e43df7a9c7d9b7bb3f3160d51b64f998ed419", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_0-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "390039c3020798e5da7656c8429bdde39d128c2951e203eb0b0cdb1afd041492", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_0-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9a37c53b6fe133e8e779aebbeeecf887fd43f7c82d16cad7a3b8d71968ac0511", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_1-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0493182ac6c3512d8458195cbe860a4a0bd50032bfc3dc770a395a9608357ec1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_1-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a3224c68409954dea4b2883c93f0f06497af8f058f6b9d7caf26f1ca2260cce4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_1-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e09314de0c69c9b2d3c2e03823dd6ae53a4da5cfacd825cf73e8294a7563bec1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_2-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c919a230104991bc1cdce07fd4f997c4e814a88318b51b0f08c67d95e871c372", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_2-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9d0d8c5dbea91e1a1dcbaeb3d6a5d887df6b027fb381796acccb280acd51d238", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_2-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1e00c29a0323b1f2d3c99defe6846deb46a887800e1e99d686d9d91e6f3f0617", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_3-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f1b3aa27b34c01e650f69b7cc3004e2174bed006abd3830cc703f5c6a6b4474f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "68288104dcf1f5dbea25a70231753b6ac2ac3589f4016522fdc2a3d9d038829e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_3-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8e9a4e6305582d6c8d53b1e6e4cc847b4218008e160fdf1abf0725cbb0b180e8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: name-already-used-Epoch3_3-Clarity4, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 115, + read_count: 3, + runtime: 510, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_name_already_used_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_name_already_used_cdeploy.snap new file mode 100644 index 00000000000..463a6dea061 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_name_already_used_cdeploy.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "8d956af6b22c472853f432445276d339d3b57589470915f8cc1fad0bd18c925a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 41, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8785, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 41, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8785, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8b7761df3fd27db36b9404e749873142c142765a57f8666182b8ff94d71f7993", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 41, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8785, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 41, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8785, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b7d9404c1c78ec26e95098011f38980125abedd76afd12ca0f0125ff896003d5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 41, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8785, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 41, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8785, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4b6f883ccf3127c3005bc46c750f5e31ccfcff306529eea14dab05c44b3f0568", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(NameAlreadyUsed(\"ft-get-supply\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 41, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8785, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 41, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8785, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_no_such_contract_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_no_such_contract_ccall.snap new file mode 100644 index 00000000000..585272a2c27 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_no_such_contract_ccall.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "0221a8b28a132a04a0a36c499529d642bf875c1ea6a8e3ccdbc2bc944e65fa5d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: non-existent-contract, function_name: this-function-does-not-exist, function_args: [[]])", + vm_error: "Some(NoSuchContract(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.non-existent-contract\")) [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: 0, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 0, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_no_such_public_function_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_no_such_public_function_ccall.snap new file mode 100644 index 00000000000..a965062d335 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_no_such_public_function_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "c889799e4de48612e7d7ba3e0eb95fe47b6870197435df7520669f15689c180b", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 399000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 399000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1359140896bec9b1acb64235eee47680a1d721ac7240a82e61d3677ad3ad3683", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 302367, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 302367, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b5ebe6e84877ed41aafe40cbf9f816e6ec8dd34ad0e795a49942cbdf107add5f", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b005b4e7f8dce6505d991a4dc6b3399ae94d495ce696680325e48cab9f30c8cc", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "91244f2f02d028f34ce26198943dc545f30945a5dcb43ac15cfa6cdcafbfb0dc", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ab6af4f5bf3c4eaa2f2c9815aaacb89dabd118f7c8ca9948a0b4d882f4c671c5", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "54854b0dbcb7ef9db62ab2e8527b41dec3f7c03d6851937a8166e61288b3fceb", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a5dcea478ca7c2c6d299adface6d78513a4766aa2bebecd4db89e9839b687c84", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8cc61cf2d990cdb44e1675c198a406bca8340652516e3f309b762c39c4bb9f64", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "480a24f25e033bca3d82b1878a9ae0e7dee9d1c1ce904b220b07fa807d914071", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d5eb5aa007814311c64d7a60ecd9e549a47df8da2004957895fdc37bd5430660", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "070b98203184b1aea4040120753af86e97330a1312bccd6d0f268bffc11b2f3e", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5a62bfa74126fc91907f1ae5bc5fcc3828fa33fdca01a8ff396e51cd6db99a82", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6871e7cbd95048d51835458b4630228cf88ba339a7b71794c3f89129295e167f", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "089ba793dbd04b73c0c2ddab3760100159d18d9bcbfcbab27ef8eaea3b4d63f1", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e33ff5f841e1b4d13aa8b462e5bc43b9c5134b976fac7f5757321ce2f3cb5a90", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5aaaa96e28eccc941dcbe283e728ec424f4ca5bc11973f56439f76be18331107", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0d788443658c159450af44994bbe2719ffc52b6877d620a9969d9f73e5bdead0", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "515038678e8186693f22c388d9bbcb271e3a703f09a6e048896bfb9c57e0f27a", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "32d348dce6d677744bdf5364c329e73b07cc0eefd3bf5f3d16a3bea0c1e57963", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3a5725c16b3fa503fed45cef31fba9543ddf585c90c1aee4711943ef918056b3", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f99b9c2aefa766fd22671690af5c2d8b6335269059143b5ce9920591b6cd4285", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1a93c3bac185c4c1f9c6a2b916e47e006bd2e037d8a0188600121e200900dcc7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ee337ea60bce6d1b14a935ad2d453769ad3e30c83a5cfbc8bd72353e68fb0a7b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "394fa626a4f61d7235383db01ebb04e496680b08d9dece341950002de66ec424", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: target-contract-Epoch3_3-Clarity4, 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: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9025, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cbe51844c7d4677c3553ff36aa01c738c1e2412168658dd6279cb221d8dc2a1a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_0-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_0-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d66930a9cfe5c7d885e3538fe882ec14cd7afa12a66e1c43c56c3a62742d0012", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_05-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_05-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9a0a6d012f45cce18ee4b27c03a51a0a51819ffc542a0450bf9c3953706e268f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_1-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_1-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d1d132164101d58d78d6af0d7e122ec5960cda65b708059d9ea9a7516f4e1b57", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_1-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_1-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "03af72d7680982a44df15e278b6faa40b67b82c89b089e1b6c617669e9daecfa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_2-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_2-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "36af755fcbc4ac8e24a6fccde09fd9f1c5acd13f2623d6dbfcd48a9fac6143c8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_2-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_2-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4441e22d41932b0b0ba8551598c0b6b44fcc91268e30ee4780c3c3f4f9c6ccdf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_3-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_3-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5dcc73c7c669293d1ff309d17a30153f72310f28ba6718ee35a7c7450c425c06", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_3-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_3-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9b1400ea332f81787de137b228e208f6484778af7cba851139ce0df130a44e47", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_4-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_4-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "46e4848d397e044dbe90e10aa538b4a5f9549a277555b8bccd6b5b9f3cffe74f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_4-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_4-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "844668522b41d2441394c7c5f2daec7539bcb113058ea5fb4c25b62a71cb8067", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_5-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_5-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5cb2c70ad1cc8e6fdd5f2599c723170d6c4db2c560690fcab45341b0fba16aa5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch2_5-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch2_5-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0d2ee74c2d8a1bce5ae0450e35b69d7306bfa1a8b7f3c9a0d6b2d0c8e7711116", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_0-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_0-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "af70d4d7b9c8ee6d013f08841f4074887f7c5326ecbccaabed5940b0c3124fc9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_0-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_0-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b026a9fb6f21393d7508be09a58135c127bdcec6c4d314b58f6451a0c6b22f45", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_0-Clarity3, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_0-Clarity3\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2b53e6c2c348ebe800af5aaa152ab32753daebb3754bc66dbf4e64eb24f877d5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_1-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_1-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "666289a52daf8b33258ba12696e284d1ab90fcd351ca466f4746d336727546f3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_1-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_1-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c488cfce83b19ed581df1f8898f03a190febcba39fcbb96cbb63500b038e7d63", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_1-Clarity3, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_1-Clarity3\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "84937da157588e230acd65f71e1314ff2fac9a5da68eeb0122981bb81a53f749", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_2-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_2-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0507369ead42fc9aed5e58946ba468807c54e0c6412b94e5ff158656e38926b8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_2-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_2-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "77b50f275df1f45b469dd7016b1dbfc0d95143c4510a5d059e5f5e10a635361d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_2-Clarity3, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_2-Clarity3\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d397af88e1b068fa5ae2dbdc3be4b8635089a2f7e22fcd00b6801fd27f598656", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_3-Clarity1, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_3-Clarity1\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "24d706f4c2fac1f9965af014cab211a64eb28fc3f4b5dcd8b16b5456ec4ab50d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_3-Clarity2, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_3-Clarity2\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f93dc37bc631ce4ef27160b773fca35d3131b71b5dac4043a0d3b282ca51cbbe", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_3-Clarity3, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_3-Clarity3\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9655425dde017d1c8533cd6e59c1a31487a097738f47ca96abc51ef1c68578a9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: target-contract-Epoch3_3-Clarity4, function_name: get-one, function_args: [[]])", + vm_error: "Some(NoSuchPublicFunction(\"ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.target-contract-Epoch3_3-Clarity4\", \"get-one\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 35, + read_count: 3, + runtime: 114, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_return_types_must_match_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_return_types_must_match_ccall.snap new file mode 100644 index 00000000000..727c40f22d4 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_return_types_must_match_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "6d29966d0b561d8434af4a76a31d324cafc83fd68fe61f26b445ba0285629dc8", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 1979000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 1979000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ce68d03e5ddf7e279fc0137d259a61ce1868fd54e36452c22132c2ee81406126", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 329721, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 329721, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c7505c97c34e40526e6631a7146c2803c90347ca2b8dbf241c85caef445d7199", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4960acba07546102d64059e3c8229daa79727dce668330321b0cc9a30467b06b", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "866722f5a8449547998d2dc4c6f7cbc81d0bd3cfac33d84f58504a56c0be7c32", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a7233a1836bed895dbc077fd5ec57b95f3d2a58d88fe070eb6ebb3ded4696171", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "02087a97837bc13e5f69d030b778e601aeae134ccadf9a89bcd0adb5df628bea", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6e939af08c52610333aac6560e75a9c687b4825df63628d341a76b66a9876ad9", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5fbe7f1f54fc8da029d873eb1fcd610e7e9432a6e6071a55d10b129c77757bd0", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4bae187e97ea4be2a961d7d541d5b7562d0f8d721cb6b41f10d65c0f0a8c6a06", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d246f20e23fcdb779fd2519a6aaf1fcf8da3863d902d8570d84c131ef8912536", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4454ed9a3e8e5dbd6aff0ce41dabbf0cf05ce83a4b07f8a55b8141e14be374a7", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cd83d8651be3b9787d6deaffc94309fcc7792930d3c581651ff1f1917c7c22cf", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f6f3f4b7b52586da9f983bf837170069015e2013a3c2c78950081f0e80aff0c2", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cc9d00480100d03f4154475138c4b83d36aff945c5341736296954c5811ffd9f", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e109f68892573f274ebf04c4d805e432db391a946a75a5e45c70bd2b84d3edb2", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1037010c0c429d4aeeb40f89f2545045d7c865a2072e68a49c408f041bf75bae", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5bb97a0a3a90c4bc1494ae7ac9dcdbe81c81592e78b94309d4e3b266d1932de3", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ba3dc6100e2c3bae8236039ac8114b443e363333defb83cc3ad075de58116a9c", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6c223bdd937325f0a4b5668bdb22638ef1b9b87471e302e06c9a2547328a9df0", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "53b127e62476175d65c92ba6282f372cf947f1876f541f4dba2f264f28be1555", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "588264eca2dab1e4a8cabc5fe1ffa08a1b857d3d6b0db0e1b3ab4beb432c7024", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15501, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f82242403a6359dee89df5271368075dce8485ea8bf85b5533853b265c1d234d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "40ec6b9b3a3e67d79dfe405ae62c409a945e2b292f544e7ed4df60a2afa2eb96", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "358b03e56fe4223fe65cc79fc4adf9671a3bd0e6818c2247888bf4a8d1df56a1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: dispatching-contract-Epoch3_3-Clarity4, 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: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 198, + write_count: 2, + read_length: 6, + read_count: 2, + runtime: 15500, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "09a55714f1c553b2b118063f7eb03d1bfa8206a6a58571e26ae3989828bc6fab", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_0-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3d317dee7d525107e57f3722314a21ae378708dd724083cce958a6aa1854a63f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_05-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d3f7f11dffbcff7b105bff31d5b5497aed3c2c1427d50336b79c20cfb0be5855", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_1-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "56ab638454f7de7406fcebd6dba33e20638ddc5f4444e42934252191a832e89a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_1-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "81a3d8800e48c53befe9a5882c298798186f5b29e69e4a7e4d22e1bd6b2bebbb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_2-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "411b6501dee6d673937cafeb5d36b64a54ed8e54adddcd405528f36a81149891", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_2-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "18070bc682e2538f089d187f34cb51ddb497a7260473ec940528e50421fb9a22", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_3-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f214f5d80f075867f1e7dbfea7d063f25e72b986576b96ad26ce3106f00b6668", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_3-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3de4f4e3bb25bd6f2ee8ee19a91710a4572c7fbf927ebd6472f9902ffe389a19", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_4-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1eeb9f0d3476a6543a7aeb2d47fe86298cc9f941340283c6b274dbd1516f15b5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_4-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "547be8ac65094859b58b495af983490133ef4c41e99371637df7a15a2a9a6504", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_5-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2d155007584e04132126a2037d9fb3338b3acd54ff3cc5e82082cfd83617aa46", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch2_5-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "109e032fd7c2434e4f0c67ab3cc5b256b44eb2541601cfd0fd334957d858566a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_0-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fb8977134c06543f575c9c7cfa143360eb63cdecf70e7aeb5b71cc00678471e9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_0-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d302c459083a147e349e38cb2126589dcf7dd7f9ba7dd86b57e6cd1c9db1d495", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_0-Clarity3, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "229e166911ccb9f427d67ae17dc45cd3a3d177a12c27f101c24bb8ba3e53b7f2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_1-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8420a6dd88355df92d8223e69ee5a12d673a2880140cefdc1426e4a05a22eace", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_1-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "94727636a33448261b28caaa876d4e88b2bbd4e077a5eb184aff71bbd3035441", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_1-Clarity3, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "25a95cb2798cc614604138d50ab8b58076d2c0df47512e1a7f14e780920f802e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_2-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5c9267d511d1a81aa8db5ff2e598fdb35b3ca072cf607b14bd7b6e1b05504dd7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_2-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "68a053187b2a4f8d09129dfb49d46bde9ff856483c65ed584af6039f819c199d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_2-Clarity3, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e80d1d1cd3007ccdfacf6c2865e5eaf82363fdcc6c016b5ab0fded5281edebf4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_3-Clarity1, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8df643a526c4418c25db06b1e072cdd0a2c5244b88bbc0da6dc1321d05eca8aa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_3-Clarity2, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7c260ca14023d26ebf12fa7d37361d397b48b483e8d5b5128acc8b52b5fab5d8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_3-Clarity3, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4d7b65a21dd7232130f149c576e3cf63ceda9045ba4dd198417a540307cb4872", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: dispatching-contract-Epoch3_3-Clarity4, function_name: wrapped-get-1, function_args: [[Principal(Contract(QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"target-contract\") }))]])", + vm_error: "Some(ReturnTypesMustMatch(ResponseType((UIntType, UIntType)), ResponseType((IntType, NoType)))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 216, + read_count: 6, + runtime: 1139, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_signature_too_deep_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_signature_too_deep_ccall.snap new file mode 100644 index 00000000000..1ad456d3ed6 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_signature_too_deep_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "04c043e146389379498d7293de3c74226b735340f46d4bcea96d0eeb58b4c6b2", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 20535000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 20535000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6585bf8a6900e2e23fbb934219a348890b5bed161cdb4d4e85264236a9a09b9d", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 614518, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 614518, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "caaab43c7c4aa3ed8b8de119f0accc062f2ade25b07fc62cb1bfc54be9523254", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "46676941b4f5b01de06b8006e7f62797d7c006b266d3630351bcdeead71471f1", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b80b574d8030b9f26ee87c8888e4dd4077914b59c932ce6d34712644e349932c", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "43e2cca3ef9e3b99760b63ba30a3d165737caea4576af9699b4ba5add451aed7", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8f449486f585cac271c62076ef9f6b25d21b39b24e05d8f929ec52ef17d6eb64", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1ee61343873e253766db6a61c9e4d0fb6a82f569a22b00c5a03a01784da2a886", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "773bb8dc2df3b06cc42a9bc723680cd0a09c1b0c5f1641d748838bbd89d1bf5a", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "06b2aeec8485676e4d74db0034c32c3df3b3ec9db77ee575d7b8842ceca61d7b", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e4fdb5b428cd56937d6e3efde6c4c59505684f2955eef974b3b8696ba971b292", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cd4ed945935c5abf16c295aa1cb29f2a36993136f6fcd964a4c2ea28c78192ea", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "054269e54336ed4dab27e7c98a355c92aaf93bfb760468e352bf121f717c8565", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ef769b2b61474be5edf02aa7713328d8ec8fbe4df7a3021dc20fffcd2ae8119e", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d74279f1d68be7b63fef00b256dcb9ffda3d7f6094594d9a0c3dfd600539b0d0", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "be6e03f7d97a4ba3323419e578fb794840c97c989070e00cfdfea1d1ba4543ec", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1c9d2a32452e1cc0a98dc0079866419b5b7cab0494177112f2e37f9da53a6e44", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5b456d3b9aaf3543d99f6907a1bdc2769df7349bffdebeb9ca951e2e72050715", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6033127651c569262f283b11ce041fcc0fb8340357a04bce193f57e11c6dae8f", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8c3858d2711424e392f01cae0bc6420abd676c9f433650f59b91f2a41abaa83c", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "23512cc760379bc7757d303c5087a43cc18f3b43c8b7107d4918f63d8f505224", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "016b3bfbe74720ca8904ab58a09319ab4675fd656e1006986c191996e08cfbfa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d5b51d2468117ede33f13023c6946bc9457e987f0cb65c458439580c9a22911b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "654e1664dc7ad498139176209340d1c764796082b9454edbf0da1dbe79339eab", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d74a7e2669cce4559e2160640eea85e3de09a04721a09cb316fff9e5fba110d9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_3-Clarity4, 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: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1913, + write_count: 3, + read_length: 1, + read_count: 1, + runtime: 91642, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3e80113602e7e9fbbd6549e14001ccde435dcbb71c81fe09b72df04e854e0541", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_0-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e4aa7442cb4d0458f0145ed359ff05ff07a25e9ed58bde94bb0585bab603cb90", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_05-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8cb3643e4730715acea56dbec214b5aa2df0eb6d917b11056b11ce8e0ce92927", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_1-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bd59a1769936c4e24e3792108ace54edf93b6a16ce33f74ad1a3be5881a06d98", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_1-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8911566d9cd0937e2f91b3ed1f768db89fa0999fe39d815ea69df64f349d904c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_2-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9c287820f104adcdeb35176150c33da7209f2cfa0f978df71a6dab7c01bdd55b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_2-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7c7a5d864faea871222e816dc470add38875262627365d62a21868def62dc086", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_3-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b0ea0f29240f776e0599af20e302cc8641b8fc70f84b848196f7b21a55899387", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fe2934b2f2a30901e78d31af511829262ad3785e7c149653e44d760cd2e44309", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_4-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c3a5070712cea1c647868ad13890b2fa2d0e8141bfc8c91e991f4383a178c19a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_4-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6072c3d544d525efa99eaf0fb574dd691d819d7c416a99a6927507e33ce5f8bc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_5-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3fcdcdd53bfd3fc84ad869983ca07d2523767cdcfd4f91edd4fddfd9f9e81d79", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch2_5-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b1f7501b4757350edb93f0b16535284d291f82af1b700ee9832da3adfec78252", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_0-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2e5499f8a4b39a44a1586bca2418ada3c2a15103cb24f4e82b0cc8cb1090d01a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_0-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f6e7bd756bac5365e5bf7c9d15a4590fc824cb270d1a3d4d8d38f6f015af2cc1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_0-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9720fa03e4ce6e3755d9cea328b367cb4a3f8ace95678f72553317e1a60f43af", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_1-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f7a9adf388776be5fe01f95a727ccc72c21f0e78c065986911c4320ec413ccc3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_1-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "84e1f0615fdc63e22800e16c890be71d4ab5c7bfe4133aee08aa9415aee27937", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_1-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1eeb319c854f4a16be97bdc2e1284088c68bb2438319ff606d75d87f7d26f0bd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_2-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "88ba2bf743b194f6742c7781d7ab6972504ad181cf28190b8e4ba6df0ef6678c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_2-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c809fd86adb30987ddf12065afb954fb8ca29a19c1d14adbef88f9dbace09e76", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_2-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3f94986943d66af81f8a6b281b1a219376df76a77e365640e5830f9a7ad94491", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_3-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "78c89b099128ae1a8e2016cb5b935c5b291ca8cc3df1ac7a557921e7836e707f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "72b78093730a1e493449c382c0395c73e566fb7173703ca65c7da19a1a708db3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_3-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e0e0c76440e9184410f867f5988e80dad069ab3c946cffe307f7d40acc932514", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: type-depth-runtime-Epoch3_3-Clarity4, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 117, + write_count: 1, + read_length: 1586, + read_count: 4, + runtime: 7959, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_signature_too_deep_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_signature_too_deep_cdeploy.snap new file mode 100644 index 00000000000..3eee6cf6c93 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_signature_too_deep_cdeploy.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "487cba889edf498ee41d3d2ae5afee48cfeb0330dadb6483c128f33e7edcdae5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 1963, + write_count: 4, + read_length: 1, + read_count: 2, + runtime: 95289, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1963, + write_count: 4, + read_length: 1, + read_count: 2, + runtime: 95289, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9942de61e187a807462e98216f9210c148444f92756b9edd7a10986cb8cd51fe", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 1963, + write_count: 4, + read_length: 1, + read_count: 2, + runtime: 95289, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1963, + write_count: 4, + read_length: 1, + read_count: 2, + runtime: 95289, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6ba7c17beab0113cbf7a81572464787b09cb21e468c68fd351f57171104107d1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 1963, + write_count: 4, + read_length: 1, + read_count: 2, + runtime: 95289, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1963, + write_count: 4, + read_length: 1, + read_count: 2, + runtime: 95289, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7061525d5b2de60fc6a687b9860b3d6989a638fb776fa5067824f685196c230b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-depth-runtime-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(TypeSignatureTooDeep) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 1963, + write_count: 4, + read_length: 1, + read_count: 2, + runtime: 95289, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1963, + write_count: 4, + read_length: 1, + read_count: 2, + runtime: 95289, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_value_error_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_value_error_ccall.snap new file mode 100644 index 00000000000..e093b50bd03 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_value_error_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ed3f610a55927c7a7cbf7de6247d5fee574dd1d2b1df3285e90fd34b3baa3c7c", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 581000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 581000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "36468a56a9f9c2e5fb7fcf50af4d4d198f02f886b35d438a0fa2a1c59214bd75", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 305355, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 305355, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1902f6554741528182f212e3f4eba5fe48d6332dc5330406a8a776170e7ddf47", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e6997ee0d6a141d1b9bc77d56be7c358956e348f36515600034d984d67777ad0", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4869c503fa48a3c74301507338d69c94ba157600c6fe7003b9b44038a2398646", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "74eaf2e6572fec90af9d7af749bf80688ee44b2a99111ba26730829cdc6ecc02", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4e4df840e75ec41ff64cba4bd048f1683ab38c8c3584bc242aa3788a13761359", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "95fb45ce59195697b11688256f60fab976b8ac6c67e80ebf41ba1b0d4a8ac6d4", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4488bf9c0e904e0210834de6bf63141aad89b5ecb2ae2f2b8a312e5aa89489a3", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fa414551d7df575c2facd751704618d494dc068475f9f953e0ecdf75c3bddae3", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "641e05f12705974a90264813efc0dbf71617889f212b56cad4f286496aaa0731", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d5332f04a571b0fd6542ec979eecc3163163c9b6aed11dcc08b2f1091b12a2d2", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "08e12eb4cd65abc2655ee1541a772e31764f7c3ac0674931669cc24982db8ba3", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3289b1f436a2a18aa212a8ea6812ed331291020d257cbd0feea68f3a4904c9ce", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "88a7a979a02daa4f6bf956b66f7e359e8fbe772f0bc5a4959d6915a780431b68", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "165b64e1b47dc3d876835d4858f6b2526591184167fcc8f7644e942465b66291", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9a6453316f4cb5acb9651249adf7990e8c207a2fb1fa6d0ee17702b0ac2b2c6b", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f41cfc739aab1f23e4524aa15d573044eadad274f957e3b27b471f76031ca03f", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2958b6d3d3a9744f04ad08845fa80c0de83c8a817f753a89742fb63fa9f132ee", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "499d0c1032ffa2bc6dfb8959d126e6c806124ceb62c29adb15f410462cbfef33", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "72ad797f9a37d3ada890af7b614a14bf80947e80ca63db8bc17f2d6e8a0ccb15", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2e4fa556200c255e7c71a4c6a045406c3334f3dd9f35b5acf49abdf386347e40", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3636c1407ebc9a6465ae0d0c77c67a029729b905bcd4d1ed31fa24dc4b010ef9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6a368e403b287e6ec18eee21ee07ba255c533c78fcfafb505a6acd2cc20ed112", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5fdb4b0d435b03451a27f8078cde76fa8321c005985f7214b48d25cd6ffed1ba", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity4, 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: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9659, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ca3686bae931eba40818795f692b3d6d1964a762d236d99d1fd4d305264b79bb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_0-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5f235469571b7a9d5fa029ea507499a59bee8848a2bbb6b01d6f594c20a5c0de", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_05-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2975cdebc05f02663e73b1c6708775f50d1701edae5c20048eb6d64141ec4f02", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_1-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b30beebaa39f77741ea970282cc6ac6fb75e262aa29aba6cbc1d86c32d49fef7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_1-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8f16d1ca7b8a07ae5ab32b1a2efcc710c7a7cab34e34a76e7d24c2afc9f8943e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_2-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c450e44018e55bd111489da95ecf9222dc5862f2a7d43c384b07599200d77f03", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_2-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0d17a6437b1b176487dcc7acb621fca819535c065ffebe6bc488dd364cd73716", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_3-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "27d0f3c2daa02dc7c5ccf3581fe8cbed32a4cc893b78e1d20b1be97386039250", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b6172c9fac497ac0c3fec6e929665f33ef31e1afcf678ad40444c73b98307838", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_4-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ff5c3f74bffd7acbccd763aa3d875d9927663448240074c9d0e0355ea4172df5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_4-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2abbdb54575d119899fc60e0593ca0990dd38734f60059d5006c07fc2fdb8d55", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_5-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c231a21e13ab766e31567625d3984e41ddfd79fa8da5dd9119f1d91308e7b36e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch2_5-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ede9c0ec2b6714d165f80cca041562064bfb886291271cd1025049d94dc205bc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_0-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c034a668e613f50b13d81e343e335090b667beb471ceac668bd8ac3f219440c8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_0-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "78e76288d6f7c45358553adcfa98cc048c4bedf0e403d50dfa94651034c7cbed", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_0-Clarity3, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f26a215506cb97e2e904380adfdd79a313e4c47df95d376308ff5ca060dec343", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_1-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c75ae6a297311712e4bca1595f7ccc7458ed529630800cae0176c60f9a479086", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_1-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6912754dfda2daac6146a8f6d7987ea5a953c09b341633898989b08a3f9d7c0b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_1-Clarity3, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "06529c7916738977338fb3e02888c03f052925d38e82eaa8c4fb283f6f1d1496", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_2-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4185f7d9b2d5cbce6a7b60a6b0175195cd6db272b741edd22873f9ffe5316940", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_2-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d6a23d4c7134a91f41ae480baafd72ac731425f261ab7d9dfb229fabbf17132c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_2-Clarity3, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "63023e0ca7d5a7ec5637b55a48ac2cb6f18e2eb6c007feeb15f1f52b690ec9fd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_3-Clarity1, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7bfb6cc9b24acd4224bc21de3cbeb4bf3d46c0f42696a4e2760c9ea730d28a2f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_3-Clarity2, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "33593cc783c9a74bafffc98d21cc9f1db96d59f2613a78f2585c9e9bafc46711", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_3-Clarity3, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "420a8154554ca90294f2c34737f3b1d3fddc7dc1165a1c3995e6f48ffbfb820d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: check-error-kind-Epoch3_3-Clarity4, function_name: trigger-error, function_args: [[Bool(true)]])", + vm_error: "Some(TypeValueError(UIntType, Bool(true))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 51, + read_count: 3, + runtime: 168, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_value_error_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_value_error_cdeploy.snap new file mode 100644 index 00000000000..058aef15957 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_type_value_error_cdeploy.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "8e55538edd58262d81a0825d583fe73f3fe8a20674ef8c751adbad9fdf73e697", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(TypeValueError(SequenceType(BufferType(BufferLength(33))), Sequence(Buffer()))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 317, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 21506, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 317, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 21506, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "164f3c467022f4f202b9592f94a3e2fe9e26c7bc4296c311fc33f6b1fe6a7694", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(TypeValueError(SequenceType(BufferType(BufferLength(33))), Sequence(Buffer()))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 317, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 21505, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 317, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 21505, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f2d8ead5db5986df6aed58218d13f4574d3128f3a29af1fc9d62facfbc877214", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(TypeValueError(SequenceType(BufferType(BufferLength(33))), Sequence(Buffer()))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 317, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 21505, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 317, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 21505, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cc3a620e6be240f0024700ca291296d7b963ad63844f0678479a9204f195b550", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: check-error-kind-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(TypeValueError(SequenceType(BufferType(BufferLength(33))), Sequence(Buffer()))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 317, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 21505, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 317, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 21505, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_undefined_function_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_undefined_function_ccall.snap new file mode 100644 index 00000000000..64f962d5326 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_undefined_function_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "0ab1bf6f7455a2e241c5eb01c7e25217e12c1ebeeaadba18a7913d6102adcd7e", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 609000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 609000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a763ec8b72977e0633f837b2bc353fb1c0cb1bb6e1986f283ad8704fc464c594", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 305897, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 305897, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6be1ccbbb04f18f533a94e66d70d79706ac81e482b56765274dd6afe68fbbf09", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b6dcb7b30687954419f13d807db87d0b821208bd5b592fd4f3a9c600708a797b", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "53bfdb1be3f33482b5ef4df587cdbc09d8cc6640ca9f2943b74ea4757cdd2302", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c0d8cfb95337826e8a87a62e7434caf5ada31ce1545c994d722a99344634b4c5", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0469d8ffc1af1d2f523b4c80cc4db61d27a563a3bc35b783a19469c8a25c106c", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ee2dc8b75fd4097889a7f4c00d0e50ef9e1e2fffa9c6cb6c4381e53f0323ce26", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9e52017615f665f8fe00b2fcfbb337441a7776d41ade41c8f7c9564f6ca7fe3f", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a9f97c4211ab7f24ac5804b1b1ecbc0e14a3af2aeb6d45c95269b802dfa5ecb1", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "db0c7233c7c4604a0038ca6c1a66f6891d2cdc04298ff91cdb116af95ead6f22", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1a2620ed6648f34c606fac45079d3fd78bd7c7efde8e9bc169298480daf347b8", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9817ac1da15ee3f70c5734c10260f37e7f41513044017eafb0d8a622aed6cbf3", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cb8cd107f79952fd0497f50bd9f3b6026fab8468062201577342adabe8cdcb1b", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4c9a1e7da89d1116fdf95fe7f75229ead79585cb795594d9b38120bf3c8bd482", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8aa5a1771479a7542a64d176afacd36863af679dba2e1e09ea89564900bdeb6a", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c7de4457e94319e76d2c571357479dde3eaef7a1a52ac688d85891dac8740515", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0cc97b6d9f32f5db30bb7c1c6bf1b6c463ac41298e290dd3d2edde3ad4492dc9", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a63247c9c4696088146a1b40a05b63805e02c2feb820ed721ed7a684a7a561d7", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "00395a682e1b1285f27d337209d302536db996d46ec941af90b7cc92625f1e3d", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cc62900d2997aa95692aadc17674067ad656220698caa5dfa3d4174cf6b3fbe9", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fe5742a15cdb7b9a357832a17e5a66ea1d6c6f3c694d437d5304e5b04b184625", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "17e1240c643bb248aa4cbb3517d26bcfde4175ab4070a13753be6642ccaf1e69", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a8f91bfd3df3f42a886906061ac18a6918d8ca6e685fe98b079a6dd2352aef7b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6afb7a5e5f272eacf26021c92ee1805a466f2ed974bdef55d936d233c89d16d5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undef-fn-call-Epoch3_3-Clarity4, 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: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 62, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 9762, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4dea8cff72318fc8c1bd9d06407a50dec2c7ca2a7421c92837c2cf8e89de6fea", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_0-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "baa5fd16653076f752a83d24eb497ebba7def527aacefcaf5875fbc36cde0a68", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_05-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3c84befc4fd78cc92e1659ee7c311b65054adc0f093ac690aa796539ec7bbd94", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_1-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3abc676bfd39554d3460c1c0cb449ffa38c2ea929b21d500b13e26643798be7a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_1-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5ac5742cbe6181cc2ce5f4075d3f88d5fb22ad82758518b40e409aaa4998bef9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_2-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0a53edc3e5f0f0d6d27898f142d761938ed717a2ac595dc8ff0e3e0bf4ba24c3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_2-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e90429fe1e9b5cd15ae57935a68c489bd9e02ad88eb7495fb252c8e68677a9db", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_3-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "093ad943fcdbb8b75715664f0b2c637179c5a2f34dc093b6b7097a4afc5b52d2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_3-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d431383d46c31bfd572bae18db72b9c5cecfc5aa2ca1f022f291a9b7e3919411", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_4-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fa1ae4cc44b30bb33a1dcaac7e12242d58da9cb86ac032f2e12b6f467b13adae", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_4-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "580989dbe4f9e616511b6b8f4e821bf9055e64c3e3ca997ed7df2fc15000b2bb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_5-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c004545a92b38f9a90e26cb3afb7f9f75d71a2905168c95ce46ad5744d7d8605", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch2_5-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8a87274c316b1ee5dd20c4c9ee305e438b1731bab5ae377802c5810440915444", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_0-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "340ccec66b3715c267ef9c7138fe539749ce9d120923661a63b8765bf6d21ef5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_0-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e701acf4352c8f7e125e9e7b0af3301e961bbc2e5b39693a683356465482798a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_0-Clarity3, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b22ab43859f00770c13c1b141bcd7079b562a456b7daeb77bd8e7e78925e0473", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_1-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6d437664a178347f3bdf0856515041417f777fa1b1200f7f948f95646f429b9d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_1-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3cb0e6b19212b81c321e99a294986b8247c1faac112cb849920fed56bce21cf0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_1-Clarity3, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "576ef250a10bf8b9d87642fca99694ae4b8f32fedccdea0295418fb8d9db3124", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_2-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "db26335fd69ef1c9e230d534405a35612db189ad4c9b35bed4314998578c0ad4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_2-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3ddd866d49d9fb652e19a19512518500a45bd134a48553f7fe8a30b21d5bf3ba", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_2-Clarity3, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bbc396ce4b94101c20941d24de308ef0509c9cdb547df5c7d87c8f0c54b0aaed", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_3-Clarity1, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d539afd10180f39e40f0b8ffb25e9b52ed1b6b1672667ba30b2c38a1dede355f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_3-Clarity2, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "941c5de5d614243874dc3458ff36049c75c6b26166a664cd3c3436af40c563cd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_3-Clarity3, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "690a90456b63f2a27e5105562a364442ed516ecb0538868edb442dad4ad86c34", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: undef-fn-call-Epoch3_3-Clarity4, function_name: missing-func, function_args: [[]])", + vm_error: "Some(UndefinedFunction(\"missing-func\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 54, + read_count: 3, + runtime: 133, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_union_type_value_error_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_union_type_value_error_ccall.snap new file mode 100644 index 00000000000..dfa0384f3e3 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_union_type_value_error_ccall.snap @@ -0,0 +1,64 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "7c0dcc19543ecca0386f4e3cc052e097cc11f8633787e51bde1e021915f965fa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-2-Epoch3_3-Clarity4, 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: 296, + write_count: 2, + read_length: 3, + read_count: 2, + runtime: 20202, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 296, + write_count: 2, + read_length: 3, + read_count: 2, + runtime: 20202, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "72bc1062d04aba71e6dd6699d63e92a38894aee94ef51d79d5438b0722d7e5db", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: contract-2-Epoch3_3-Clarity4, function_name: trigger-runtime-error, function_args: [[]])", + vm_error: "Some(UnionTypeValueError([IntType, UIntType, BoolType, PrincipalType, SequenceType(BufferType(BufferLength(524284))), SequenceType(StringType(UTF8(StringUTF8Length(262144))))], CallableContract(CallableData { contract_identifier: QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"contract-1\") }, trait_identifier: Some(TraitIdentifier { name: ClarityName(\"trait-1\"), contract_identifier: QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"contract-2-Epoch3_3-Clarity4\") } }) }))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 267, + read_count: 3, + runtime: 5835, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 267, + read_count: 3, + runtime: 5835, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_union_type_value_error_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_union_type_value_error_cdeploy.snap new file mode 100644 index 00000000000..d5531edbffa --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_union_type_value_error_cdeploy.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "89d0625148d64e4c64add4eb0b6106cf68261e1221269d4ae818a5602def3252", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-2-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(UnionTypeValueError([IntType, UIntType, BoolType, PrincipalType, SequenceType(BufferType(BufferLength(524284))), SequenceType(StringType(UTF8(StringUTF8Length(262144))))], CallableContract(CallableData { contract_identifier: QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"contract-1\") }, trait_identifier: Some(TraitIdentifier { name: ClarityName(\"trait-1\"), contract_identifier: QualifiedContractIdentifier { issuer: StandardPrincipalData(ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP), name: ContractName(\"contract-2-Epoch3_3-Clarity4\") } }) }))) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 287, + write_count: 2, + read_length: 3, + read_count: 2, + runtime: 25164, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 287, + write_count: 2, + read_length: 3, + read_count: 2, + runtime: 25164, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_value_too_large_ccall.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_value_too_large_ccall.snap new file mode 100644 index 00000000000..e56c1942bbc --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_value_too_large_ccall.snap @@ -0,0 +1,1456 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "db327d2b6ec024a5145c3cc5852443996abd32d0d95ce97dcc9e3d0ce5afb6c3", + evaluated_epoch: Epoch20, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_0-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 16160000, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 16160000, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0c0bd0ea5907a23e68d390d9b2a45cdc36ea2c333eedbe3b2645dc30971e0d58", + evaluated_epoch: Epoch2_05, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_05-Clarity1, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 568779, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 568779, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c013ddd01381bb01ba2db2a5b282af1d28b585c377ff884b566914dd9c17db63", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d02c2d3d8b96336ff1ccd8ceb08088bc3597a65e67ea694bbdbaf92b6c039090", + evaluated_epoch: Epoch21, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "483edeacb45e30f204140b52215489667cd7b205c40a46ad8aad6cf8747c22d7", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8623e1e39110a7392725adb3de2c3bcb63c72b890be418b4708d70d95fe47967", + evaluated_epoch: Epoch22, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0fc0b561063c90aefd893e6926ad9e03af8b97cf9142f64e6b6b065c5aef05fa", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a61aa4ebbbd2b25a4c157482de1b4e745766fe61a2fa7e34552f84434b5eb5bd", + evaluated_epoch: Epoch23, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a5d1a953ae093867fef35b1eae3ca0698a3daa4cfd0498b44b8b41431a38254d", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_4-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b141ca5970b69456c078cd6601d0a750a7d8e00861693c110caaf086bb2eb7e1", + evaluated_epoch: Epoch24, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_4-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "54eb48060d9f52ee674b91c294e57789fc4ba9b1145dbe01188d84fb5bb2ec23", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_5-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2eb83898da30e7726a0507ed58f8ca3340e1522c4b46591e138e215e5c8220f0", + evaluated_epoch: Epoch25, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch2_5-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5efe54e4c03f72dc4dd0d82d8d5b5d31d3b650bf827c306753f426995aad7a05", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_0-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d7a41333eb1acb9648babb126661253e1a2ba52c7f15cd98e17c89a5d45dc769", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_0-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "caa33127bc7ed30683cb81581fe4fffada51f2aad019b94347efafd8b0f6c646", + evaluated_epoch: Epoch30, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_0-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ca27af5aeda99e6cfd9abd06c8a78263768c0fa3644e3420003f3df690ed8e3f", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_1-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fac2b24ddcb4200d1f54aad6cb4dcf3441cd8322818b975d6b2c7a75b3adc3a2", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_1-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7084d7c9b2e315f9f632cbb859cb698e9b6c4151d3a7bf1c2bbeaec15772caba", + evaluated_epoch: Epoch31, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_1-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f8a3a83452bf738d60a5e8de3891efc293ef55cb772e63528da7b651d3638e8b", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_2-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "027f2c827216bf418dc142c5f2a919d7ee36f3d20a3930d0af57acbb777cef22", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_2-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "725ec043e4e4f515c09ea4755501d48cabf8a1f4c3cd6097427c875c6b0b7f90", + evaluated_epoch: Epoch32, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_2-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1e5c6d26f5a845e7f34c08e315b18f57697bedd047fb4c848b1e622d61d16e70", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "151f73132ce1a6cde36620e922aefca1f4a03d87c1154e463c0f75313eab1cd7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "df4f066d74e27f59f9cd7d52d1b984c00f8fc7b4219c42ef53b322ca9e822c8a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "060936d055d4d7c54c1273d1d20afd7848955e31866e65a41d5a70a7dcde0dfb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity4, 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: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1535, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 74570, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c6b3a03014ac4a7c89d8f8b0a63c06b5ee5ec5f51211c3d2ecccdd9d2d5c70bc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_0-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5e74545ee0100390fe83b20cb94fcb6cbe0808271093700a0322b536851ff605", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_05-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "887cdb0110b7332d1504b20c02e0633518789c8766a713856a7ee55f8d7fb68a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_1-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "70513b025b699a38eee960cac5cde69266aa1ab83e6514c153d65e2b676f9f4c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_1-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a539f5eee2bb5fde03d6b477c93c3e80d69021e821b3a4f701f9811d6163ca0b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_2-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "656518e5455dad0309a635a268cec03867353f9bbec4b6651a3552786fc7deb0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_2-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6bd11fc7dcc6a6bca5f9a00c83769f3fe2050c22c96017e718a06c156d6c879e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_3-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "14e8407009997f059632a6cb5ff7121108f6240f7ceb28144274e35ee9d93ed2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a88bfd922a7a89b0c9cb9e582fa68a2cb05e625f279dfff31fb13d832cf30ae1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_4-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0e1a4e2a04d5ae942e79f09e6235886746f49c700039cb7a33b9268d5cfb05ad", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_4-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "71386ce4dccae5181f4cacd2e1af850d368156e358d9ddb0284f7264e8340969", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_5-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e887064d8d8a1db866f1cf45a662c6c7fc529af57c358d6ad2e5a2ff5f952f7e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch2_5-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "574cefd49beba0589b9c066c1f9e174a006a7bbb40dcd2ff2006c5ab624ea29a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_0-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e9085630a8d483b7d12a694866011aab1290ddf532b03c4fdaf4ad5c23f006de", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_0-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d3ed5f7f9ec0cdcb2924377d351cba0e3286407d667768d1ef8b3b503bcffd15", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_0-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "50deafee5150d6ee3bb9e712a4adf31c9d538665450637f1d9c4a33c665bf3da", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_1-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fa169ab4d9b24ebe5c32e7f69812214b78d7fc65589efc5b256d455fa35701d4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_1-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "509d80dd1a4a49907a5af031b492313e326d7ff78843d47a449578a0d3426754", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_1-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ecaafca1fa4a6f14b54c3d45c3a62d99e76d50c04767ac33e383c72e60245f53", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_2-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "edd6a782d87e220fbe557deaa6490ed1fc8a64ec1061816016eb9067247ec663", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_2-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cc9f2f22d38e509f8008cf87c6477fdbc67ea64bb6c458c93d8fb85cf33f4ab3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_2-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4c76e7dd753787f9f7cc94fb5f3e94131142ffdd207f3af4102793fb1454d964", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_3-Clarity1, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f65f163d01f1d58291f87efb10df00fcbab35b69c51cf48f60c97015fb1beb5f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_3-Clarity2, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5cbfe60d341de737d4ae9d849da80ce2563aae2b2e91a40ce3963cc843abaef8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_3-Clarity3, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2e9723033961eea22cc8426fcb67c36cd59623f66b77beddd8696ecae959b1a4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "ContractCall(address: ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP, contract_name: value-too-large-Epoch3_3-Clarity4, function_name: trigger-error, function_args: [[]])", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 1375, + read_count: 3, + runtime: 84033978, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_value_too_large_cdeploy.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_value_too_large_cdeploy.snap new file mode 100644 index 00000000000..3ddea5bf387 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__runtime_analysis_tests__check_error_kind_value_too_large_cdeploy.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/runtime_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "a4918ec1d216e0987507582a79615fc96c1d2f9e1838ae9e8c464e6525e8fea2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 1472, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 84104599, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1472, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 84104599, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f0d662c19c9f885621c5390fac9eaf6833da14dce5ee208ac7373b10b7c22a88", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 1472, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 84104599, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1472, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 84104599, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "667ad2ea06d28caa1deca432d86a2612bf76294d2a29e34fe2e7cba5f055951e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 1472, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 84104599, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1472, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 84104599, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d4b14c4dad73009b4a4c9057ff73daf03950752dd79619c13ec8d677e55655b3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(ValueTooLarge) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 1472, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 84104599, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 1472, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 84104599, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__error_invalid_stacks_transaction_duplicate_contract.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__error_invalid_stacks_transaction_duplicate_contract.snap new file mode 100644 index 00000000000..226aeb40413 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__error_invalid_stacks_transaction_duplicate_contract.snap @@ -0,0 +1,50 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "2d7d0b29a889aa04c79c2b794ad5ecc9e7f2ff84cdf99cf62b6ead24e11263a1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: contract-name, code_body: [..], clarity_version: None)", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 35, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8817, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 35, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8817, + ), + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 6eabb186436e51578fc50c56e538cf22e2bf23d1de977132342e5b2af71ca95f: InvalidStacksTransaction(\"Duplicate contract \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.contract-name\'\", false)", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 470e5ea2d1c22a84f1cf95731ada6d25b9df8813f2032a6c12a8ce8118de59e0: InvalidStacksTransaction(\"Duplicate contract \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.contract-name\'\", false)", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 5c99bb620d852120112bb10ac3850a5a104a4ec70998867d1aaae65efe4e91c3: InvalidStacksTransaction(\"Duplicate contract \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.contract-name\'\", false)", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 15c7400f3a64a32f4d0b8ea5b04b24bbfbfede36ce82f1fa063a40e714eff8a2: InvalidStacksTransaction(\"Duplicate contract \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.contract-name\'\", false)", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_allowance_expr_not_allowed.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_allowance_expr_not_allowed.snap new file mode 100644 index 00000000000..ccd7bd31d48 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_allowance_expr_not_allowed.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "eb32387df909f2eadd0d7a1063b569712b8c3a35df55a36c76728a41d601db1b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: allow-expr-not-allo-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: allowance expressions are only allowed in the context of a `restrict-assets?` or `as-contract?`) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_at_block_closure_must_be_read_only.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_at_block_closure_must_be_read_only.snap new file mode 100644 index 00000000000..60011852cdc --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_at_block_closure_must_be_read_only.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "dfe63494e41a728bb312b67505cf3e630fa0d8c56f6a6653e979de854e75044b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: closure-must-be-ro-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: (at-block ...) closures expect read-only statements, but detected a writing operation) [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: 3966, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3966, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2e049a4b1768177abbc1c07666ef5c95cfbb1a57d792513f19c28e989aed3e17", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: closure-must-be-ro-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: (at-block ...) closures expect read-only statements, but detected a writing operation) [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: 3966, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3966, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "def986371d12dab1abd72cf648c74e5bb9e543005a629289d69282c188353e94", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: closure-must-be-ro-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: (at-block ...) closures expect read-only statements, but detected a writing operation) [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: 3966, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3966, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "77abee8f88c8661a041465269b184208ab433a283a5c22c1abd3396138f90180", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: closure-must-be-ro-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: (at-block ...) closures expect read-only statements, but detected a writing operation) [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: 3966, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3966, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_function_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_function_name.snap new file mode 100644 index 00000000000..e0342bdf0d6 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_function_name.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "958e85fdbd6d7dee181af20aa952a51577ebbf3bba213cfd6c19e98817192959", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-func-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid function name) [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: 801, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 801, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "25bedf706335e24c42cf710d27337a19863fb7aac1d2fd0048887173f02643b1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-func-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid function name) [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: 801, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 801, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "52dd982457d65c8ba04a17e0f6f04b60bf2aaa0b575366704f15774f476856c7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-func-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid function name) [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: 801, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 801, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "526adbd4cb28ab037c2bca72d6bab0bfec3062a9690290c83badcab759d6d2a1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-func-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid function name) [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: 801, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 801, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_let_syntax.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_let_syntax.snap new file mode 100644 index 00000000000..cf9e595d343 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_let_syntax.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "9a7b61f181ef8592a441f9ecc91bbc12f9a1793cfbec3513e4721f18d67d759c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-let-syntax-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid syntax of \'let\') [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: 396, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 396, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bd7f849c2ca3f82215077ff231c5b9ab2aabab13ffe6dde893ac874934486e89", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-let-syntax-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid syntax of \'let\') [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: 396, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 396, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b9892b671586d1a137bce485d61a9413be9835ac270bc2b9d8e012d14148cda6", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-let-syntax-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid syntax of \'let\') [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: 396, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 396, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "88bca3a73fff95a22e4108e03d3e75b391b62baca8ea07fbed2f76889b099110", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-let-syntax-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid syntax of \'let\') [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: 396, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 396, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_map_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_map_name.snap new file mode 100644 index 00000000000..f85b950249d --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_map_name.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3986d2b49c834d730e91c37a0749894acbf15729a49fa0212b9972a2c44bbea2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-map-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid map name) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1047, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1047, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f73ce2a128df823fceb534d19390397feca6196c922a95f3fa8fcc5ddeb31be0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-map-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid map name) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1047, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1047, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c7cd24d368c0f4ddb7d3a8b86063dc3934decdb2e264714fbc9ad3a898fc48b3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-map-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid map name) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1047, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1047, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2a8f6c0917fbed26587e59b30895894d390e8d506e08e443b67fe97d306879a7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-map-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid map name) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1047, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1047, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_map_type_definition.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_map_type_definition.snap new file mode 100644 index 00000000000..24563ee4790 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_map_type_definition.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "4cca742df63dfae2a6082353ebd9528d316f13ae99fb29442bb8e53cc7342565", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-map-type-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid map definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1372, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1372, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "20140d78c081fb88aa6389b2a11c24b3f98e14832df47562e52210c5145d91cb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-map-type-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid map definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1372, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1372, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "00c123e8a822408dad4879b7e9d4158887a1d2750862ed15d3b34cc4cd7cc70b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-map-type-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid map definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1372, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1372, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6feebdbc00848565df5f577460dcf3937f5518e4eb91d228d73d5ed09d3cb8b6", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-map-type-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid map definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1372, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1372, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_input.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_input.snap new file mode 100644 index 00000000000..cbb47a8dede --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_input.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "86bad69f94ef8fe921cd9e12608e4ad2418a129a68764b9e0c6aa328637b88bd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-input-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: match requires an input of either a response or optional, found input: \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 14, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1662, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 14, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1662, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "efd98f057220cb8cfc3ae8e6edad5628232e9e85ec70402ec0e63d177f77340e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-input-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: match requires an input of either a response or optional, found input: \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 14, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1662, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 14, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1662, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "eccff05d829bd4e6bed92d4e07cb7c073509bb81ec35b7950ae89fea4cf61af3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-input-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: match requires an input of either a response or optional, found input: \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 14, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1662, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 14, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1662, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "059b24eac24492c149c3e18867b6dd4f8ff0e18b84d5acbd0f40cd53a91a349c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-input-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: match requires an input of either a response or optional, found input: \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 14, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1662, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 14, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1662, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_option_syntax.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_option_syntax.snap new file mode 100644 index 00000000000..07cc4b205b6 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_option_syntax.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "9bd61674813ec48aadc6a7e6d0e019dda68271947d89e128ef15fcf0734bc3de", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-option-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: expecting 4 arguments, got 3) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1538, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1538, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6016f3cfb0f2f7d23baace16e5d3165206f98ffa04c7ef1d3d330921cfcdaa86", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-option-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: expecting 4 arguments, got 3) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1538, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1538, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7cabe7b6fadfecf3563ef85c2fe58807ad5c6b541ee5d0b9e0053282cd3d3653", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-option-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: expecting 4 arguments, got 3) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1538, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1538, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "383c6ae1a0149e8bd366bf5edb05f604fb7e2de4a36cfa3238c3ea67361b466c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-option-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: expecting 4 arguments, got 3) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1538, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1538, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_response_syntax.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_response_syntax.snap new file mode 100644 index 00000000000..65115b321b5 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_match_response_syntax.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "0831e40c8237627cca7bcea8b689e67bda242d2ae49da018aca9c19f00980f67", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-response-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: match on a result type uses the following syntax: (match input ok-name if-ok-expression err-name if-err-expression). Caused by: expecting 5 arguments, got 3) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1485, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1485, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3ff099450bf29efc360cf1985bf77c2d58f371876b174f68b7749d6f1c2c016b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-response-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: match on a result type uses the following syntax: (match input ok-name if-ok-expression err-name if-err-expression). Caused by: expecting 5 arguments, got 3) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1485, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1485, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f7d6c4b9afe4b34156f4a24ea8eb843eb7ab4aa92d2bc2cd775c301453187ef5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-response-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: match on a result type uses the following syntax: (match input ok-name if-ok-expression err-name if-err-expression). Caused by: expecting 5 arguments, got 3) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1485, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1485, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6c8a3737db86945b6cbc4801bf5e448999bfede6332a6ca9c25cc93ff45ad3c8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-match-response-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: match on a result type uses the following syntax: (match input ok-name if-ok-expression err-name if-err-expression). Caused by: expecting 5 arguments, got 3) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1485, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1485, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_syntax_binding.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_syntax_binding.snap new file mode 100644 index 00000000000..3dfeb8dfaf3 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_syntax_binding.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "5757a72059ef9758e18238aad508b3c505548d4ec91c188b0331abbf516231e2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-syntax-binding-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid syntax binding: Let-binding item #1 is not a two-element list) [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: 666, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 666, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "23abed8e414c422c7eaaf6981863e16f9e36f83e6588787e3b366d45a476d380", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-syntax-binding-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid syntax binding: Let-binding item #1 is not a two-element list) [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: 666, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 666, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "32a47e26e9953fa3451bfcdf8ba00395b5d574b6e6472f8458774c3b29959ab4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-syntax-binding-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid syntax binding: Let-binding item #1 is not a two-element list) [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: 666, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 666, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1cf5ce609cb847dd7558af25d631a1a12549c1ac377527d15fcb2a9db607aa0d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-syntax-binding-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid syntax binding: Let-binding item #1 is not a two-element list) [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: 666, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 666, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_token_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_token_name.snap new file mode 100644 index 00000000000..c7786bc4873 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_token_name.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3390089ac0826e8e5677d5093fa3d0db6081e88e6a1763017efc763d3cb96b16", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-token-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting an token name as an argument) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e5cab45ec9a8034bc8deefb862099bc775bad5bfca6bbe8896c5d4b69bd58773", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-token-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting an token name as an argument) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "dd195890bfe644b746de8f2d27e986a2cc8407929d3e7ca32ce18f1460a40348", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-token-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting an token name as an argument) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bcc6deb5971a412ffbbf92f64405124ca3e0e0c1408e1da9d3da08d239e003a6", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-token-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting an token name as an argument) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + )), +] 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 00000000000..5cc9021b887 --- /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,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "12d33d45dd2d1e1b69dc051295249fbea64a8c3fd09448e3997f6d9441724448", + 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: 3157, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3157, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8ccaf85453bc27e815e4b127745b61c0e3ab40bf22e73fc7b8c74f5ac8c458f3", + 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: 3157, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3157, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "111496a7fc28efe5966db421eb0ecd0b736d5435ff490585ba801f1f5093b339", + 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: 3157, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3157, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f4274bba15e471d656212d8e0b57f2386074437a263e743a0423715ea32d3f40", + 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: 3157, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 17, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3157, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_tuple_construction.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_tuple_construction.snap new file mode 100644 index 00000000000..e0f91a2dece --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_tuple_construction.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "c7325ae92d1ef974494c13e18014778fbe87f74a3c654eb5f9461aa7d38fcc34", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-tuple-constr-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid tuple syntax: defining \'name\' conflicts with previous value) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1030, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1030, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "64981f31580117d55d9f3527ee4300d55d1eccb084965bcfa5ce6d86827635cf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-tuple-constr-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid tuple syntax: defining \'name\' conflicts with previous value) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1030, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1030, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "875b8f5f914d202184bd3bb618319af5d88c1692b902e069561e75a1b0da05d4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-tuple-constr-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid tuple syntax: defining \'name\' conflicts with previous value) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1030, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1030, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "779ea49997c7f6b76972ba2c855d0adf03dbb91ee5b60923421d72142e81a70f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-tuple-constr-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid tuple syntax: defining \'name\' conflicts with previous value) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1030, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1030, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_tuple_field_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_tuple_field_name.snap new file mode 100644 index 00000000000..0c6cf9a1435 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_bad_tuple_field_name.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "c7325ae92d1ef974494c13e18014778fbe87f74a3c654eb5f9461aa7d38fcc34", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-tuple-field-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid tuple field name) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 939, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 939, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "53e6f527920fae9c68d283cddb6bb234d6707f978ce1b7ea60e284c4c9da3782", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-tuple-field-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid tuple field name) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 939, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 939, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "500aa6950d9812bd87c6085ad1d3108c926e1878ef1ba6fd223f490f67e04a45", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-tuple-field-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid tuple field name) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 939, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 939, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "37d05369bb78bfa6f01ad670df20f3682e215a7f2e0e405e9c0b533e37e38b2d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: bad-tuple-field-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid tuple field name) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 939, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 939, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_constructed_list_too_large.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_constructed_list_too_large.snap new file mode 100644 index 00000000000..db55afb0ffc --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_constructed_list_too_large.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "4865d7980ca587867066c6e012ef04e079a89b2e97ef78d3a2248b34c38e3f41", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: constructed-list-large-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: reached limit of elements in a sequence) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 29, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7437, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 29, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7437, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "69fae186776e92cf6946ed6a4a83c28d0024e0390278df6e68a69e09482d16e7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: constructed-list-large-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: reached limit of elements in a sequence) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 29, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7436, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 29, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7436, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "535d3cb64b5043bc386984fce0b0e71ad7c2f703b2f4a91bac5865227642b788", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: constructed-list-large-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: reached limit of elements in a sequence) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 29, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7436, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 29, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7436, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7b61f5697e66a568a248c80b83cae3df329c6ef279c3076d441c5d833b71c898", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: constructed-list-large-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: reached limit of elements in a sequence) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 29, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7436, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 29, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7436, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_contract_call_expect_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_contract_call_expect_name.snap new file mode 100644 index 00000000000..5834dd54aa8 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_contract_call_expect_name.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "0baa8536816ea19016addf5641e710546c1337086d00ae90446b95d3cc4fab61", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: ccall-expect-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: missing contract name for call) [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: 2151, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2151, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2ed7c0c0aabed9df7b3fb279db73498156a063af779e047537f15f7d1a4fca97", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: ccall-expect-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: missing contract name for call) [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: 2151, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2151, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8f4226f89fa28f6cac5946c87e70301055d7bd8daf6e32545b99b6437a377940", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: ccall-expect-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: missing contract name for call) [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: 2151, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2151, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e294d7a75b14cf11124d8f842923b3e332b40c3fead74a57e2a224853c7d013b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: ccall-expect-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: missing contract name for call) [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: 2151, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2151, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_contract_of_expects_trait.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_contract_of_expects_trait.snap new file mode 100644 index 00000000000..60f09897f85 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_contract_of_expects_trait.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "68e84be6abc605f8b749ffddc651ac1638855423b92fafc696e2838da89dcf88", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expect-trait-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: trait reference expected) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 686, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 686, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1686e569006424107fbe3d0443019c8769d8bbb0773f38e17a1a226671304336", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expect-trait-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: trait reference expected) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 686, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 686, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1b37ce2a9bde28884ec5b15ba72017631a200bc33c6eda4b5deff0a71ff817b4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expect-trait-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: trait reference expected) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 686, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 686, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "31b6628796a3326feb9b789bb1850cab55ede05ca7d1cbf77e5ee1cabc775afd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expect-trait-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: trait reference expected) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 686, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 686, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_cost_balance_exceeded.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_cost_balance_exceeded.snap new file mode 100644 index 00000000000..a9bd31bb1f8 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_cost_balance_exceeded.snap @@ -0,0 +1,22 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 04296a317858a65219360203bb34df7cc4e490d5b80e661ffa61d1d7f2b581f7: CostOverflowError(ExecutionCost { write_length: 0, write_count: 0, read_length: 0, read_count: 0, runtime: 0 }, ExecutionCost { write_length: 75013, write_count: 1, read_length: 1020001, read_count: 15001, runtime: 135183501 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 64bd21d5719a95afb9137237e44b0c54328e3a14b814c14e437fc89fe5244225: CostOverflowError(ExecutionCost { write_length: 0, write_count: 0, read_length: 0, read_count: 0, runtime: 0 }, ExecutionCost { write_length: 75013, write_count: 1, read_length: 1020001, read_count: 15001, runtime: 135168502 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block b672c031d7a8fac0896f6c21e6fd911e580024a0ad0308a60dfd133a953576fa: CostOverflowError(ExecutionCost { write_length: 0, write_count: 0, read_length: 0, read_count: 0, runtime: 0 }, ExecutionCost { write_length: 75013, write_count: 1, read_length: 1020001, read_count: 15001, runtime: 135168502 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block a8639c1bddd3a9aea58e3486249f0397686c727a1017580933539f2ff5844ec7: CostOverflowError(ExecutionCost { write_length: 0, write_count: 0, read_length: 0, read_count: 0, runtime: 0 }, ExecutionCost { write_length: 75013, write_count: 1, read_length: 1020001, read_count: 15001, runtime: 135168502 }, ExecutionCost { write_length: 15000000, write_count: 15000, read_length: 100000000, read_count: 15000, runtime: 5000000000 })", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_match_types.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_match_types.snap new file mode 100644 index 00000000000..95f02923f4d --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_match_types.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "e98fcb2f30a5cca370fc492fca335c2094657af7c8229458cf187a26f82b8bbf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: attempted to match on an (optional) or (response) type where either the some, ok, or err type is indeterminate. you may wish to use unwrap-panic or unwrap-err-panic instead.) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1379, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1379, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "701590b3c37a11cd6dc06659bb9f0c342d7780bdee8148fc390729e0a3bd73b8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: attempted to match on an (optional) or (response) type where either the some, ok, or err type is indeterminate. you may wish to use unwrap-panic or unwrap-err-panic instead.) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1379, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1379, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6b96bef71f8d821d5eb9b9cc393143a5cb932ac6a3cf75315635017f633402b3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: attempted to match on an (optional) or (response) type where either the some, ok, or err type is indeterminate. you may wish to use unwrap-panic or unwrap-err-panic instead.) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1379, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1379, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8f7a9f0eaf519c577031da36fb419f348b9a638924f637d564c00bc6d8a1467d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: attempted to match on an (optional) or (response) type where either the some, ok, or err type is indeterminate. you may wish to use unwrap-panic or unwrap-err-panic instead.) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1379, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1379, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_response_err_type.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_response_err_type.snap new file mode 100644 index 00000000000..a829159b481 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_response_err_type.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "c7325ae92d1ef974494c13e18014778fbe87f74a3c654eb5f9461aa7d38fcc34", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: attempted to obtain \'err\' value from response, but \'err\' type is indeterminate) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 966, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 966, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ee6a98c9f0600bfb7234c250156b55adceaa1d1f799985955eb50e33ae936f43", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: attempted to obtain \'err\' value from response, but \'err\' type is indeterminate) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 966, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 966, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ad30235655e4a1356d95cf029ea1b272f40591dd33f2e15bb4d450d9a61f5587", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: attempted to obtain \'err\' value from response, but \'err\' type is indeterminate) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 966, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 966, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "710fd89410ea25f1e5ee2c1a55de407da84848c914e6de8ad1025edd384fa5fb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: attempted to obtain \'err\' value from response, but \'err\' type is indeterminate) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 966, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 966, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_response_ok_type.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_response_ok_type.snap new file mode 100644 index 00000000000..787f3233a94 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_response_ok_type.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "5757a72059ef9758e18238aad508b3c505548d4ec91c188b0331abbf516231e2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: attempted to obtain \'ok\' value from response, but \'ok\' type is indeterminate) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 931, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 931, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a09db656c9da7a1005ce5a15439dbfec1bffe9b82cdaf00bff43630360e4ff90", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: attempted to obtain \'ok\' value from response, but \'ok\' type is indeterminate) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 931, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 931, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "93a84e8c359dd5d96b6c929ef52a44da3ed8fdbdea210940cfb0d1421cb51998", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: attempted to obtain \'ok\' value from response, but \'ok\' type is indeterminate) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 931, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 931, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "97339d9c87866821ad51d00c83114e095e42be9787302e6e902b48efe3373774", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: attempted to obtain \'ok\' value from response, but \'ok\' type is indeterminate) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 931, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 931, + ), + )), +] 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 new file mode 100644 index 00000000000..c750aef4acb --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_serialization_type.snap @@ -0,0 +1,96 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "b3b9782ccbe1bf3a66f1c34fe50c83c418fd9d6265761b0a82ffe9950dc8e30f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: serialization-type-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: could not determine the input type for the serialization function) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 41, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7759, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 41, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7759, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "000052458b68bb6d4184aee0daf39736b0799c96514237aa8377e7c10f00fd61", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: serialization-type-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: could not determine the input type for the serialization function) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 41, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7759, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 41, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7759, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "322b1c89f517b9a55c2487d6f900057dadab0c93034bd5120be87fd7dc7fe86f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: serialization-type-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: could not determine the input type for the serialization function) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 41, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7759, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 41, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 7759, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_type.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_type.snap new file mode 100644 index 00000000000..b30859a1ae9 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_could_not_determine_type.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "a1ba1c6711af9225754f4503aaa15ea11c8b043513b5630c32582be50ebf43a3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: type of expression cannot be determined) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1136, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1136, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "756733812c29ccf1a323bbe30003922119266675e389190d536ded2c2a35dea6", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: type of expression cannot be determined) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ad3121ac68bbe2571d9714023de241967c72ea8e6819c85634f807ff3eba80a4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: type of expression cannot be determined) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1124, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "44823046ccdb67c2ebfc133360d382729ae79a9bca0e108208f86fcfab950cbb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: could-not-determine-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: type of expression cannot be determined) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1124, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1124, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_default_types_must_match.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_default_types_must_match.snap new file mode 100644 index 00000000000..c7807a20c5b --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_default_types_must_match.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "30261957397a00a1facce85f43fffe82dbd7cd0d962c822b904bec0ba1c73af3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: default-types-must-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expression types passed in \'default-to\' must match (got \'bool\' and \'int\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 28, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4991, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 28, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4991, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3fab0f7cac72ffbd9fc0411401bdd99354e87f293ccfcfbe09bfbc9f2d8595a5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: default-types-must-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expression types passed in \'default-to\' must match (got \'bool\' and \'int\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 28, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4991, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 28, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4991, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bdc2a354a99671fecc71486e56ce504660026e6c0b978621499dde9853d21b6b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: default-types-must-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expression types passed in \'default-to\' must match (got \'bool\' and \'int\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 28, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4991, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 28, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4991, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "7afcd0b4ec3fe54ff6b1f8d32e9c474a8221b0f26b0d9ffb166e9cfeec30c566", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: default-types-must-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expression types passed in \'default-to\' must match (got \'bool\' and \'int\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 28, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4991, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 28, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4991, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_function_bad_signature.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_function_bad_signature.snap new file mode 100644 index 00000000000..086229e8286 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_function_bad_signature.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "0d3b93bec153507aa367e009aaf31d22810569f48e6710442e930725c81135ab", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-func-bad-sign-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid function definition) [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: 720, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 720, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "76b2af45f6a0ef7f8700b0733fb4a1bfaae4237d3c7e2dec921eaab45cf118e0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-func-bad-sign-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid function definition) [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: 720, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 720, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fb0ff80618f517a6af2b659b1d71197d3fdeced528462234d5ac23815757173e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-func-bad-sign-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid function definition) [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: 720, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 720, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "79a0353d25a40feeb4524c567a7593a9e69ef0fb6b676350a7ecc43e0058d357", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-func-bad-sign-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid function definition) [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: 720, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 720, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_nft_bad_signature.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_nft_bad_signature.snap new file mode 100644 index 00000000000..12e3d493c6d --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_nft_bad_signature.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "9bd61674813ec48aadc6a7e6d0e019dda68271947d89e128ef15fcf0734bc3de", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: nft-bad-signature-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: (define-asset ...) expects an asset name and an asset identifier type signature as arguments) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1497, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1497, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "669e41818c99b7f54bf3acc1458387cd2c18ca67ab8830bd32e369f0c08b46ba", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: nft-bad-signature-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: (define-asset ...) expects an asset name and an asset identifier type signature as arguments) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1497, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1497, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cf975aa3e10d06b9d5870c7fb31b38986d2b4ee0924e03dc0667911cf0e321c5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: nft-bad-signature-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: (define-asset ...) expects an asset name and an asset identifier type signature as arguments) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1497, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1497, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "232e11cd51e7cbc9cb6e2990de3a6e4fb8851413ca076c8e7dbf7d08555c4833", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: nft-bad-signature-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: (define-asset ...) expects an asset name and an asset identifier type signature as arguments) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1497, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1497, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_trait_bad_signature.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_trait_bad_signature.snap new file mode 100644 index 00000000000..365d51c314b --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_trait_bad_signature.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "f80d8825cf580fda2e36a975d7c02e0c227051a0f56ae0ee50ede8ea2e4266fb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-trait-bad-sign-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid trait definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1397, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1397, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "13cfd665a9fdb72caef26e86e8eb3697aa282c89e6aba8a08230aa50d7225dcb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-trait-bad-sign-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid trait definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1397, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1397, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c4f2a04a75fcf53d1e4d31f6d308b026e00eb60f56e3f621536ce9e6754b2c2b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-trait-bad-sign-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid trait definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1397, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1397, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "345cd8885c37d1ac1c4e261aab67cd0e620d5edc5c13cdaa59948a9d9f21fa07", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-trait-bad-sign-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid trait definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1397, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1397, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_trait_duplicate_method.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_trait_duplicate_method.snap new file mode 100644 index 00000000000..68bf0413e2f --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_trait_duplicate_method.snap @@ -0,0 +1,124 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "4761d32153c2f749dafe09d791baf35aa8a046e7f4fde6f5c8b93fa9b7bcacbd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-trait-dup-method-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "None [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: true, + data: Bool(true), + )), + cost: ExecutionCost( + write_length: 163, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12905, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 163, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 12905, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e3c3390d4abad1cc25ce01266beebbfb214946828db69f382c3f5f1c56c98639", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-trait-dup-method-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: duplicate method name \'foo\' in trait definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 21, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4094, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 21, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4094, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "01be73c925b1fd4ccbf23afadc1f984e99456decca9bf9bfc71d48a31baa1d13", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-trait-dup-method-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: duplicate method name \'foo\' in trait definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 21, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4094, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 21, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4094, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "90aa3aeb5edbb8c0b471ea204f3362f17bc9efd01e5ca64fe836a23195884460", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: def-trait-dup-method-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: duplicate method name \'foo\' in trait definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 21, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4094, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 21, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 4094, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_variable_bad_signature.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_variable_bad_signature.snap new file mode 100644 index 00000000000..2061c960036 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_define_variable_bad_signature.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3986d2b49c834d730e91c37a0749894acbf15729a49fa0212b9972a2c44bbea2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: define-variable-bad-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting 3 arguments, got 2) [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: 936, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 936, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c7bdfb39ef7286728ae1e059a341ba8c1d35c19e3ef052df10f616e01a1294d5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: define-variable-bad-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting 3 arguments, got 2) [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: 936, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 936, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a147afd28647fc80fbea08e3e4e2f66421a443be6497f7db0acbeb8c313360e7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: define-variable-bad-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting 3 arguments, got 2) [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: 936, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 936, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "006d8e80572233b24cead3478544649b58318c4beb72a4f598827f5b92e5c5cc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: define-variable-bad-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting 3 arguments, got 2) [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: 936, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 936, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_empty_tuples_not_allowed.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_empty_tuples_not_allowed.snap new file mode 100644 index 00000000000..5ce3110c8ed --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_empty_tuples_not_allowed.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "cb65c4db199772d38250885573213cd047ab5a6005280da51ec86ec999d84665", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: empty-tuples-not-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: tuple types may not be empty) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2425, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2425, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6a06f69ebd26658d76381d2846c87075953cbb1c7ddcdfd335d37d259366d8c9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: empty-tuples-not-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: tuple types may not be empty) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2425, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2425, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ebf27f692de59977c4e1fac03fef7b137e36686f23efe5be1af381d2e313e607", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: empty-tuples-not-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: tuple types may not be empty) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2425, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2425, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "af00aacdc7c28122ae86a882ff02d4bd78ccad0c58a01a981b223f254dc11dce", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: empty-tuples-not-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: tuple types may not be empty) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2425, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2425, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_allowance_expr.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_allowance_expr.snap new file mode 100644 index 00000000000..5d60bb50e6c --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_allowance_expr.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "9bd61674813ec48aadc6a7e6d0e019dda68271947d89e128ef15fcf0734bc3de", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-allowa-expr-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expected an allowance expression, got: not) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1653, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1653, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_callable_type.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_callable_type.snap new file mode 100644 index 00000000000..81cd43e0d59 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_callable_type.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "a15389f8ccd87bba99abda67472f4f01d4d9dc022ed837d0cacaa2c90c4f0c9d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-callable-type-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of undeclared trait ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2927, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2927, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "79d2ba599e11ab67599d5e12ff0f1ce97d2fe8dba27e491af1312df9bdc641ed", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-callable-type-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expected a callable contract, found uint) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2927, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2927, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8f9bef44af35bf3e640ef14cb9a74bd5647541cd288689dcd293f2af4d3a8a34", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-callable-type-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expected a callable contract, found uint) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2927, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2927, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3dbb2b083e8b7c6599811b917c06df49a8c9620d1a2dcb9fc9aee8cf2b33e18e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-callable-type-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expected a callable contract, found uint) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2927, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2927, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_list_application.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_list_application.snap new file mode 100644 index 00000000000..c508c19b98e --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_list_application.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "26a7cf9478898f9b24f8aca56188ac912a1e505770bf0c0f15f8a1deeab06c54", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-list-appl-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type list) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "49c6a767e73a9f036b33fe9846f9c4165f935f3ff66a363488909366eb95bc55", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-list-appl-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting expression of type list) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c3a681a97a0bb1d153d09e92133d4a65d9f2815f447d0a2a13f5a61538d34024", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-list-appl-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting expression of type list) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "93519863161a77d5ec36ea36e644215fee98a27813f181c8834b8cf0abd16b97", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-list-appl-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting expression of type list) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 605, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_list_of_allowances.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_list_of_allowances.snap new file mode 100644 index 00000000000..97314425f3d --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_list_of_allowances.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "080e462a7a4181ec7a8eeecef8d0902641c1d9e71e8c70416c7dd1816231d41f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-list-of-allowances-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: restrict-assets? expects a list of asset allowances as argument 2) [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: 1125, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1125, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_name.snap new file mode 100644 index 00000000000..d4e6f424b74 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_name.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "8d956af6b22c472853f432445276d339d3b57589470915f8cc1fad0bd18c925a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: expected a name argument to this function) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1222, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1222, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6ecdd34cd336313a4d020a697a62988b44eefc084061013d73510747c87eaaa2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: expected a name argument to this function) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1222, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1222, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3a72a793cccd515dff20e9f2de3d4051af296fa90401fb5229bc27cf2dcdc2f7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: expected a name argument to this function) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1222, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1222, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2c1c92a4de00ef40bfea4f00e54b69d7bc75ee54d050fae4a88a3e4c82f1c358", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: match on a optional type uses the following syntax: (match input some-name if-some-expression if-none-expression). Caused by: expected a name argument to this function) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1222, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1222, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_optional_or_response_type.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_optional_or_response_type.snap new file mode 100644 index 00000000000..07d3160d3e1 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_optional_or_response_type.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3de467f48119164c4e38dd507c6ac2dd63d252126c28fc55a565e24811e350fa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-opt-or-res-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type \'optional\' or \'response\', found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 485, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 485, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d48d16f993514ee365ad3a5084e5a0cd90ffaa998576f29b08ea7829061d8fdb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-opt-or-res-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting expression of type \'optional\' or \'response\', found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 485, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 485, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2a70d824d647785c1a02731ef4f0c171418a95141a713fd30bf242a2b924d871", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-opt-or-res-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting expression of type \'optional\' or \'response\', found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 485, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 485, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bc318401894ea3764f45c3953e42c42459616b9fdff0f66f6e8ac78cf466a052", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: exp-opt-or-res-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting expression of type \'optional\' or \'response\', found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 485, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 4, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 485, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_optional_type.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_optional_type.snap new file mode 100644 index 00000000000..80603c82751 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_optional_type.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "68e84be6abc605f8b749ffddc651ac1638855423b92fafc696e2838da89dcf88", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-optional-type-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type \'optional\', found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 824, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 824, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bfb613860a5e65ab56c3f5acf848606403d0deb242266e9c1d2e1ad6fcae982d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-optional-type-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting expression of type \'optional\', found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 824, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 824, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9f6fb0577f689f1d6db402eb2808bf97cbc0847ea1bedbffcd9e5a0a89408fae", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-optional-type-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting expression of type \'optional\', found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 824, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 824, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "20da9f02d0887429722f522078650e78b1526ca526380719fbd6ef262ec0c03d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-optional-type-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting expression of type \'optional\', found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 824, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 824, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_response_type.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_response_type.snap new file mode 100644 index 00000000000..d9dade64f89 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_response_type.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "958e85fdbd6d7dee181af20aa952a51577ebbf3bba213cfd6c19e98817192959", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-response-type-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type \'response\', found \'(optional int)\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1065, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1065, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "94881c3c68d1bb85663f37a1fe1d673a32d8331b195a2a7e194d75b25d7f7e37", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-response-type-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting expression of type \'response\', found \'(optional int)\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1065, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1065, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d53be84c1c2cadec503d46f6b0771d6af6fc85412f29ca1a279df8591ca9ce56", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-response-type-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting expression of type \'response\', found \'(optional int)\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1065, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1065, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6e4572f1139387ea145d90ed200de8a5b7d3758ee40912f20cf64e0e77db4312", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-response-type-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting expression of type \'response\', found \'(optional int)\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1065, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1065, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_sequence.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_sequence.snap new file mode 100644 index 00000000000..050d7077c8c --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_sequence.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "68e84be6abc605f8b749ffddc651ac1638855423b92fafc696e2838da89dcf88", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-sequence-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type \'list\', \'buff\', \'string-ascii\' or \'string-utf8\' - found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 713, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 713, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fffbc8001d406da6c9d701e076029c33b44baaaceca50dc6f5d8bb717cad04ea", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-sequence-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting expression of type \'list\', \'buff\', \'string-ascii\' or \'string-utf8\' - found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 713, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 713, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f956aea7606dc0bd69e1cd3ec9be3e528469b8335752f1635d722c707857b2d3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-sequence-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting expression of type \'list\', \'buff\', \'string-ascii\' or \'string-utf8\' - found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 713, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 713, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3eff9b43bb6fa8209b9ef1fa31f4539c5026ef47296a836e26bcfddb329059e1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-sequence-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting expression of type \'list\', \'buff\', \'string-ascii\' or \'string-utf8\' - found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 713, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 713, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_tuple.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_tuple.snap new file mode 100644 index 00000000000..cff0f070627 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_expected_tuple.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "a1ba1c6711af9225754f4503aaa15ea11c8b043513b5630c32582be50ebf43a3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-tuple-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting tuple, found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 882, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 882, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b1cbab15093f365816c5ff07d570d4d2cab5d461797cef48082a05a108cd64b5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-tuple-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting tuple, found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 882, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 882, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5703a29c37bb7dd3ff5eacb94ead510ef26e9a3318e2c35cd501549c61054167", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-tuple-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting tuple, found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 882, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 882, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f65260e67901ed7e31cf93b18a6633c4dca0ce207817b302265257fe4c4e6726", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: expected-tuple-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting tuple, found \'int\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 882, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 882, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_block_info_expect_property_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_block_info_expect_property_name.snap new file mode 100644 index 00000000000..612daa387fd --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_block_info_expect_property_name.snap @@ -0,0 +1,66 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "cb5ff6bc3fe2978e0d48ad53032bd7b51715fcfa099febbbbc11effc17f2f919", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: info-exp-prop-name-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: missing property name for block info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 877, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 877, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e0b3b7122d17266152730aeae6ca52fd269e37d495a4aa5a9ef6e5cca13d546a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: info-exp-prop-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: missing property name for block info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 877, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 877, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_burn_block_info_expect_property_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_burn_block_info_expect_property_name.snap new file mode 100644 index 00000000000..4165a24c3be --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_burn_block_info_expect_property_name.snap @@ -0,0 +1,96 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "5311183dc3e03047bd9570c885a42a7d3f6a132564c698d1c01754a21277375e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: burn-exp-prop-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: missing property name for burn block info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1012, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1012, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2538705ec563f283dc4ea81ceeb092022b2d54e8e9cdb73388f1337e2e062d3c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: burn-exp-prop-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: missing property name for burn block info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1012, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1012, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0aeb9ca8becc1b5e8facc045ab0c446a409588389ccc306352acde9127e65924", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: burn-exp-prop-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: missing property name for burn block info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1012, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1012, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_stacks_block_info_expect_property_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_stacks_block_info_expect_property_name.snap new file mode 100644 index 00000000000..f4f2f9afd53 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_stacks_block_info_expect_property_name.snap @@ -0,0 +1,66 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "5e4bbfaf3781fa1f6772bafc466a0e54ead257511f09e1d83bd8e461a4ef60d4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: stacks-exp-prop-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: missing property name for stacks block info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "90e34b79ab849883221a3981a8f4fe037dbeab06e328a921038a7741ab99de42", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: stacks-exp-prop-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: missing property name for stacks block info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_tenure_info_expect_property_name.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_tenure_info_expect_property_name.snap new file mode 100644 index 00000000000..803db8a4a7a --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_get_tenure_info_expect_property_name.snap @@ -0,0 +1,66 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "958e85fdbd6d7dee181af20aa952a51577ebbf3bba213cfd6c19e98817192959", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: tenure-exp-prop-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: missing property name for tenure info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 904, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 904, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "78d556d0bd35e61eb279623a78ebbd9fb70007346606d959e6260b14ffb4ba6b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: tenure-exp-prop-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: missing property name for tenure info introspection) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 904, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 904, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_if_arms_must_match.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_if_arms_must_match.snap new file mode 100644 index 00000000000..16b8efb718c --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_if_arms_must_match.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "68e84be6abc605f8b749ffddc651ac1638855423b92fafc696e2838da89dcf88", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: if-arms-must-match-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expression types returned by the arms of \'if\' must match (got \'bool\' and \'int\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 981, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 981, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "17d67b2dc90b68061c646dd066a4715e2f94f5f680462d91b38fc0ce1c62aff5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: if-arms-must-match-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expression types returned by the arms of \'if\' must match (got \'bool\' and \'int\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 980, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 980, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1bfef61e9b94cf689c03cea835d26f747d6bb009923a1d6648747f69bc24fb5a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: if-arms-must-match-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expression types returned by the arms of \'if\' must match (got \'bool\' and \'int\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 980, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 980, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "974ef8d241da5da9690a045ee8c8584f1977711c3f6a9b28ac27e2f0304fc451", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: if-arms-must-match-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expression types returned by the arms of \'if\' must match (got \'bool\' and \'int\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 980, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 980, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_illegal_or_unknown_function_application.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_illegal_or_unknown_function_application.snap new file mode 100644 index 00000000000..d140055986d --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_illegal_or_unknown_function_application.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "c7325ae92d1ef974494c13e18014778fbe87f74a3c654eb5f9461aa7d38fcc34", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: illegal-or-unknown-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of illegal / unresolved function \'if) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 961, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 961, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8c5aa701c6f5bfdea3b0c4df1753c523064047ecac9157372925417c98614c36", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: illegal-or-unknown-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: use of illegal / unresolved function \'if) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 961, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 961, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "01ea0cb64763fa6d72f3dfb6a11ee8b41e7f75d7fdd9cdbc0c3cc18eabdd6020", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: illegal-or-unknown-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of illegal / unresolved function \'if) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 961, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 961, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2bf1a90fe696763b4bbd9cc1009a67b9bc52eb61c7dd4bc5320df60dad3ce356", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: illegal-or-unknown-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of illegal / unresolved function \'if) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 961, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 961, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_incompatible_trait.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_incompatible_trait.snap new file mode 100644 index 00000000000..d85e3a9be72 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_incompatible_trait.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "1a93804dc742a3f03d31684ac4548229f31c5d375a3426fd96cdcebd7d645e91", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: incompatible-trait-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type \'\', found \'\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 47, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 10728, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 47, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 10728, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "077f2e58b7d899f0ae06b675f3cae7209e0d7c67144d2220aec1e30d1a5590f4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: incompatible-trait-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: trait \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.incompatible-trait-Epoch3_3-Clarity2.trait-1\' is not a compatible with expected trait, \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.incompatible-trait-Epoch3_3-Clarity2.trait-2\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 47, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 10716, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 47, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 10716, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6e0c426707d05d4b770e487d836b9f56da67239a9693db77d7f1c5605e9a3ead", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: incompatible-trait-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: trait \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.incompatible-trait-Epoch3_3-Clarity3.trait-1\' is not a compatible with expected trait, \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.incompatible-trait-Epoch3_3-Clarity3.trait-2\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 47, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 10716, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 47, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 10716, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ccc4a7402c9aa8f7db5ad4a8719465e83eb21c7e33faecee0f25c30ac2966cce", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: incompatible-trait-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: trait \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.incompatible-trait-Epoch3_3-Clarity4.trait-1\' is not a compatible with expected trait, \'ST1AW6EKPGT61SQ9FNVDS17RKNWT8ZP582VF9HSCP.incompatible-trait-Epoch3_3-Clarity4.trait-2\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 47, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 10716, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 47, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 10716, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_incorrect_argument_count.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_incorrect_argument_count.snap new file mode 100644 index 00000000000..bd09ed7fdaa --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_incorrect_argument_count.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "cb5ff6bc3fe2978e0d48ad53032bd7b51715fcfa099febbbbc11effc17f2f919", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: incorrect-arg-count-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting 1 arguments, got 2) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 885, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 885, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5228eb6774874cafae8a3ebdaf0b479cf2ed71a4cfd93a474aba042d7e205dc0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: incorrect-arg-count-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting 1 arguments, got 2) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 885, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 885, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "6ee5821301445e04cb2ffa00ffb78a8b972a0cbf466e6cb64656229f9ea731cb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: incorrect-arg-count-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting 1 arguments, got 2) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 885, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 885, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e4bda05caa58cbc187f11e14b57be40a4127a400c993d6b66145568d87d4469c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: incorrect-arg-count-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting 1 arguments, got 2) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 885, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 885, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_invalid_type_description.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_invalid_type_description.snap new file mode 100644 index 00000000000..8b9de5a3bd2 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_invalid_type_description.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "8d956af6b22c472853f432445276d339d3b57589470915f8cc1fad0bd18c925a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: invalid-type-desc-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: invalid variable definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "50c6da88adec86d434a6cca0862f53e7b6122afa51c4cdc0475e61996f20f6bd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: invalid-type-desc-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: invalid variable definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9b7277c6c51eba3c77c38cda1c6ea16384121617cd587609a00b79e08565fbdd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: invalid-type-desc-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: invalid variable definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1175, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d21e9ecd5b113dcb0023aad628c58fd4f5e02382ea8c023dae664462cbf0addf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: invalid-type-desc-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: invalid variable definition) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1175, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1175, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_match_arms_must_match.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_match_arms_must_match.snap new file mode 100644 index 00000000000..46efcf1a439 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_match_arms_must_match.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "256ea4635a6a42d3c1f2156bd5920433c97526be10cff0d883110fd0ecc7f05b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: match-arms-must-match-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expression types returned by the arms of \'match\' must match (got \'int\' and \'bool\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2512, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2512, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2b5bff06b55870af1aaa29621e32c792b8579745e0e32cc58e3bf40e7fa79544", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: match-arms-must-match-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expression types returned by the arms of \'match\' must match (got \'int\' and \'bool\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2512, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2512, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "872451e72c2e6d1e11fc4a31eb73857376fd111833247bf3a0cf445bf9ab4d83", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: match-arms-must-match-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expression types returned by the arms of \'match\' must match (got \'int\' and \'bool\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2512, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2512, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f98dbc36353694cba28fe7d06eb14cc75069cb72af5b21abc7cf533843724423", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: match-arms-must-match-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expression types returned by the arms of \'match\' must match (got \'int\' and \'bool\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2512, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 15, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2512, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_max_identifier_length_exceeded.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_max_identifier_length_exceeded.snap new file mode 100644 index 00000000000..91f35367647 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_max_identifier_length_exceeded.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "9dd6b272e6b172c3dc38c13567f38974e96caef45e70e4c1b362acaad56c838f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: max-ident-len-excd-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: with-nft allowance identifiers list must not exceed 128 elements, got 130) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 142, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 16108, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 142, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 16108, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_name_already_used.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_name_already_used.snap new file mode 100644 index 00000000000..f347796dac5 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_name_already_used.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ef8ca5e533b17f2746804c4ead9de18b1a04cb18dabe4c1c8d309a19628912e4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: defining \'foo\' conflicts with previous value) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2187, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2187, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "d77984d1398e5f4200b6a21aa2758aa3d8f0b75c1d965349a72066db1608f6cb", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: defining \'foo\' conflicts with previous value) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2187, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2187, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e43f00aff1cbcbd51997927e276c050713caf919ad177650df2b40205c5019fa", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: defining \'foo\' conflicts with previous value) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2187, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2187, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1f82cfdc4fbbf5a4f08cb2b39eb2e499e392a167a4f07ca15b0102b1d4ac0a12", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: name-already-used-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: defining \'foo\' conflicts with previous value) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2187, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2187, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_block_info_property.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_block_info_property.snap new file mode 100644 index 00000000000..6c4f64c3216 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_block_info_property.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "5e4bbfaf3781fa1f6772bafc466a0e54ead257511f09e1d83bd8e461a4ef60d4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-block-info-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of unresolved function \'get-burn-block-info?\') [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: 963, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 963, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "92416f81d8f176f3502973d49ae12b8f5bcb775d60540eb2712984fdd31f48d5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-block-info-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: use of block unknown property \'none\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ecd44b2c8364f595a463ee3343a9200f074b53865f9384b2f950411b5ef130cf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-block-info-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of block unknown property \'none\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c02b6614c84aaa45bf63ecedbd58bb702bd512c840ddbfc1e259f1110cf9ef01", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-block-info-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of block unknown property \'none\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1066, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_contract.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_contract.snap new file mode 100644 index 00000000000..7095eed2ff3 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_contract.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "cb65c4db199772d38250885573213cd047ab5a6005280da51ec86ec999d84665", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-contract-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of unresolved contract \'S1G2081040G2081040G2081040G208105NK8PE5.contract-name\') [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: 2313, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2313, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f7316094315e5d5ac178cc4fbf95341c5881e8c61edb52f645dbf7cdd67feb18", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-contract-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: use of unresolved contract \'S1G2081040G2081040G2081040G208105NK8PE5.contract-name\') [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: 2313, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2313, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fd98f918d2b6d52ef0aea257587312a017f213dce48a4bf091571535020c5004", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-contract-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of unresolved contract \'S1G2081040G2081040G2081040G208105NK8PE5.contract-name\') [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: 2313, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2313, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3bde921adb5ec8f2bc5923735cfbba7a51199a2326bd36274088d7e3c85a61e8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-contract-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of unresolved contract \'S1G2081040G2081040G2081040G208105NK8PE5.contract-name\') [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: 2313, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2313, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_data_variable.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_data_variable.snap new file mode 100644 index 00000000000..a79095c6fd8 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_data_variable.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "8d004a3557c0396f4fc38d9ce6bf700be2d07f6afab03f03ff4e97ab98fe0f01", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-data-var-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of unresolved persisted variable \'cursor\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b2566dfa83802a5f0ceb47dd31cc69cfbac9066e5727b47b83480ba4efed56dd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-data-var-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: use of unresolved persisted variable \'cursor\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8c609a64eaa93fbf5e7a54b4874deb11c4b1d14c5b86ff131e8a27eb979197d3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-data-var-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of unresolved persisted variable \'cursor\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2510, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "391d634f78731f647f3b224224b5a2934778aaf0a2330453469f91c951c4abe2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-data-var-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of unresolved persisted variable \'cursor\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2510, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2510, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_ft.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_ft.snap new file mode 100644 index 00000000000..66a74dafeb5 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_ft.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ffa3b803b8f265d11fba465d54eccf469db85763d8f9158d759d670d18eb876a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-ft-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: tried to use token function with a undefined token (\'stackoos\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1201, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1201, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2a8ef23dd15fa90350e9435cc60f2eb1b638cc22e6465301ae951fae64fad714", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-ft-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: tried to use token function with a undefined token (\'stackoos\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1201, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1201, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "55d35c7909bcbb26fef287cdb3a6a370d6d835d898dbffd3161145cff2cfb0a3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-ft-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: tried to use token function with a undefined token (\'stackoos\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1201, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1201, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "68dfd25e2274ddc5a37d8df70aff670b46cf18c51870521cacc1375b9f904ea0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-ft-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: tried to use token function with a undefined token (\'stackoos\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1201, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1201, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_map.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_map.snap new file mode 100644 index 00000000000..7c4f1899730 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_map.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "e98fcb2f30a5cca370fc492fca335c2094657af7c8229458cf187a26f82b8bbf", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-map-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of unresolved map \'non-existent\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1406, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1406, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2e60017ad42ef0c335699107b71612755451d95258bc0b07c9cf6ac6663cf3b9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-map-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: use of unresolved map \'non-existent\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1406, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1406, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3c2493928bbe73bf44a80cd72a68e265381c5cb777b6ac6dcc0f686d9dfffb5c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-map-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of unresolved map \'non-existent\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1406, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1406, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f90b3a977860c34f8ba95f7f5187bc447fe8ed4416b5ae354590c9f66b1b16a6", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-map-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of unresolved map \'non-existent\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1406, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1406, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_nft.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_nft.snap new file mode 100644 index 00000000000..537d945bd89 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_nft.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "56fa04cf02387fdc8e68b68ad163927126a2928ac81eb1bb1605a3399017304d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-nft-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: tried to use asset function with a undefined asset (\'stackoos\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1093, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1093, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "86b2d758ddee687dc42948d4dfd0ed94a5c109831e5383b28708f3c196b2f4b0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-nft-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: tried to use asset function with a undefined asset (\'stackoos\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1093, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1093, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fc7ff58c3d0860ee7a0b3e223c5e39924eb53180f8be38ee64f733dc1648d256", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-nft-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: tried to use asset function with a undefined asset (\'stackoos\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1093, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1093, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "56c0870f17b38ae5fc0c0c1c6f4fa8176bf487be70f393ceb92199e9ee898b2e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-nft-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: tried to use asset function with a undefined asset (\'stackoos\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1093, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1093, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_public_function.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_public_function.snap new file mode 100644 index 00000000000..d0c4a8eae2b --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_public_function.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ef8ca5e533b17f2746804c4ead9de18b1a04cb18dabe4c1c8d309a19628912e4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-pub-func-lit-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: contract \'ST000000000000000000002AMW42H.pox-4\' has no public function \'missing-func\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2038, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2038, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1478b5991938a292f48ad6c99d4c73c249fcb6d204bd8767f24ec6552706d872", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-pub-func-lit-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: contract \'ST000000000000000000002AMW42H.pox-4\' has no public function \'missing-func\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2038, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2038, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8b43ac26e0f5478ea5eee07b9ba210b5612a44b9790bc78e41c04d218df02e09", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-pub-func-lit-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: contract \'ST000000000000000000002AMW42H.pox-4\' has no public function \'missing-func\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2038, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2038, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fc35fc956ded04bc69eeed04007653a9f1bad12a06a9a86c5149e7454639e8a8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-pub-func-lit-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: contract \'ST000000000000000000002AMW42H.pox-4\' has no public function \'missing-func\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2038, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2038, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_stacks_block_info_property.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_stacks_block_info_property.snap new file mode 100644 index 00000000000..7a06cbb4c4c --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_stacks_block_info_property.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3390089ac0826e8e5677d5093fa3d0db6081e88e6a1763017efc763d3cb96b16", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-stacks-info-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of unresolved function \'get-stacks-block-info?\') [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: 1017, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1017, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "64fb9f9ab0c3614ea4e930ebfe84e18fadc7416c45239de31a6e4b855230980b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-stacks-info-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: use of unresolved function \'get-stacks-block-info?\') [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: 1017, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 1017, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cfc29fea26824fd483854c762b704c0822c18f5effa466ad963b680e016f6c6d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-stacks-info-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of unknown stacks block property \'none\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cc72f611641398e40a9d3008a4fb4c94071d0f7ba1d61ac620cb3c23823ac4dc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-stacks-info-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of unknown stacks block property \'none\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1120, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_tenure_info_property.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_tenure_info_property.snap new file mode 100644 index 00000000000..57c0e9a3371 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_tenure_info_property.snap @@ -0,0 +1,66 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "690118c9fd710a6064dffcf0e76029e0cddb898e18675d08e48a62c6e0ea4828", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-tenure-info-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of unknown tenure property \'none\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 958, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 958, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "b5d4cb40c9460e09eb53193e29ea16ab8cb947543ae1b9d17a944036f197bf0e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-tenure-info-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of unknown tenure property \'none\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 958, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 958, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_tuple_field.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_tuple_field.snap new file mode 100644 index 00000000000..1bb07fdfe81 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_no_such_tuple_field.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "5311183dc3e03047bd9570c885a42a7d3f6a132564c698d1c01754a21277375e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-tuple-f-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: cannot find field \'value\' in tuple \'(tuple (name int))\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1084, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1084, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "aafac2400c9f46aa4757effb68e47f1bbbc3656762aa7f559314f5c315955a21", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-tuple-f-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: cannot find field \'value\' in tuple \'(tuple (name int))\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1084, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1084, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9448f4697bfcc8f0017d7624be86e4066e1611f00ba2e377a76986057862af2d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-tuple-f-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: cannot find field \'value\' in tuple \'(tuple (name int))\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1084, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1084, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "330e9e70da320f3623685c31803bb3058985178b1e2e10873e9a1dd6863c3731", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: no-such-tuple-f-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: cannot find field \'value\' in tuple \'(tuple (name int))\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1084, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 9, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1084, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_non_function_application.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_non_function_application.snap new file mode 100644 index 00000000000..da45c82d904 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_non_function_application.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "a1ba1c6711af9225754f4503aaa15ea11c8b043513b5630c32582be50ebf43a3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: non-function-appl-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type function) [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: 747, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 747, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5e191be88410092614da6257b0ba35c94719661e187b6b4be0afa3ed6a56e729", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: non-function-appl-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting expression of type function) [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: 747, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 747, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "52f92f4990c2752eb3131f983126a2697b432f47c51876376b92c7e996c10d3b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: non-function-appl-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting expression of type function) [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: 747, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 747, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ea5433d4326b513d4b121aa290241c3bc36f3aa889e6f872244a118b49b29bfd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: non-function-appl-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting expression of type function) [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: 747, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 747, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_requires_at_least_arguments.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_requires_at_least_arguments.snap new file mode 100644 index 00000000000..61177f017e7 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_requires_at_least_arguments.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "98eb69ac91e37f908772babde2e079f6da7a1a1e3fcd0e93e84ef8f41499e8c8", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: requires-at-least-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting >= 1 arguments, got 0) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 3, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 441, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 3, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 441, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "18b9658eab5abf77cf0bac933f623232c079427506200af3b86d7096c183f068", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: requires-at-least-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting >= 1 arguments, got 0) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 3, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 441, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 3, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 441, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0487080b36b09b41443b092c4ce5a49238aefe8bcb866d29f6776cef2cf1df08", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: requires-at-least-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting >= 1 arguments, got 0) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 3, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 441, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 3, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 441, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "fd8b4ff67400d03905e9a6b0d815e322cf43af7327b8d192c4ec1ae27ab2cfc1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: requires-at-least-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting >= 1 arguments, got 0) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 3, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 441, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 3, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 441, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_requires_at_most_arguments.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_requires_at_most_arguments.snap new file mode 100644 index 00000000000..a3af63e5680 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_requires_at_most_arguments.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "3e74c16a03b30f200a53276325e94fce8280f2e7745a293e5c4254a545b7b3d2", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: requires-at-most-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of unresolved function \'principal-construct?\') [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: 2367, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 2367, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "636875c2a9d713f29db8f130a3ac302369d204cd7ba30f571b3216899cc33c82", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: requires-at-most-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting < 3 arguments, got 4) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2474, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2474, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ebd425d842ec7a5dd53994cbf9de2cc71e5903a5eb8febe9a212fc40aad03360", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: requires-at-most-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting < 3 arguments, got 4) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2474, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2474, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f5f81bd7bee23120b8fead863a2da45011771c2b6b5c49d1b33aef35daacaaa9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: requires-at-most-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting < 3 arguments, got 4) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2474, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 7, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2474, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_reserved_word.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_reserved_word.snap new file mode 100644 index 00000000000..3fdb7035fde --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_reserved_word.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "080e462a7a4181ec7a8eeecef8d0902641c1d9e71e8c70416c7dd1816231d41f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: reserved-word-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(NameAlreadyUsed(\"block-height\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8876, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8876, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4f892af1a8a0482ac3b3484326827e306ec68c081aac438cf73738703bc2b470", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: reserved-word-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(NameAlreadyUsed(\"block-height\")) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8876, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 43, + write_count: 2, + read_length: 1, + read_count: 1, + runtime: 8876, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bf4452408f9e33d9a4230c4542ca06ee24dae1be2cb09160e2e5b6e4dfa9fd35", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: reserved-word-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: block-height is a reserved word) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1315, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1315, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5bac3e80337a660b56e8f46d47ad93ee63f12fafb48d1feac32a2a7a44f0a20f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: reserved-word-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: block-height is a reserved word) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1315, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1315, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_return_types_must_match.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_return_types_must_match.snap new file mode 100644 index 00000000000..3661e1a834d --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_return_types_must_match.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "7f0d4415c43fb0e25c9e4c06d9b3ba65180e232e1988fccb85c978d138b89f72", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: return-types-must-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: detected two execution paths, returning two different expression types (got \'(response UnknownType int)\' and \'(response UnknownType bool)\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 42, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 9463, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 42, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 9463, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2437107153b4aa494ce6dc95a9d1d63dbf2c52e4b2a26633859fe634cb4ab17b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: return-types-must-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: detected two execution paths, returning two different expression types (got \'(response UnknownType int)\' and \'(response UnknownType bool)\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 42, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 9463, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 42, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 9463, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1d324958dccc3217e0ab81c63a043b7195ec9bc9e7c41dab31adef097e28351f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: return-types-must-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: detected two execution paths, returning two different expression types (got \'(response UnknownType int)\' and \'(response UnknownType bool)\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 42, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 9463, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 42, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 9463, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "39c2be546aa7b90c1a95055f6dca367ff2465422aeb0b10e8c9c2fbcb144ba1d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: return-types-must-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: detected two execution paths, returning two different expression types (got \'(response UnknownType int)\' and \'(response UnknownType bool)\')) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 42, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 9463, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 42, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 9463, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_supertype_too_large.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_supertype_too_large.snap new file mode 100644 index 00000000000..9824d0e21ca --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_supertype_too_large.snap @@ -0,0 +1,22 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block 0d9a22b0addac68110e11145d19a57186b7e6b7ea42f2ed8027edc9ef93f5a86: ClarityError(StaticCheck(StaticCheckError { err: SupertypeTooLarge, expressions: Some([SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"append\")), id: 41 }, SymbolicExpression { expr: Atom(ClarityName(\"initial\")), id: 42 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"tuple\")), id: 44 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"a\")), id: 46 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"var-get\")), id: 48 }, SymbolicExpression { expr: Atom(ClarityName(\"small\")), id: 49 }]), id: 47 }]), id: 45 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"b\")), id: 51 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"var-get\")), id: 53 }, SymbolicExpression { expr: Atom(ClarityName(\"big\")), id: 54 }]), id: 52 }]), id: 50 }]), id: 43 }]), id: 40 }]), diagnostic: Diagnostic { level: Error, message: \"supertype of two types is too large\", spans: [Span { start_line: 0, start_column: 0, end_line: 0, end_column: 0 }], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block df41e1ebe0ce7009fb04a926c36f91d2fed2f08df5ce309f42ac948d97051d18: ClarityError(StaticCheck(StaticCheckError { err: SupertypeTooLarge, expressions: Some([SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"append\")), id: 41 }, SymbolicExpression { expr: Atom(ClarityName(\"initial\")), id: 42 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"tuple\")), id: 44 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"a\")), id: 46 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"var-get\")), id: 48 }, SymbolicExpression { expr: Atom(ClarityName(\"small\")), id: 49 }]), id: 47 }]), id: 45 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"b\")), id: 51 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"var-get\")), id: 53 }, SymbolicExpression { expr: Atom(ClarityName(\"big\")), id: 54 }]), id: 52 }]), id: 50 }]), id: 43 }]), id: 40 }]), diagnostic: Diagnostic { level: Error, message: \"supertype of two types is too large\", spans: [Span { start_line: 0, start_column: 0, end_line: 0, end_column: 0 }], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block cd532364f7eab92dad8d01e3f9f414b41deb8d0c6166b164f2ce12f0bbd76436: ClarityError(StaticCheck(StaticCheckError { err: SupertypeTooLarge, expressions: Some([SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"append\")), id: 41 }, SymbolicExpression { expr: Atom(ClarityName(\"initial\")), id: 42 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"tuple\")), id: 44 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"a\")), id: 46 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"var-get\")), id: 48 }, SymbolicExpression { expr: Atom(ClarityName(\"small\")), id: 49 }]), id: 47 }]), id: 45 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"b\")), id: 51 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"var-get\")), id: 53 }, SymbolicExpression { expr: Atom(ClarityName(\"big\")), id: 54 }]), id: 52 }]), id: 50 }]), id: 43 }]), id: 40 }]), diagnostic: Diagnostic { level: Error, message: \"supertype of two types is too large\", spans: [Span { start_line: 0, start_column: 0, end_line: 0, end_column: 0 }], suggestion: None } }))", + )), + Failure(ExpectedFailureOutput( + evaluated_epoch: Epoch33, + error: "Invalid Stacks block fedb5abccb1d54e207251e441644ae6a460eb8f159e90204d76a71758179b20e: ClarityError(StaticCheck(StaticCheckError { err: SupertypeTooLarge, expressions: Some([SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"append\")), id: 41 }, SymbolicExpression { expr: Atom(ClarityName(\"initial\")), id: 42 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"tuple\")), id: 44 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"a\")), id: 46 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"var-get\")), id: 48 }, SymbolicExpression { expr: Atom(ClarityName(\"small\")), id: 49 }]), id: 47 }]), id: 45 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"b\")), id: 51 }, SymbolicExpression { expr: List([SymbolicExpression { expr: Atom(ClarityName(\"var-get\")), id: 53 }, SymbolicExpression { expr: Atom(ClarityName(\"big\")), id: 54 }]), id: 52 }]), id: 50 }]), id: 43 }]), id: 40 }]), diagnostic: Diagnostic { level: Error, message: \"supertype of two types is too large\", spans: [Span { start_line: 0, start_column: 0, end_line: 0, end_column: 0 }], suggestion: None } }))", + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_too_many_allowances.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_too_many_allowances.snap new file mode 100644 index 00000000000..ba19ab249b7 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_too_many_allowances.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "0ae4e1e13b67a919db60017efe073dafc1785c8a4065908d316580bd5a893c5d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-allowances-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: too many allowances specified, the maximum is 128, found 130) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 396, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 51150, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 396, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 51150, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_too_many_function_parameters.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_too_many_function_parameters.snap new file mode 100644 index 00000000000..6a00a27d377 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_too_many_function_parameters.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "51a9d4d6a816bdd1e92d4cfac521a418d8cee787792789298efb632d1bcb8bab", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-params-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: too many function parameters specified: found 257, the maximum is 256) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 269, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 36990, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 269, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 36990, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "628c64177ed5b43871fcc2bd01aca435323ff71dc797c2c3f30e9d148754e992", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-params-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: too many function parameters specified: found 257, the maximum is 256) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 269, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 36990, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 269, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 36990, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a5083ad371b92eee22aac7076556ec90fc3595f7356fd874a8468427d3849771", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-params-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: too many function parameters specified: found 257, the maximum is 256) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 269, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 36990, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 269, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 36990, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ee51cf5ddbbc54498c2888dee162d23164f6e486cfef544fe5bed887e079b3b4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-params-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: too many function parameters specified: found 257, the maximum is 256) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 269, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 36990, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 269, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 36990, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_method_unknown.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_method_unknown.snap new file mode 100644 index 00000000000..38ac475ae9e --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_method_unknown.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "a925c201881f9c7149edb74985364d4e86a42cb0894811728f3e71c68ef53607", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-method-unknown-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: method \'get-2\' unspecified in trait ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 25, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 5648, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 25, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 5648, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "35b7334ac59f88a13a95025c2628ac7b747fa0f641788cb9e6e3b043c95ed6dd", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-method-unknown-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: method \'get-2\' unspecified in trait ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 25, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 5648, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 25, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 5648, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "87b22a54be9809e39fe3bf61d8d0a9161ff0247408273039d114804433102dd1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-method-unknown-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: method \'get-2\' unspecified in trait ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 25, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 5648, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 25, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 5648, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "c5f2037cec2f8e26848997e2bd60fc5a1808e22d064426f8c7dfe6ccb334840f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-method-unknown-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: method \'get-2\' unspecified in trait ) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 25, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 5648, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 25, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 5648, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_reference_unknown.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_reference_unknown.snap new file mode 100644 index 00000000000..0130cfa10ce --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_reference_unknown.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "d0a94b5b4ced232c0486676e46e31c76bceec5392bb7f6ffd31577e50ff99ca0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-ref-unknown-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(use of undeclared trait ) [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: 558, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 558, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "1b4f335ad5764e2fa177afbbd2a7b9883efe30d262b28626d0eef692c8f1c327", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-ref-unknown-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(use of undeclared trait ) [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: 558, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 558, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "14d91c5f8a01918944f4895723b4e73b6c2fea0fa414c54df4bf497169600c44", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-ref-unknown-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(use of undeclared trait ) [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: 558, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 558, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2a7a1dca4d1856d94ceb3237d69a9beb7ee19e0c4e370f95e3d61e7052fd79c1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-ref-unknown-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(use of undeclared trait ) [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: 558, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 558, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_too_many_methods.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_too_many_methods.snap new file mode 100644 index 00000000000..5147ab5e7e3 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_trait_too_many_methods.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "7b3b22d0107e05d40a066b9235572a3a3158d4075985c61b0c857c0dddbdbc0a", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-methods-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: too many trait methods specified: found 257, the maximum is 256) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 2061, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 286544, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 2061, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 286544, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3518af9fede23f6500dfe0a7dff52e8056413146d8f8227c974d011867b766ce", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-methods-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: too many trait methods specified: found 257, the maximum is 256) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 2061, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 286544, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 2061, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 286544, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cb06c378924b9b5f23feff54ce6adb506a90cfa851ba50cd7293df08e27058d3", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-methods-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: too many trait methods specified: found 257, the maximum is 256) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 2061, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 286544, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 2061, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 286544, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "18396ce9aa4c072b9b9e1b254b520032904d7f25e3c61eb129ea7602ec75bb73", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: too-many-methods-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: too many trait methods specified: found 257, the maximum is 256) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 2061, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 286544, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 2061, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 286544, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_type_error.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_type_error.snap new file mode 100644 index 00000000000..6456cb107fc --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_type_error.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "649dbc0fcb271409512009fd37644542578f70d371499e7e9ba1139a37bea3f4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-error-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type \'int\', found \'bool\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1288, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1288, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "9e0346bac690a5ab54480ba4b21a444ff77e70268a3a6838277cae6d41e58dbc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-error-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting expression of type \'int\', found \'bool\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1277, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1277, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2fd93f350a09578a2a9b13e9e71fa7f477468488139f024ed736c6add75e141b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-error-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting expression of type \'int\', found \'bool\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1277, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1277, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "aa2415bf06af8e35464b356fd883fac1de6f723df6010e3fb29dc7df5028d201", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: type-error-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting expression of type \'int\', found \'bool\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1277, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1277, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_type_signature_too_deep.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_type_signature_too_deep.snap new file mode 100644 index 00000000000..7e29d6e19cc --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_type_signature_too_deep.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "21cdf140aba22fc6bcef7daa80b07ae37626be01cdd3f01b97ae853e01fdbeae", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: signature-too-deep-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: created a type which was deeper than maximum allowed type depth) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 77, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 12036, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 77, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 12036, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e7db8eca76b5504c7b85c6411dcdd610fcf3c32eb06380bf2cf037e94c887d54", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: signature-too-deep-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: created a type which was deeper than maximum allowed type depth) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 77, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 12036, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 77, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 12036, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bf06432ec317866df4959ebd47b128cd073bb1239bb84199c8a127d79f79ca97", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: signature-too-deep-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: created a type which was deeper than maximum allowed type depth) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 77, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 12036, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 77, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 12036, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "ee8b2687c1a225f00b4cc5d0d0f1bbea3bec7efca2508469044dce9b1913e420", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: signature-too-deep-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: created a type which was deeper than maximum allowed type depth) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 77, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 12036, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 77, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 12036, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unchecked_intermediary_responses.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unchecked_intermediary_responses.snap new file mode 100644 index 00000000000..225c1d5e122 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unchecked_intermediary_responses.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "44404afb73f927ad02e570b5189847084801458e4a8b68eb1a92273c0e13794d", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unchecked-resp-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: intermediary responses in consecutive statements must be checked) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3222, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3222, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "53ee0e161ae3c99502b61b1cbc75b70a26a85fc67cb805285de2deedd4a0632b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unchecked-resp-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: intermediary responses in consecutive statements must be checked) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3222, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3222, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "60a072c35aa07afd9656cd0d3413cf1e16996dd2dea5fd36fb6ea92aee76772e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unchecked-resp-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: intermediary responses in consecutive statements must be checked) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3222, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3222, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "264a55159341b88b30fa5c70c3cc965bc92e237fdefbadd1a788a7d51ca49787", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unchecked-resp-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: intermediary responses in consecutive statements must be checked) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3222, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 13, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3222, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_undefined_variable.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_undefined_variable.snap new file mode 100644 index 00000000000..3a4878fdbd3 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_undefined_variable.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "9a7b61f181ef8592a441f9ecc91bbc12f9a1793cfbec3513e4721f18d67d759c", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undefined-variable-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of unresolved variable \'x\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 517, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 517, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f4b0a03b9ae73d9bd1e1ec77670fbcdd90191aaad5b777c134aa496698278c82", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undefined-variable-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: use of unresolved variable \'x\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 517, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 517, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "2686a862c339bc8baea4ad14b9ef33ea86ab206d25181f612337e3c5ef52e934", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undefined-variable-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of unresolved variable \'x\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 517, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 517, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "623998e0fa8cec8ce015897237e9e27614819494755a4cb86254e7db04f78c73", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: undefined-variable-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of unresolved variable \'x\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 517, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 6, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 517, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unexpected_trait_or_field_reference.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unexpected_trait_or_field_reference.snap new file mode 100644 index 00000000000..ea0bae8c33c --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unexpected_trait_or_field_reference.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "4df8213bfda7f9306cb9a8cc6cb151da417f319be324e03a26594a437e72c474", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-or-field-ref-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: unexpected use of trait reference or field) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1969, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1969, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0ae3236c8b5bb036b14deb4fd47186102c90b359f7f6419462f50c6705affbb9", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-or-field-ref-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: unexpected use of trait reference or field) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1969, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1969, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "5b1515a1e15a95b5fa85697ea620d0b86c57a5b22096b32d4097fc2b8e0067dc", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-or-field-ref-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: unexpected use of trait reference or field) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1969, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1969, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "45ecdc8f37187d87929c7853346cdb33e7c906892e1a90670ac02dd7c169f7d0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: trait-or-field-ref-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: unexpected use of trait reference or field) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1969, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1969, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_union_type_error.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_union_type_error.snap new file mode 100644 index 00000000000..6cd1e521288 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_union_type_error.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "080e462a7a4181ec7a8eeecef8d0902641c1d9e71e8c70416c7dd1816231d41f", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: union-type-error-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting expression of type \'int\' or \'uint\', found \'bool\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1532, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1532, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "e864ba8c401b6e6c98eddae56e8358d3fa7eac664522d575b455803a69f0dc71", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: union-type-error-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting expression of type \'int\' or \'uint\', found \'bool\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1532, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1532, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "a5c6e2ca93557a4e7a5654c5516f7adca43040a41cb1adf6e7b3b578cda1f0a7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: union-type-error-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting expression of type \'int\' or \'uint\', found \'bool\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1532, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1532, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "8fedf9ed13bbc6ea39b40cdff9277bcf17d942aeed400fee09cfb49067ebe23e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: union-type-error-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting expression of type \'int\' or \'uint\', found \'bool\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1532, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1532, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unknown_function.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unknown_function.snap new file mode 100644 index 00000000000..41e1ce2f160 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unknown_function.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "1ee5bdee72193aa745d290a84719f9e59f3e339572c34d4f2c495243960a3a64", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unknown-function-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: use of unresolved function \'ynot\') [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: 423, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 423, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "183103b236d5fd0239800d3796872caf19f3fac3ee53d700b25cb9474bb2a2a7", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unknown-function-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: use of unresolved function \'ynot\') [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: 423, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 423, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "4f78241cf302593d752758fbd1d3c7c0430d6cc8404d77f8819a113c3be0acd0", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unknown-function-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: use of unresolved function \'ynot\') [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: 423, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 423, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "78ee0a2b71d680c7a5a5a9538c730648c9b2a25c17c158f07e27684fa8325325", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unknown-function-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: use of unresolved function \'ynot\') [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: 423, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 423, + ), + )), +] 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 new file mode 100644 index 00000000000..37bb457dd8c --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_unknown_type_name.snap @@ -0,0 +1,96 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "8d004a3557c0396f4fc38d9ce6bf700be2d07f6afab03f03ff4e97ab98fe0f01", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unknown-type-name-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: failed to parse type: \'foo\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2519, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2519, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cbe12e1fc1ac7d7c8e51a5017f252d5194eae8f9954bda1db5ff63919ecaea6b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unknown-type-name-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: failed to parse type: \'foo\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2519, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2519, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "461b19fae1c2c4c055386fe3500aca96406c7b4438828249ec0a1d89939348a5", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: unknown-type-name-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: failed to parse type: \'foo\') [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2519, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2519, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_value_out_of_bounds.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_value_out_of_bounds.snap new file mode 100644 index 00000000000..3a3abe305f4 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_value_out_of_bounds.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "ef8ca5e533b17f2746804c4ead9de18b1a04cb18dabe4c1c8d309a19628912e4", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-out-of-bounds-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: created a type which value size was out of defined bounds) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 16, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2200, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 16, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2200, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bec3d23b89c3bfdd06d340e5d350b802737f6977869aa2f72fc6a5321147fc64", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-out-of-bounds-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: created a type which value size was out of defined bounds) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 16, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2200, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 16, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2200, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "bafa0e13d80e915bebff5ef698c11a7c9475e049703682398fe74ca74bd30251", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-out-of-bounds-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: created a type which value size was out of defined bounds) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 16, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2200, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 16, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2200, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "368e99bb4f4feecba50a596d60e53896e397de3f31dca15c0919680bd482753e", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-out-of-bounds-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: created a type which value size was out of defined bounds) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 16, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2200, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 16, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2200, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_value_too_large.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_value_too_large.snap new file mode 100644 index 00000000000..fd90035c6c5 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_value_too_large.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "21ba50be198c8909400b0b345ba2d1f003736af3f1d792c811df76532aeea4ee", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: created a type which was greater than maximum allowed value size) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1024, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1024, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "0e9945b4080ca5bdbe8594c123830a06bae5ef7af6d750d0900acf1788439a86", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: created a type which was greater than maximum allowed value size) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1024, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1024, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "553c14831a345a4282efd9150e165becf4a5835656f75bfea6b86d783cfe7201", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: created a type which was greater than maximum allowed value size) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1024, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1024, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "3c338fda6e9b8e9019df8b399d04e7f76261fc6c14d8457b7c33bc442d2e9d9b", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: value-too-large-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: created a type which was greater than maximum allowed value size) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1024, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 5, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1024, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_all_allowance_not_allowed.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_all_allowance_not_allowed.snap new file mode 100644 index 00000000000..20b37735d80 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_all_allowance_not_allowed.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "592f6545c67772255bea2a807b441ff6f4535efa2ea58964358b15023b2215f1", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: all-allow-not-allowed-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: with-all-assets-unsafe is not allowed here, only in the allowance list for `as-contract?`) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 8, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2029, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 8, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 2029, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_all_allowance_not_alone.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_all_allowance_not_alone.snap new file mode 100644 index 00000000000..6a7c80a2937 --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_all_allowance_not_alone.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "4df8213bfda7f9306cb9a8cc6cb151da417f319be324e03a26594a437e72c474", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: all-allow-not-alone-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: with-all-assets-unsafe must not be used along with other allowances) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1977, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 10, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 1977, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_nft_expected_list_of_identifiers.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_nft_expected_list_of_identifiers.snap new file mode 100644 index 00000000000..0fb94078aef --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_with_nft_expected_list_of_identifiers.snap @@ -0,0 +1,36 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "50a7d2b847f18b54c70237597e75621b9c0ef23979ecc6ed160fea98f0fa2402", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: with-nft-exp-ident-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: with-nft allowance must include a list of asset identifiers) [NON-CONSENSUS BREAKING]", + return_type: Response(ResponseData( + committed: false, + data: Optional(OptionalData( + data: None, + )), + )), + cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3293, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 11, + write_count: 1, + read_length: 1, + read_count: 1, + runtime: 3293, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_write_attempted_in_read_only.snap b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_write_attempted_in_read_only.snap new file mode 100644 index 00000000000..8284f0a63bf --- /dev/null +++ b/stackslib/src/chainstate/tests/snapshots/blockstack_lib__chainstate__tests__static_analysis_tests__static_check_error_write_attempted_in_read_only.snap @@ -0,0 +1,126 @@ +--- +source: stackslib/src/chainstate/tests/static_analysis_tests.rs +expression: result +--- +[ + Success(ExpectedBlockOutput( + marf_hash: "46d7a492d7193b90da9df916ea21aac0b9f068e3aa32146adc1e78bffac73f48", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: write-attempted-in-ro-Epoch3_3-Clarity1, code_body: [..], clarity_version: Some(Clarity1))", + vm_error: "Some(:0:0: expecting read-only statements, detected a writing operation) [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: 3075, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3075, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "49444c1788d84f5f5716e71db049d942a430c4487c2aeada3b86dd24a00e6212", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: write-attempted-in-ro-Epoch3_3-Clarity2, code_body: [..], clarity_version: Some(Clarity2))", + vm_error: "Some(:0:0: expecting read-only statements, detected a writing operation) [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: 3075, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3075, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "f9233e0ec4e33c2db598427877a82173c43a10a73d5f01786869fd63fbd64a12", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: write-attempted-in-ro-Epoch3_3-Clarity3, code_body: [..], clarity_version: Some(Clarity3))", + vm_error: "Some(:0:0: expecting read-only statements, detected a writing operation) [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: 3075, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3075, + ), + )), + Success(ExpectedBlockOutput( + marf_hash: "cf65c9425dcbbacdc72b366f19ea51c508e779049a1d2425eaeb4909af848101", + evaluated_epoch: Epoch33, + transactions: [ + ExpectedTransactionOutput( + tx: "SmartContract(name: write-attempted-in-ro-Epoch3_3-Clarity4, code_body: [..], clarity_version: Some(Clarity4))", + vm_error: "Some(:0:0: expecting read-only statements, detected a writing operation) [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: 3075, + ), + ), + ], + total_block_cost: ExecutionCost( + write_length: 0, + write_count: 0, + read_length: 0, + read_count: 0, + runtime: 3075, + ), + )), +] diff --git a/stackslib/src/chainstate/tests/static_analysis_tests.rs b/stackslib/src/chainstate/tests/static_analysis_tests.rs new file mode 100644 index 00000000000..0f09a5eab2f --- /dev/null +++ b/stackslib/src/chainstate/tests/static_analysis_tests.rs @@ -0,0 +1,1205 @@ +// Copyright (C) 2025 Stacks Open Internet Foundation +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! This module contains consensus tests related to Clarity CheckErrorKind errors that happens during contract analysis. + +use std::collections::HashMap; + +use clarity::types::StacksEpochId; +use clarity::vm::analysis::type_checker::v2_1::{MAX_FUNCTION_PARAMETERS, MAX_TRAIT_METHODS}; +#[allow(unused_imports)] +use clarity::vm::analysis::CheckErrorKind; +use clarity::vm::types::MAX_TYPE_DEPTH; +use clarity::vm::ClarityVersion; + +use crate::chainstate::tests::consensus::{ + clarity_versions_for_epoch, contract_deploy_consensus_test, ConsensusTest, ConsensusUtils, + SetupContract, TestBlock, EPOCHS_TO_TEST, +}; +use crate::core::BLOCK_LIMIT_MAINNET_21; +use crate::util_lib::boot::boot_code_test_addr; + +/// CheckErrorKind: [`CheckErrorKind::CostBalanceExceeded`] +/// Caused by: exceeding the static-read analysis budget during contract deployment. +/// The contract repeatedly performs static-dispatch `contract-call?` lookups against the boot +/// `.costs-3` contract, forcing the type checker to fetch the remote function signature enough +/// times to surpass the read-count limit in [`BLOCK_LIMIT_MAINNET_21`]. +/// Outcome: block rejected. +/// Note: Takes a couple of minutes to run! +#[ignore] +#[test] +fn static_check_error_cost_balance_exceeded() { + contract_deploy_consensus_test!( + contract_name: "cost-balance-exceeded", + contract_code: &{ + let boot_addr = boot_code_test_addr(); + let mut contract = String::from("(define-read-only (trigger)\n (begin\n"); + let call_count = BLOCK_LIMIT_MAINNET_21.read_count as usize + 1; + let call_line = format!( + "(contract-call? '{boot_addr}.costs-3 cost_analysis_type_check u0)\n", + ); + for _ in 0..call_count { + contract.push_str(&call_line); + } + contract.push_str("true))"); + contract + }, + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ValueTooLarge`] +/// Caused by: Value exceeds the maximum allowed size for type-checking +/// Outcome: block accepted. +#[test] +fn static_check_error_value_too_large() { + contract_deploy_consensus_test!( + contract_name: "value-too-large", + contract_code: "(as-max-len? 0x01 u1048577)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ValueOutOfBounds`] +/// Caused by: Value is outside the acceptable range for its type +/// Outcome: block accepted. +#[test] +fn static_check_error_value_out_of_bounds() { + contract_deploy_consensus_test!( + contract_name: "value-out-of-bounds", + contract_code: "(define-private (func (x (buff -12))) (len x)) + (func 0x00)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedName`] +/// Caused by: Expected a name (e.g., variable) but found an different expression. +/// Outcome: block accepted. +#[test] +fn static_check_error_expected_name() { + contract_deploy_consensus_test!( + contract_name: "expected-name", + contract_code: "(match (some 1) 2 (+ 1 1) (+ 3 4))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedResponseType`] +/// Caused by: Expected a response type but found a different type. +/// Outcome: block accepted. +#[test] +fn static_check_error_expected_response_type() { + contract_deploy_consensus_test!( + contract_name: "expected-response-type", + contract_code: "(unwrap-err! (some 2) 2)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::CouldNotDetermineResponseOkType`] +/// Caused by: `unwrap!` on literal `(err 3)` leaves the response `ok` type unknown. +/// Outcome: block accepted. +#[test] +fn static_check_error_could_not_determine_response_ok_type() { + contract_deploy_consensus_test!( + contract_name: "could-not-determine", + contract_code: "(unwrap! (err 3) 2)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::CouldNotDetermineResponseErrType`] +/// Caused by: `unwrap-err-panic` on `(ok 3)` gives no way to infer the response `err` type. +/// Outcome: block accepted. +#[test] +fn static_check_error_could_not_determine_response_err_type() { + contract_deploy_consensus_test!( + contract_name: "could-not-determine", + contract_code: "(unwrap-err-panic (ok 3))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::CouldNotDetermineMatchTypes`] +/// Caused by: matching a bare `none` provides no option type, leaving branch types ambiguous. +/// Outcome: block accepted. +#[test] +fn static_check_error_could_not_determine_match_types() { + contract_deploy_consensus_test!( + contract_name: "could-not-determine", + contract_code: "(match none inner-value (/ 1 0) (+ 1 8))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::MatchArmsMustMatch`] +/// Caused by: the `some` arm yields an int while the `none` arm yields a bool. +/// Outcome: block accepted. +#[test] +fn static_check_error_match_arms_must_match() { + contract_deploy_consensus_test!( + contract_name: "match-arms-must-match", + contract_code: "(match (some 1) inner-value (+ 1 inner-value) (> 1 28))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadMatchOptionSyntax`] +/// Caused by: option `match` expecting 4 arguments, got 3. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_match_option_syntax() { + contract_deploy_consensus_test!( + contract_name: "bad-match-option", + contract_code: "(match (some 1) inner-value (+ 1 inner-value))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadMatchResponseSyntax`] +/// Caused by: response `match` expecting 5 arguments, got 3. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_match_response_syntax() { + contract_deploy_consensus_test!( + contract_name: "bad-match-response", + contract_code: "(match (ok 1) inner-value (+ 1 inner-value))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::RequiresAtLeastArguments`] +/// Caused by: invoking `match` with no arguments. +/// Outcome: block accepted. +#[test] +fn static_check_error_requires_at_least_arguments() { + contract_deploy_consensus_test!( + contract_name: "requires-at-least", + contract_code: "(match)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::RequiresAtMostArguments`] +/// Caused by: `principal-construct?` is called with too many arguments. +/// Outcome: block accepted. +#[test] +fn static_check_error_requires_at_most_arguments() { + contract_deploy_consensus_test!( + contract_name: "requires-at-most", + contract_code: r#"(principal-construct? 0x22 0xfa6bf38ed557fe417333710d6033e9419391a320 "foo" "bar")"#, + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadMatchInput`] +/// Caused by: `match` input is the integer `1`, not an option or response. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_match_input() { + contract_deploy_consensus_test!( + contract_name: "bad-match-input", + contract_code: "(match 1 ok-val (/ ok-val 0) err-val (+ err-val 7))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedOptionalType`] +/// Caused by: `default-to` second argument `5` is not an optional value. +/// Outcome: block accepted. +#[test] +fn static_check_error_expected_optional_type() { + contract_deploy_consensus_test!( + contract_name: "expected-optional-type", + contract_code: "(default-to 3 5)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::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: " + (impl-trait .trait-contract.trait-1) + (define-public (get-1 (x (list 5 uint))) (ok u1))", + setup_contracts: &[setup_contract], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NameAlreadyUsed`] +/// Caused by: redefining constant `foo` a second time. +/// Outcome: block accepted. +#[test] +fn static_check_error_name_already_used() { + contract_deploy_consensus_test!( + contract_name: "name-already-used", + contract_code: " + (define-constant foo 10) + (define-constant foo 20)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ReturnTypesMustMatch`] +/// Caused by: `unwrap!` default returns `err 1` while the function returns `err false`, so response types diverge. +/// Outcome: block accepted. +#[test] +fn static_check_error_return_types_must_match() { + contract_deploy_consensus_test!( + contract_name: "return-types-must", + contract_code: " + (define-map tokens { id: int } { balance: int }) + (define-private (my-get-token-balance) + (let ((balance (unwrap! + (get balance (map-get? tokens (tuple (id 0)))) + (err 1)))) + (err false)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TypeError`] +/// Caused by: initializing `define-data-var cursor int` with the boolean `true`. +/// Outcome: block accepted. +#[test] +fn static_check_error_type_error() { + contract_deploy_consensus_test!( + contract_name: "type-error", + contract_code: "(define-data-var cursor int true)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::DefineVariableBadSignature`] +/// Caused by: `define-data-var` is provided only a name and value, missing the required type. +/// Outcome: block accepted. +#[test] +fn static_check_error_define_variable_bad_signature() { + contract_deploy_consensus_test!( + contract_name: "define-variable-bad", + contract_code: "(define-data-var cursor 0x00)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::InvalidTypeDescription`] +/// Caused by: `define-data-var` uses `0x00` where a valid type description is required. +/// Outcome: block accepted. +#[test] +fn static_check_error_invalid_type_description() { + contract_deploy_consensus_test!( + contract_name: "invalid-type-desc", + contract_code: "(define-data-var cursor 0x00 true)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TypeSignatureTooDeep`] +/// Caused by: parameter type nests `optional` wrappers deeper than [`MAX_TYPE_DEPTH`]. +/// Outcome: block accepted. +#[test] +fn static_check_error_type_signature_too_deep() { + contract_deploy_consensus_test!( + contract_name: "signature-too-deep", + contract_code: &{ + let depth: usize = MAX_TYPE_DEPTH as usize + 1; + let mut s = String::from("(define-public (f (x "); + for _ in 0..depth { + s.push_str("(optional "); + } + s.push_str("uint"); + for _ in 0..depth { + s.push_str(") "); + } + s.push_str(")) (ok x))"); + s + }, + ); +} + +/// CheckErrorKind: [`CheckErrorKind::SupertypeTooLarge`] +/// Caused by: combining tuples with `buff 600000` and `buff 10` forces a supertype beyond the size limit. +/// Outcome: block rejected. +#[test] +fn static_check_error_supertype_too_large() { + contract_deploy_consensus_test!( + contract_name: "supertype-too-large", + contract_code: " + (define-data-var big (buff 600000) 0x00) + (define-data-var small (buff 10) 0x00) + (define-public (trigger) + (let ((initial (list (tuple (a (var-get big)) (b (var-get small)))))) + (ok (append initial (tuple (a (var-get small)) (b (var-get big)))))))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ConstructedListTooLarge`] +/// Caused by: mapping `sha512` over a list capped at 65,535 elements constructs a list past [`MAX_VALUE_SIZE`]. +/// Outcome: block accepted. +#[test] +fn static_check_error_constructed_list_too_large() { + contract_deploy_consensus_test!( + contract_name: "constructed-list-large", + contract_code: " + (define-data-var ints (list 65535 int) (list 0)) + (define-public (trigger) + (let ((mapped (map sha512 (var-get ints)))) + (ok mapped) + ) + )", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UnknownTypeName`] +/// Caused by: `from-consensus-buff?` references an undefined type named `foo`. +/// Outcome: block accepted. +/// Note: during analysis, this error can only be triggered by `from-consensus-buff?` +/// which is only available in Clarity 2 and later. So Clarity 1 will not trigger +/// this error. +#[test] +fn static_check_error_unknown_type_name() { + contract_deploy_consensus_test!( + contract_name: "unknown-type-name", + contract_code: " + (define-public (trigger) + (ok (from-consensus-buff? foo 0x00)))", + exclude_clarity_versions: &[ClarityVersion::Clarity1], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UnionTypeError`] +/// Caused by: `map` applies subtraction to booleans. +/// Outcome: block accepted. +#[test] +fn static_check_error_union_type_error() { + contract_deploy_consensus_test!( + contract_name: "union-type-error", + contract_code: "(map - (list true false true false))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UndefinedVariable`] +/// Caused by: `x`, `y`, and `z` are referenced without being defined. +/// Outcome: block accepted. +#[test] +fn static_check_error_undefined_variable() { + contract_deploy_consensus_test!( + contract_name: "undefined-variable", + contract_code: "(+ x y z)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadMapTypeDefinition`] +/// Caused by: Invalid map type definition in a `(define-map ...)` expression. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_map_type_definition() { + contract_deploy_consensus_test!( + contract_name: "bad-map-type", + contract_code: "(define-map lists { name: int } contents)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::CouldNotDetermineType`] +/// Caused by: `(index-of (list) none)` supplies no concrete element types. +/// Outcome: block accepted. +#[test] +fn static_check_error_could_not_determine_type() { + contract_deploy_consensus_test!( + contract_name: "could-not-determine", + contract_code: "(index-of (list) none)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedSequence`] +/// Caused by: passing integer `3` as the sequence argument to `index-of` instead of a list or string. +/// Outcome: block accepted. +#[test] +fn static_check_error_expected_sequence() { + contract_deploy_consensus_test!( + contract_name: "expected-sequence", + contract_code: r#"(index-of 3 "a")"#, + ); +} + +/// CheckErrorKind: [`CheckErrorKind::CouldNotDetermineSerializationType`] +/// Caused by: `to-consensus-buff?` over a list of trait references lacks a serialization type. +/// Outcome: block accepted. +/// Note: during analysis, this error can only be triggered by `from-consensus-buff?` +/// which is only available in Clarity 2 and later. So Clarity 1 will not trigger +/// this error. +#[test] +fn static_check_error_could_not_determine_serialization_type() { + contract_deploy_consensus_test!( + contract_name: "serialization-type", + contract_code: " + (define-trait trait-a ((ping () (response bool bool)))) + (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], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::IllegalOrUnknownFunctionApplication`] +/// Caused by: calling `map` with `if` (a non-function) as its function argument. +/// Outcome: block accepted. +#[test] +fn static_check_error_illegal_or_unknown_function_application() { + contract_deploy_consensus_test!( + contract_name: "illegal-or-unknown", + contract_code: "(map if (list 1 2 3 4 5))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UnknownFunction`] +/// Caused by: invoking the undefined function `ynot`. +/// Outcome: block accepted. +#[test] +fn static_check_error_unknown_function() { + contract_deploy_consensus_test!( + contract_name: "unknown-function", + contract_code: "(ynot 1 2)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::IncorrectArgumentCount`] +/// Caused by: `len` receives two arguments even though it expects exactly one. +/// Outcome: block accepted. +#[test] +fn static_check_error_incorrect_argument_count() { + contract_deploy_consensus_test!( + contract_name: "incorrect-arg-count", + contract_code: "(len (list 1) (list 1))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadLetSyntax`] +/// Caused by: `let` is used without a binding list. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_let_syntax() { + contract_deploy_consensus_test!( + contract_name: "bad-let-syntax", + contract_code: "(let 1 2)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadSyntaxBinding`] +/// Caused by: `let` binding `((1))` is not a two-element list. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_syntax_binding() { + contract_deploy_consensus_test!( + contract_name: "bad-syntax-binding", + contract_code: "(let ((1)) (+ 1 2))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedOptionalOrResponseType`] +/// Caused by: expected an optional or response type, but got a value +/// Outcome: block accepted. +#[test] +fn static_check_error_expected_optional_or_response_type() { + contract_deploy_consensus_test!( + contract_name: "exp-opt-or-res", + contract_code: "(try! 3)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::DefineTraitBadSignature`] +/// Caused by: calling `define-trait` with a method signature that is not valid. +/// Outcome: block accepted. +#[test] +fn static_check_error_define_trait_bad_signature() { + contract_deploy_consensus_test!( + contract_name: "def-trait-bad-sign", + contract_code: "(define-trait trait-1 ((get-1 uint uint)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::DefineTraitDuplicateMethod`] +/// Caused by: trait definition contains duplicate method names +/// Outcome: block accepted. +/// Note: This error was added in Clarity 2. Clarity 1 will accept the contract. +#[test] +fn static_check_error_define_trait_duplicate_method() { + contract_deploy_consensus_test!( + contract_name: "def-trait-dup-method", + contract_code: " + (define-trait double-method ( + (foo (uint) (response uint uint)) + (foo (bool) (response bool bool)) + ))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UnexpectedTraitOrFieldReference`] +/// Caused by: unexpected use of trait reference or field +/// Outcome: block accepted. +#[test] +fn static_check_error_unexpected_trait_or_field_reference() { + contract_deploy_consensus_test!( + contract_name: "trait-or-field-ref", + contract_code: "(+ 1 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR.contract.field)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::IncompatibleTrait`] +/// Caused by: pass a trait to a trait parameter which is not compatible. +/// Outcome: block accepted. +/// Note: Added in Clarity 2. Clarity 1 will trigger a [`CheckErrorKind::TypeError`]. +#[test] +fn static_check_error_incompatible_trait() { + contract_deploy_consensus_test!( + contract_name: "incompatible-trait", + contract_code: " + (define-trait trait-1 ( + (get-1 (uint) (response uint uint)) + )) + (define-trait trait-2 ( + (get-2 (uint) (response uint uint)) + )) + (define-public (wrapped-get-2 (contract )) + (internal-get-2 contract)) + (define-public (internal-get-2 (contract )) + (contract-call? contract get-2 u1))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TraitTooManyMethods`] +/// Caused by: a trait has too many methods. +/// Outcome: block accepted. +#[test] +fn static_check_error_trait_too_many_methods() { + contract_deploy_consensus_test!( + contract_name: "too-many-methods", + contract_code: &format!( + "(define-trait trait-1 ({}))", + (0..(MAX_TRAIT_METHODS + 1)) + .map(|i| format!("(method-{i} (uint) (response uint uint))")) + .collect::>() + .join(" ") + ), + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TooManyFunctionParameters`] +/// Caused by: a function has too many parameters. +/// Outcome: block accepted. +#[test] +fn static_check_error_too_many_function_parameters() { + contract_deploy_consensus_test!( + contract_name: "too-many-params", + contract_code: &format!( + "(define-trait trait-1 ((method ({}) (response uint uint))))", + (0..(MAX_FUNCTION_PARAMETERS + 1)) + .map(|i| "uint".to_string()) + .collect::>() + .join(" ") + ), + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ReservedWord`] +/// Caused by: name is a reserved word +/// Outcome: block accepted. +/// Note: This error was added in Clarity 3. Clarity 1 and 2 +/// will trigger a [`CheckErrorKind::NameAlreadyUsed`]. +#[test] +fn static_check_error_reserved_word() { + contract_deploy_consensus_test!( + contract_name: "reserved-word", + contract_code: "(define-private (block-height) true)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchBlockInfoProperty`] +/// Caused by: referenced an unknown property of a burn block +/// Outcome: block accepted. +#[test] +fn static_check_error_no_such_block_info_property() { + contract_deploy_consensus_test!( + contract_name: "no-such-block-info", + contract_code: "(get-burn-block-info? none u1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchStacksBlockInfoProperty`] +/// Caused by: referenced an unknown property of a stacks block +/// Outcome: block accepted. +/// Note: This error was added in Clarity 3. Clarity 1, and 2 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_no_such_stacks_block_info_property() { + contract_deploy_consensus_test!( + contract_name: "no-such-stacks-info", + contract_code: "(get-stacks-block-info? none u1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::UncheckedIntermediaryResponses`] +/// Caused by: Intermediate `(ok ...)` expressions inside a `begin` block that are not unwrapped. +/// Outcome: block accepted. +#[test] +fn static_check_error_unchecked_intermediary_responses() { + contract_deploy_consensus_test!( + contract_name: "unchecked-resp", + contract_code: " + (define-public (trigger) + (begin + (ok true) + (ok true)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchFT`] +/// Caused by: calling `ft-get-balance` with a non-existent FT name. +/// Outcome: block accepted. +#[test] +fn static_check_error_no_such_ft() { + contract_deploy_consensus_test!( + contract_name: "no-such-ft", + contract_code: "(ft-get-balance stackoos tx-sender)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchNFT`] +/// Caused by: calling `nft-get-owner?` with a non-existent NFT name. +/// Outcome: block accepted. +#[test] +fn static_check_error_no_such_nft() { + contract_deploy_consensus_test!( + contract_name: "no-such-nft", + contract_code: r#"(nft-get-owner? stackoos "abc")"#, + ); +} + +/// CheckErrorKind: [`CheckErrorKind::DefineNFTBadSignature`] +/// Caused by: malformed signature in a `(define-non-fungible-token ...)` expression +/// Outcome: block accepted. +#[test] +fn static_check_error_define_nft_bad_signature() { + contract_deploy_consensus_test!( + contract_name: "nft-bad-signature", + contract_code: "(define-non-fungible-token stackaroos integer)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadTokenName`] +/// Caused by: calling `ft-get-balance` with a non-valid token name. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_token_name() { + contract_deploy_consensus_test!( + contract_name: "bad-token-name", + contract_code: "(ft-get-balance u1234 tx-sender)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::EmptyTuplesNotAllowed`] +/// Caused by: calling `set-cursor` with an empty tuple. +/// Outcome: block accepted. +#[test] +fn static_check_error_empty_tuples_not_allowed() { + contract_deploy_consensus_test!( + contract_name: "empty-tuples-not", + contract_code: " + (define-private (set-cursor (value (tuple))) + value)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchDataVariable`] +/// Caused by: calling var-get with a non-existent variable. +/// Outcome: block accepted. +#[test] +fn static_check_error_no_such_data_variable() { + contract_deploy_consensus_test!( + contract_name: "no-such-data-var", + contract_code: " + (define-private (get-cursor) + (unwrap! (var-get cursor) 0))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NonFunctionApplication`] +/// Caused by: attempt to apply a non-function value as a function. +/// Outcome: block accepted. +#[test] +fn static_check_error_non_function_application() { + contract_deploy_consensus_test!( + contract_name: "non-function-appl", + contract_code: "((lambda (x y) 1) 2 1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedListApplication`] +/// Caused by: calling append with lhs that is not a list. +/// Outcome: block accepted. +#[test] +fn static_check_error_expected_list_application() { + contract_deploy_consensus_test!( + contract_name: "expected-list-appl", + contract_code: "(append 2 3)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchContract`] +/// Caused by: calling contract-call? with a non-existent contract name. +/// Outcome: block accepted. +#[test] +fn static_check_error_no_such_contract() { + contract_deploy_consensus_test!( + contract_name: "no-such-contract", + contract_code: "(contract-call? 'S1G2081040G2081040G2081040G208105NK8PE5.contract-name test! u1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ContractCallExpectName`] +/// Caused by: calling contract-call? without a contract function name. +/// Outcome: block accepted. +#[test] +fn static_check_error_contract_call_expect_name() { + contract_deploy_consensus_test!( + contract_name: "ccall-expect-name", + contract_code: "(contract-call? 'S1G2081040G2081040G2081040G208105NK8PE5.contract-name u1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedCallableType`] +/// Caused by: passing a non-callable constant as the contract principal in `contract-call?`. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 2. Clarity 1 will trigger a [`CheckErrorKind::TraitReferenceUnknown`] +#[test] +fn static_check_error_expected_callable_type() { + contract_deploy_consensus_test!( + contract_name: "exp-callable-type", + contract_code: " + (define-constant bad-contract u1) + (contract-call? bad-contract call-me)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchPublicFunction`] +/// Caused by: calling a non-existent public or read-only function on a contract literal. +/// Outcome: block accepted. +#[test] +fn static_check_error_no_such_public_function() { + contract_deploy_consensus_test!( + contract_name: "no-such-pub-func-lit", + // using the pox-4 contract as we know it exists! + contract_code: &format!("(contract-call? '{}.pox-4 missing-func)", boot_code_test_addr()), + ); +} + +/// CheckErrorKind: [`CheckErrorKind::DefaultTypesMustMatch`] +/// Caused by: calling `default-to` with a default value that does not match the expected type. +/// Outcome: block accepted. +#[test] +fn static_check_error_default_types_must_match() { + contract_deploy_consensus_test!( + contract_name: "default-types-must", + contract_code: " + (define-map tokens { id: int } { balance: int }) + (default-to false (get balance (map-get? tokens (tuple (id 0)))))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::IfArmsMustMatch`] +/// Caused by: calling `if` with arms that do not match the same type. +/// Outcome: block accepted. +#[test] +fn static_check_error_if_arms_must_match() { + contract_deploy_consensus_test!( + contract_name: "if-arms-must-match", + contract_code: "(if true true 1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedTuple`] +/// Caused by: `(get ...)` is given `(some 1)` instead of a tuple value. +/// Outcome: block accepted. +#[test] +fn static_check_error_expected_tuple() { + contract_deploy_consensus_test!( + contract_name: "expected-tuple", + contract_code: "(get field-0 (some 1))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchTupleField`] +/// Caused by: tuple argument only contains `name`, so requesting `value` fails. +/// Outcome: block accepted. +#[test] +fn static_check_error_no_such_tuple_field() { + contract_deploy_consensus_test!( + contract_name: "no-such-tuple-f", + contract_code: "(get value (tuple (name 1)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchMap`] +/// Caused by: `map-get?` refers to map `non-existent`, which is never defined. +/// Outcome: block accepted. +#[test] +fn static_check_error_no_such_map() { + contract_deploy_consensus_test!( + contract_name: "no-such-map", + contract_code: "(map-get? non-existent (tuple (name 1)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadFunctionName`] +/// Caused by: defining a function whose signature does not start with an atom name. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_function_name() { + contract_deploy_consensus_test!( + contract_name: "bad-func-name", + contract_code: "(define-private (u1) u0)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::DefineFunctionBadSignature`] +/// Caused by: defining a function with an empty signature list. +/// Outcome: block accepted. +#[test] +fn static_check_error_define_function_bad_signature() { + contract_deploy_consensus_test!( + contract_name: "def-func-bad-sign", + contract_code: "(define-private () 1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadTupleFieldName`] +/// Caused by: using `(get ...)` with a tuple field argument that is not an atom. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_tuple_field_name() { + contract_deploy_consensus_test!( + contract_name: "bad-tuple-field-name", + contract_code: "(get u1 (tuple (foo u0)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadMapName`] +/// Caused by: passing a literal instead of a map identifier to `map-get?`. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_map_name() { + contract_deploy_consensus_test!( + contract_name: "bad-map-name", + contract_code: "(map-get? u1 (tuple (id u0)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::GetBlockInfoExpectPropertyName`] +/// Caused by: calling `get-block-info` with a non-atom property argument. +/// Outcome: block accepted. +/// Note: Only Clarity 1 and 2 will trigger this error. Clarity 3 and 4 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +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], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::GetBurnBlockInfoExpectPropertyName`] +/// Caused by: calling `get-burn-block-info` with a non-atom property argument. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 2. Clarity 1 will trigger +/// a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_get_burn_block_info_expect_property_name() { + contract_deploy_consensus_test!( + contract_name: "burn-exp-prop-name", + contract_code: "(get-burn-block-info? u1 u0)", + exclude_clarity_versions: &[ClarityVersion::Clarity1], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::GetStacksBlockInfoExpectPropertyName`] +/// Caused by: calling `get-stacks-block-info` with a non-atom property argument. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 3. Clarity 1 and 2 will trigger +/// a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_get_stacks_block_info_expect_property_name() { + contract_deploy_consensus_test!( + contract_name: "stacks-exp-prop-name", + contract_code: "(get-stacks-block-info? u1 u0)", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::GetTenureInfoExpectPropertyName`] +/// Caused by: calling `get-tenure-info` with a non-atom property argument. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 3. Clarity 1 and 2 will trigger +/// a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_get_tenure_info_expect_property_name() { + contract_deploy_consensus_test!( + contract_name: "tenure-exp-prop-name", + contract_code: "(get-tenure-info? u1 u0)", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::NoSuchTenureInfoProperty`] +/// Caused by: referenced an unknown property of a tenure +/// Outcome: block accepted. +/// Note: This error was added in Clarity 3. Clarity 1, and 2 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_no_such_tenure_info_property() { + contract_deploy_consensus_test!( + contract_name: "no-such-tenure-info", + contract_code: "(get-tenure-info? none u1)", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TraitReferenceUnknown`] +/// Caused by: referenced trait is unknown +/// Outcome: block accepted. +#[test] +fn static_check_error_trait_reference_unknown() { + contract_deploy_consensus_test!( + contract_name: "trait-ref-unknown", + contract_code: "(+ 1 )", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ContractOfExpectsTrait`] +/// Caused by: calling `contract-of` with a non-trait argument. +/// Outcome: block accepted. +#[test] +fn static_check_error_contract_of_expects_trait() { + contract_deploy_consensus_test!( + contract_name: "expect-trait", + contract_code: "(contract-of u1)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TraitMethodUnknown`] +/// Caused by: defining a method that is not declared in the trait +/// Outcome: block accepted. +#[test] +fn static_check_error_trait_method_unknown() { + contract_deploy_consensus_test!( + contract_name: "trait-method-unknown", + contract_code: " + (define-trait trait-1 ( + (get-1 (uint) (response uint uint)))) + (define-public (wrapped-get-1 (contract )) + (contract-call? contract get-2 u0))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::WriteAttemptedInReadOnly`] +/// Caused by: read-only function `silly` invoking `map-delete`, which performs a write. +/// Outcome: block accepted. +#[test] +fn static_check_error_write_attempted_in_read_only() { + contract_deploy_consensus_test!( + contract_name: "write-attempted-in-ro", + contract_code: " + (define-read-only (silly) + (map-delete map-name (tuple (value 1)))) + (silly)", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::AtBlockClosureMustBeReadOnly`] +/// Caused by: `at-block` closure must be read-only but contains write operations. +/// Outcome: block accepted. +#[test] +fn static_check_error_at_block_closure_must_be_read_only() { + contract_deploy_consensus_test!( + contract_name: "closure-must-be-ro", + contract_code: " + (define-data-var foo int 1) + (define-private (foo-bar) + (at-block (sha256 0) + (var-set foo 0)))", + ); +} + +/// CheckErrorKind: [`CheckErrorKind::AllowanceExprNotAllowed`] +/// Caused by: using an allowance expression outside of `restrict-assets?` or `as-contract?`. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 4. Clarity 1, 2, and 3 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_allowance_expr_not_allowed() { + contract_deploy_consensus_test!( + contract_name: "allow-expr-not-allo", + contract_code: "(with-stx u1)", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedListOfAllowances`] +/// Caused by: post-condition expects a list of asset allowances but received invalid input. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 4. Clarity 1, 2, and 3 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_expected_list_of_allowances() { + contract_deploy_consensus_test!( + contract_name: "exp-list-of-allowances", + contract_code: "(restrict-assets? tx-sender u1 true)", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::ExpectedAllowanceExpr`] +/// Caused by: allowance list contains a non-allowance expression. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 4. Clarity 1, 2, and 3 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_expected_allowance_expr() { + contract_deploy_consensus_test!( + contract_name: "exp-allowa-expr", + contract_code: "(restrict-assets? tx-sender ((not true)) true)", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::WithAllAllowanceNotAllowed`] +/// Caused by: `restrict-assets?` allowance list contains `with-all-assets-unsafe`, which is forbidden. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 4. Clarity 1, 2, and 3 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_with_all_allowance_not_allowed() { + contract_deploy_consensus_test!( + contract_name: "all-allow-not-allowed", + contract_code: "(restrict-assets? tx-sender ((with-all-assets-unsafe)) true)", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::WithAllAllowanceNotAlone`] +/// Caused by: combining `with-all-assets-unsafe` with another allowance inside `as-contract?`. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 4. Clarity 1, 2, and 3 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_with_all_allowance_not_alone() { + contract_deploy_consensus_test!( + contract_name: "all-allow-not-alone", + contract_code: "(as-contract? ((with-all-assets-unsafe) (with-stx u1000)) true)", + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::WithNftExpectedListOfIdentifiers`] +/// Caused by: the third argument to `with-nft` is not a list of identifiers. +/// Outcome: block accepted. +/// Note: This error was added in Clarity 4. Clarity 1, 2, and 3 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_with_nft_expected_list_of_identifiers() { + contract_deploy_consensus_test!( + contract_name: "with-nft-exp-ident", + contract_code: r#"(restrict-assets? tx-sender ((with-nft tx-sender "token-name" tx-sender)) true)"#, + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::MaxIdentifierLengthExceeded`] +/// Caused by: `with-nft` lists 130 identifiers, surpassing [`MAX_NFT_IDENTIFIERS`] (128). +/// Outcome: block accepted. +/// Note: This error was added in Clarity 4. Clarity 1, 2, and 3 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_max_identifier_length_exceeded() { + contract_deploy_consensus_test!( + contract_name: "max-ident-len-excd", + contract_code: &format!( + "(restrict-assets? tx-sender ((with-nft .token \"token-name\" (list {}))) true)", + std::iter::repeat_n("u1", 130) + .collect::>() + .join(" ") + ), + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::TooManyAllowances`] +/// Caused by: allowance list supplies 130 entries, exceeding [`MAX_ALLOWANCES`] (128). +/// Outcome: block accepted. +/// Note: This error was added in Clarity 4. Clarity 1, 2, and 3 +/// will trigger a [`CheckErrorKind::UnknownFunction`]. +#[test] +fn static_check_error_too_many_allowances() { + contract_deploy_consensus_test!( + contract_name: "too-many-allowances", + contract_code: &format!( + "(restrict-assets? tx-sender ({} ) true)", + std::iter::repeat_n("(with-stx u1)", 130) + .collect::>() + .join(" ") + ), + exclude_clarity_versions: &[ClarityVersion::Clarity1, ClarityVersion::Clarity2, ClarityVersion::Clarity3], + ); +} + +/// CheckErrorKind: [`CheckErrorKind::BadTupleConstruction`] +/// Caused by: tuple literal repeats the `name` field twice. +/// Outcome: block accepted. +#[test] +fn static_check_error_bad_tuple_construction() { + contract_deploy_consensus_test!( + contract_name: "bad-tuple-constr", + contract_code: "(tuple (name 1) (name 2))", + ); +} + +/// Error: [`Error::InvalidStacksTransaction("Duplicate contract")`] +/// Caused by: trying to deploy a contract that already exists. +/// Outcome: block rejected. +#[test] +fn error_invalid_stacks_transaction_duplicate_contract() { + let contract_code = "(define-constant buff-0 0x00)"; + let mut nonce = 0; + + let tx_fee = (contract_code.len() * 100) as u64; + let mut epochs_blocks: HashMap> = HashMap::new(); + let contract_name = "contract-name"; + let deploy_tx = ConsensusUtils::new_deploy_tx(nonce, contract_name, contract_code, None); + nonce += 1; + epochs_blocks + .entry(*EPOCHS_TO_TEST.first().unwrap()) + .or_insert(vec![]) + .push(TestBlock { + transactions: vec![deploy_tx], + }); + + for epoch in EPOCHS_TO_TEST { + for version in clarity_versions_for_epoch(*epoch) { + let deploy_tx = + ConsensusUtils::new_deploy_tx(nonce, contract_name, contract_code, Some(*version)); + + let entry = epochs_blocks + .entry(*epoch) + .or_insert(vec![]) + .push(TestBlock { + transactions: vec![deploy_tx], + }); + } + } + + let result = ConsensusTest::new(function_name!(), vec![], epochs_blocks).run(); + + insta::assert_ron_snapshot!(result); +} diff --git a/stackslib/src/clarity_vm/clarity.rs b/stackslib/src/clarity_vm/clarity.rs index 41c60b5fd66..b563bbbc959 100644 --- a/stackslib/src/clarity_vm/clarity.rs +++ b/stackslib/src/clarity_vm/clarity.rs @@ -20,14 +20,14 @@ use std::thread; use clarity::consts::CHAIN_ID_TESTNET; use clarity::vm::analysis::AnalysisDatabase; use clarity::vm::clarity::TransactionConnection; -pub use clarity::vm::clarity::{ClarityConnection, Error}; +pub use clarity::vm::clarity::{ClarityConnection, ClarityError}; use clarity::vm::contexts::{AssetMap, OwnedEnvironment}; use clarity::vm::costs::{CostTracker, ExecutionCost, LimitedCostTracker}; use clarity::vm::database::{ BurnStateDB, ClarityBackingStore, ClarityDatabase, HeadersDB, RollbackWrapper, RollbackWrapperPersistedLog, STXBalance, NULL_BURN_STATE_DB, NULL_HEADER_DB, }; -use clarity::vm::errors::{Error as InterpreterError, InterpreterResult}; +use clarity::vm::errors::VmExecutionError; use clarity::vm::events::{STXEventType, STXMintEventData}; use clarity::vm::representations::SymbolicExpression; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, Value}; @@ -186,7 +186,7 @@ pub trait ClarityMarfStoreTransaction { /// It can later be deleted via `drop_metadata_for()` if given the same taret. /// Returns Ok(()) on success /// Returns Err(..) on error - fn commit_metadata_for_trie(&mut self, target: &StacksBlockId) -> InterpreterResult<()>; + fn commit_metadata_for_trie(&mut self, target: &StacksBlockId) -> Result<(), VmExecutionError>; /// Drop metadata for a particular block trie that was stored previously via `commit_metadata_to()`. /// This function is idempotent. @@ -194,7 +194,7 @@ pub trait ClarityMarfStoreTransaction { /// Returns Ok(()) if the metadata for the trie identified by `target` was dropped. /// It will be possible to insert it again afterwards. /// Returns Err(..) if the metadata was not successfully dropped. - fn drop_metadata_for_trie(&mut self, target: &StacksBlockId) -> InterpreterResult<()>; + fn drop_metadata_for_trie(&mut self, target: &StacksBlockId) -> Result<(), VmExecutionError>; /// Compute the ID of the trie being built. /// In Stacks, this will only be called once all key/value pairs are inserted (and will only be @@ -211,7 +211,7 @@ pub trait ClarityMarfStoreTransaction { /// Returns Ok(()) on successful deletion of the data /// Returns Err(..) if the deletion failed (this usually isn't recoverable, but recovery is up /// to the caller) - fn drop_unconfirmed(self) -> InterpreterResult<()>; + fn drop_unconfirmed(self) -> Result<(), VmExecutionError>; /// Store the processed block's trie that this transaction was creating. /// The trie's ID must be `target`, so that subsequent tries can be built on it (and so that @@ -220,7 +220,7 @@ pub trait ClarityMarfStoreTransaction { /// /// Returns Ok(()) if the block trie was successfully persisted. /// Returns Err(..) if there was an error in trying to persist this block trie. - fn commit_to_processed_block(self, target: &StacksBlockId) -> InterpreterResult<()>; + fn commit_to_processed_block(self, target: &StacksBlockId) -> Result<(), VmExecutionError>; /// Store a mined block's trie that this transaction was creating. /// This function is distinct from `commit_to_processed_block()` in that the stored block will @@ -229,7 +229,7 @@ pub trait ClarityMarfStoreTransaction { /// /// Returns Ok(()) if the block trie was successfully persisted. /// Returns Err(..) if there was an error trying to persist this MARF trie. - fn commit_to_mined_block(self, target: &StacksBlockId) -> InterpreterResult<()>; + fn commit_to_mined_block(self, target: &StacksBlockId) -> Result<(), VmExecutionError>; /// Persist the unconfirmed state trie so that other parts of the Stacks node can read from it /// (such as to handle pending transactions or process RPC requests on it). @@ -273,13 +273,15 @@ pub struct ClarityReadOnlyConnection<'a> { epoch: StacksEpochId, } -impl From for Error { +impl From for ClarityError { fn from(e: ChainstateError) -> Self { match e { - ChainstateError::InvalidStacksTransaction(msg, _) => Error::BadTransaction(msg), - ChainstateError::CostOverflowError(_, after, budget) => Error::CostError(after, budget), + ChainstateError::InvalidStacksTransaction(msg, _) => ClarityError::BadTransaction(msg), + ChainstateError::CostOverflowError(_, after, budget) => { + ClarityError::CostError(after, budget) + } ChainstateError::ClarityError(x) => x, - x => Error::BadTransaction(format!("{:?}", &x)), + x => ClarityError::BadTransaction(x.to_string()), } } } @@ -357,7 +359,7 @@ impl ClarityBlockConnection<'_, '_> { pub fn get_clarity_db_epoch_version( &mut self, burn_state_db: &dyn BurnStateDB, - ) -> Result { + ) -> Result { let mut db = self.datastore.as_clarity_db(self.header_db, burn_state_db); // NOTE: the begin/roll_back shouldn't be necessary with how this gets used in practice, // but is put here defensively. @@ -658,7 +660,7 @@ impl ClarityInstance { conn } - pub fn drop_unconfirmed_state(&mut self, block: &StacksBlockId) -> Result<(), Error> { + pub fn drop_unconfirmed_state(&mut self, block: &StacksBlockId) -> Result<(), ClarityError> { let datastore = self.datastore.begin_unconfirmed(block); datastore.drop_unconfirmed()?; Ok(()) @@ -758,7 +760,7 @@ impl ClarityInstance { at_block: &StacksBlockId, header_db: &'a dyn HeadersDB, burn_state_db: &'a dyn BurnStateDB, - ) -> Result, Error> { + ) -> Result, ClarityError> { let mut datastore = self.datastore.begin_read_only_checked(Some(at_block))?; let epoch = { let mut db = datastore.as_clarity_db(header_db, burn_state_db); @@ -790,7 +792,7 @@ impl ClarityInstance { burn_state_db: &dyn BurnStateDB, contract: &QualifiedContractIdentifier, program: &str, - ) -> Result { + ) -> Result { let mut read_only_conn = self.datastore.begin_read_only(Some(at_block)); let mut clarity_db = read_only_conn.as_clarity_db(header_db, burn_state_db); let epoch_id = { @@ -803,7 +805,7 @@ impl ClarityInstance { let mut env = OwnedEnvironment::new_free(self.mainnet, self.chain_id, clarity_db, epoch_id); env.eval_read_only(contract, program) .map(|(x, _, _)| x) - .map_err(Error::from) + .map_err(ClarityError::from) } pub fn destroy(self) -> MarfedKV { @@ -948,7 +950,10 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { /// before this saves, it updates the metadata headers in /// the sidestore so that they don't get stepped on after /// a miner re-executes a constructed block. - pub fn commit_mined_block(self, bhh: &StacksBlockId) -> Result { + pub fn commit_mined_block( + self, + bhh: &StacksBlockId, + ) -> Result { debug!("Commit mined Clarity datastore to {}", bhh); self.datastore.commit_to_mined_block(bhh)?; @@ -968,7 +973,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { } /// Get the boot code account - fn get_boot_code_account(&mut self) -> Result { + fn get_boot_code_account(&mut self) -> Result { let boot_code_address = boot_code_addr(self.mainnet); let boot_code_nonce = self.with_clarity_db_readonly(|db| { db.get_account_nonce(&boot_code_address.clone().into()) @@ -978,7 +983,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { Ok(boot_code_account) } - pub fn initialize_epoch_2_05(&mut self) -> Result { + pub fn initialize_epoch_2_05(&mut self) -> Result { // 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| { @@ -1061,7 +1066,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_2_1(&mut self) -> Result, Error> { + pub fn initialize_epoch_2_1(&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| { @@ -1247,7 +1252,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_2_2(&mut self) -> Result, Error> { + pub fn initialize_epoch_2_2(&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| { @@ -1274,7 +1279,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_2_3(&mut self) -> Result, Error> { + pub fn initialize_epoch_2_3(&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| { @@ -1303,7 +1308,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_2_4(&mut self) -> Result, Error> { + pub fn initialize_epoch_2_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| { @@ -1433,7 +1438,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_2_5(&mut self) -> Result, Error> { + pub fn initialize_epoch_2_5(&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| { @@ -1672,7 +1677,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_3_0(&mut self) -> Result, Error> { + pub fn initialize_epoch_3_0(&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| { @@ -1698,7 +1703,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_3_1(&mut self) -> Result, Error> { + pub fn initialize_epoch_3_1(&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| { @@ -1724,7 +1729,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_3_2(&mut self) -> Result, Error> { + pub fn initialize_epoch_3_2(&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| { @@ -1829,7 +1834,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { }) } - pub fn initialize_epoch_3_3(&mut self) -> Result, Error> { + pub fn initialize_epoch_3_3(&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| { @@ -1913,7 +1918,7 @@ impl<'a, 'b> ClarityBlockConnection<'a, 'b> { } info!("Epoch 3.3 initialized"); - (old_cost_tracker, Ok(vec![])) + (old_cost_tracker, Ok(vec![costs_4_initialization_receipt])) }) } @@ -2049,7 +2054,7 @@ impl TransactionConnection for ClarityTransactionConnection<'_, '_> { where A: FnOnce(&AssetMap, &mut ClarityDatabase) -> Option, F: FnOnce(&mut OwnedEnvironment) -> Result<(R, AssetMap, Vec), E>, - E: From, + E: From, { using!(self.log, "log", |log| { using!(self.cost_track, "cost tracker", |cost_track| { @@ -2120,9 +2125,9 @@ impl TransactionConnection for ClarityTransactionConnection<'_, '_> { impl ClarityTransactionConnection<'_, '_> { /// Do something to the underlying DB that involves writing. - pub fn with_clarity_db(&mut self, to_do: F) -> Result + pub fn with_clarity_db(&mut self, to_do: F) -> Result where - F: FnOnce(&mut ClarityDatabase) -> Result, + F: FnOnce(&mut ClarityDatabase) -> Result, { using!(self.log, "log", |log| { let rollback_wrapper = RollbackWrapper::from_persisted_log(self.store, log); @@ -2163,7 +2168,7 @@ impl ClarityTransactionConnection<'_, '_> { sender: &PrincipalData, mblock_header_1: &StacksMicroblockHeader, mblock_header_2: &StacksMicroblockHeader, - ) -> Result { + ) -> Result { self.with_abort_callback( |vm_env| { vm_env @@ -2176,7 +2181,7 @@ impl ClarityTransactionConnection<'_, '_> { ) }) }) - .map_err(Error::from) + .map_err(ClarityError::from) }, |_, _| None, ) @@ -2189,7 +2194,7 @@ impl ClarityTransactionConnection<'_, '_> { /// Commit the changes from the edit log. /// panics if there is more than one open savepoint - pub fn commit(mut self) -> Result<(), Error> { + pub fn commit(mut self) -> Result<(), ClarityError> { let log = self .log .take() @@ -2201,7 +2206,7 @@ impl ClarityTransactionConnection<'_, '_> { rollback_wrapper.depth() ); } - rollback_wrapper.commit().map_err(InterpreterError::from)?; + rollback_wrapper.commit().map_err(VmExecutionError::from)?; // now we can reset the memory usage for the edit-log self.cost_track .as_mut() @@ -2225,7 +2230,7 @@ impl ClarityTransactionConnection<'_, '_> { contract: &QualifiedContractIdentifier, method: &str, args: &[SymbolicExpression], - ) -> Result { + ) -> Result { let (result, _, _, _) = self.with_abort_callback( |vm_env| { vm_env @@ -2236,7 +2241,7 @@ impl ClarityTransactionConnection<'_, '_> { method, args, ) - .map_err(Error::from) + .map_err(ClarityError::from) }, |_, _| Some("read-only".to_string()), )?; @@ -2245,9 +2250,9 @@ impl ClarityTransactionConnection<'_, '_> { /// Evaluate a raw Clarity snippit #[cfg(test)] - pub fn clarity_eval_raw(&mut self, code: &str) -> Result { + pub fn clarity_eval_raw(&mut self, code: &str) -> Result { let (result, _, _, _) = self.with_abort_callback( - |vm_env| vm_env.eval_raw(code).map_err(Error::from), + |vm_env| vm_env.eval_raw(code).map_err(ClarityError::from), |_, _| None, )?; Ok(result) @@ -2258,9 +2263,13 @@ impl ClarityTransactionConnection<'_, '_> { &mut self, contract: &QualifiedContractIdentifier, code: &str, - ) -> Result { + ) -> Result { let (result, _, _, _) = self.with_abort_callback( - |vm_env| vm_env.eval_read_only(contract, code).map_err(Error::from), + |vm_env| { + vm_env + .eval_read_only(contract, code) + .map_err(ClarityError::from) + }, |_, _| None, )?; Ok(result) @@ -2273,7 +2282,7 @@ mod tests { use std::path::PathBuf; use clarity::types::chainstate::{BurnchainHeaderHash, SortitionId, StacksAddress}; - use clarity::vm::analysis::errors::CheckErrors; + use clarity::vm::analysis::errors::CheckErrorKind; use clarity::vm::database::{ClarityBackingStore, STXBalance, SqliteConnection}; use clarity::vm::test_util::{TEST_BURN_STATE_DB, TEST_HEADER_DB}; use clarity::vm::types::{StandardPrincipalData, TupleData, Value}; @@ -2675,7 +2684,7 @@ mod tests { // should not be in the marf. assert_eq!( conn.get_contract_hash(&contract_identifier).unwrap_err(), - CheckErrors::NoSuchContract(contract_identifier.to_string()).into() + CheckErrorKind::NoSuchContract(contract_identifier.to_string()).into() ); let sql = conn.get_side_store(); // sqlite only have entries @@ -2821,7 +2830,7 @@ mod tests { // should not be in the marf. assert_eq!( conn.get_contract_hash(&contract_identifier).unwrap_err(), - CheckErrors::NoSuchContract(contract_identifier.to_string()).into() + CheckErrorKind::NoSuchContract(contract_identifier.to_string()).into() ); let sql = conn.get_side_store(); @@ -2932,7 +2941,7 @@ mod tests { ) }) .unwrap_err(); - let result_value = if let Error::AbortedByCallback { output, .. } = e { + let result_value = if let ClarityError::AbortedByCallback { output, .. } = e { output.unwrap() } else { panic!("Expects a AbortedByCallback error") @@ -3283,7 +3292,7 @@ mod tests { )) .unwrap_err() { - Error::CostError(total, limit) => { + ClarityError::CostError(total, limit) => { eprintln!("{}, {}", total, limit); limit.runtime == 100 && total.runtime > 100 } diff --git a/stackslib/src/clarity_vm/database/ephemeral.rs b/stackslib/src/clarity_vm/database/ephemeral.rs index eb6ac7ce53b..448afeb7ab2 100644 --- a/stackslib/src/clarity_vm/database/ephemeral.rs +++ b/stackslib/src/clarity_vm/database/ephemeral.rs @@ -21,7 +21,7 @@ use clarity::vm::database::sqlite::{ sqlite_insert_metadata, }; use clarity::vm::database::{ClarityBackingStore, SpecialCaseHandler, SqliteConnection}; -use clarity::vm::errors::{InterpreterError, InterpreterResult, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError, VmInternalError}; use clarity::vm::types::QualifiedContractIdentifier; use rusqlite; use rusqlite::Connection; @@ -67,8 +67,8 @@ impl ClarityMarfStoreTransaction for EphemeralMarfStore<'_> { /// disappear when this instance is dropped /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn commit_metadata_for_trie(&mut self, target: &StacksBlockId) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn commit_metadata_for_trie(&mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { if let Some(tip) = self.ephemeral_marf.get_open_chain_tip() { self.teardown_views(); let res = @@ -85,8 +85,8 @@ impl ClarityMarfStoreTransaction for EphemeralMarfStore<'_> { /// unless the RAM-only sqlite DB is experiencing problems (which is probably not recoverable). /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn drop_metadata_for_trie(&mut self, target: &StacksBlockId) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn drop_metadata_for_trie(&mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { self.teardown_views(); let res = SqliteConnection::drop_metadata(self.ephemeral_marf.sqlite_tx(), target); self.setup_views(); @@ -111,8 +111,8 @@ impl ClarityMarfStoreTransaction for EphemeralMarfStore<'_> { /// transaction, so no disk I/O will be performed. /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn drop_unconfirmed(mut self) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn drop_unconfirmed(mut self) -> Result<(), VmExecutionError> { if let Some(tip) = self.ephemeral_marf.get_open_chain_tip().cloned() { debug!("Drop unconfirmed MARF trie {}", tip); self.drop_metadata_for_trie(&tip)?; @@ -127,13 +127,13 @@ impl ClarityMarfStoreTransaction for EphemeralMarfStore<'_> { /// motions just in case any errors would be reported. /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn commit_to_processed_block(mut self, target: &StacksBlockId) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn commit_to_processed_block(mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { if self.ephemeral_marf.get_open_chain_tip().is_some() { self.commit_metadata_for_trie(target)?; let _ = self.ephemeral_marf.commit_to(target).map_err(|e| { error!("Failed to commit to ephemeral MARF block {target}: {e:?}",); - InterpreterError::Expect("Failed to commit to MARF block".into()) + VmInternalError::Expect("Failed to commit to MARF block".into()) })?; } Ok(()) @@ -145,8 +145,8 @@ impl ClarityMarfStoreTransaction for EphemeralMarfStore<'_> { /// motions just in case any errors would be reported. /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn commit_to_mined_block(mut self, target: &StacksBlockId) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn commit_to_mined_block(mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { if let Some(tip) = self.ephemeral_marf.get_open_chain_tip().cloned() { // rollback the side_store // the side_store shouldn't commit data for blocks that won't be @@ -156,7 +156,7 @@ impl ClarityMarfStoreTransaction for EphemeralMarfStore<'_> { self.drop_metadata_for_trie(&tip)?; let _ = self.ephemeral_marf.commit_mined(target).map_err(|e| { error!("Failed to commit to mined MARF block {target}: {e:?}",); - InterpreterError::Expect("Failed to commit to MARF block".into()) + VmInternalError::Expect("Failed to commit to MARF block".into()) })?; } Ok(()) @@ -246,11 +246,11 @@ impl<'a> EphemeralMarfStore<'a> { } /// Test to see if a given tip is in the ephemeral MARF - fn is_ephemeral_tip(&mut self, tip: &StacksBlockId) -> Result { + fn is_ephemeral_tip(&mut self, tip: &StacksBlockId) -> Result { match self.ephemeral_marf.get_root_hash_at(tip) { Ok(_) => Ok(true), Err(Error::NotFoundError) => Ok(false), - Err(e) => Err(InterpreterError::MarfFailure(e.to_string())), + Err(e) => Err(VmInternalError::MarfFailure(e.to_string())), } } @@ -313,15 +313,15 @@ impl<'a> EphemeralMarfStore<'a> { } } - /// Helper function to cast a Result, Error> into InterpreterResult> - fn handle_marf_result(res: Result, Error>) -> InterpreterResult> { + /// Helper function to cast a Result, Error> into Result, VmExecutionError> + fn handle_marf_result(res: Result, Error>) -> Result, VmExecutionError> { match res { Ok(result_opt) => Ok(result_opt), Err(Error::NotFoundError) => { trace!("Ephemeral MarfedKV get not found",); Ok(None) } - Err(e) => Err(InterpreterError::Expect(format!( + Err(e) => Err(VmInternalError::Expect(format!( "ERROR: Unexpected MARF failure: {e:?}" )) .into()), @@ -334,20 +334,20 @@ impl<'a> EphemeralMarfStore<'a> { /// /// Returns Ok(Some(V)) if the key was mapped in eiher MARF /// Returns Ok(None) if the key was not mapped in either MARF - /// Returns Err(InterpreterError(..)) on failure. + /// Returns Err(VmInternalError(..)) on failure. fn get_with_fn( &mut self, key: Key, tx_getter: TxGetter, marf_getter: MarfGetter, - ) -> InterpreterResult> + ) -> Result, VmExecutionError> where TxGetter: FnOnce( &mut MarfTransaction, &StacksBlockId, Key, - ) -> InterpreterResult>, - MarfGetter: FnOnce(&mut ReadOnlyMarfStore, Key) -> InterpreterResult>, + ) -> Result, VmExecutionError>, + MarfGetter: FnOnce(&mut ReadOnlyMarfStore, Key) -> Result, VmExecutionError>, Key: std::fmt::Debug + Copy, { let value_opt = if let EphemeralTip::RAM(tip) = &self.open_tip { @@ -378,7 +378,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { /// Returns Ok(old-chain-tip) on success. /// Returns Err(..) if the given chain tip does not exist or is on a different fork (e.g. is /// not an ancestor of this struct's tip). - fn set_block_hash(&mut self, bhh: StacksBlockId) -> InterpreterResult { + fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result { if self.is_ephemeral_tip(&bhh)? { // open the disk-backed MARF to the base tip, so we can carry out reads on disk-backed // data in the event that a read on a key is `None` for the ephemeral MARF. @@ -397,7 +397,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { .map_err(|e| match e { Error::NotFoundError => { test_debug!("No such block {:?} (NotFoundError)", &bhh); - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) } Error::NonMatchingForks(_bh1, _bh2) => { test_debug!( @@ -406,7 +406,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { BlockHeaderHash(_bh1), BlockHeaderHash(_bh2) ); - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) } _ => panic!("ERROR: Unexpected MARF failure: {}", e), })?; @@ -427,7 +427,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { /// Returns Ok(Some(value)) if the key was mapped to the given value at the opened chain tip. /// Returns Ok(None) if the key was not mapped to the given value at the opened chain tip. /// Returns Err(..) on all other failures. - fn get_data(&mut self, key: &str) -> InterpreterResult> { + fn get_data(&mut self, key: &str) -> Result, VmExecutionError> { trace!( "Ephemeral MarfedKV get_data: {key:?} tip={:?}", &self.open_tip @@ -441,7 +441,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { let side_key = marf_value.to_hex(); let data = SqliteConnection::get(ephemeral_marf.sqlite_conn(), &side_key)? .ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {side_key}", )) })?; @@ -455,7 +455,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { /// Returns Ok(Some(value)) if the key was mapped to the given value at the opeend chain tip. /// Returns Ok(None) if the key was not mapped to the given value at the opened chain tip. /// Returns Err(..) on all other failures - fn get_data_from_path(&mut self, hash: &TrieHash) -> InterpreterResult> { + fn get_data_from_path(&mut self, hash: &TrieHash) -> Result, VmExecutionError> { trace!( "Ephemeral MarfedKV get_from_hash: {:?} tip={:?}", hash, @@ -477,7 +477,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { ); let data = SqliteConnection::get(ephemeral_marf.sqlite_conn(), &side_key)? .ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: Ephemeral MARF contained value_hash not found in side storage: {}", side_key )) @@ -492,7 +492,10 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { /// Returns Ok(Some(value)) if the key was mapped to the given value at the opened chain tip. /// Returns Ok(None) if the key was not mapped to the given value at the opened chain tip. /// Returns Err(..) on all other failures - fn get_data_with_proof(&mut self, key: &str) -> InterpreterResult)>> { + fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError> { trace!( "Ephemeral MarfedKV get_data_with_proof: '{}' tip={:?}", key, @@ -509,7 +512,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { let side_key = marf_value.to_hex(); let data = SqliteConnection::get(ephemeral_marf.sqlite_conn(), &side_key)? .ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -527,7 +530,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { fn get_data_with_proof_from_path( &mut self, hash: &TrieHash, - ) -> InterpreterResult)>> { + ) -> Result)>, VmExecutionError> { trace!( "Ephemeral MarfedKV get_data_with_proof_from_hash: {:?} tip={:?}", hash, @@ -544,7 +547,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { let side_key = marf_value.to_hex(); let data = SqliteConnection::get(ephemeral_marf.sqlite_conn(), &side_key)? .ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -676,7 +679,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { /// Write all (key, value) pairs to the ephemeral MARF. /// Returns Ok(()) on success /// Returns Err(..) on inner MARF errors. - fn put_all_data(&mut self, items: Vec<(String, String)>) -> InterpreterResult<()> { + fn put_all_data(&mut self, items: Vec<(String, String)>) -> Result<(), VmExecutionError> { let mut keys = Vec::with_capacity(items.len()); let mut values = Vec::with_capacity(items.len()); @@ -721,7 +724,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { fn get_contract_hash( &mut self, contract: &QualifiedContractIdentifier, - ) -> InterpreterResult<(StacksBlockId, Sha512Trunc256Sum)> { + ) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError> { sqlite_get_contract_hash(self, contract) } @@ -736,7 +739,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { contract: &QualifiedContractIdentifier, key: &str, value: &str, - ) -> InterpreterResult<()> { + ) -> Result<(), VmExecutionError> { self.teardown_views(); let res = sqlite_insert_metadata(self, contract, key, value); self.setup_views(); @@ -752,7 +755,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { &mut self, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { sqlite_get_metadata(self, contract, key) } @@ -766,7 +769,7 @@ impl ClarityBackingStore for EphemeralMarfStore<'_> { at_height: u32, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { sqlite_get_metadata_manual(self, at_height, contract, key) } } diff --git a/stackslib/src/clarity_vm/database/marf.rs b/stackslib/src/clarity_vm/database/marf.rs index ee97086ecf5..e0add1f2520 100644 --- a/stackslib/src/clarity_vm/database/marf.rs +++ b/stackslib/src/clarity_vm/database/marf.rs @@ -24,9 +24,7 @@ use clarity::vm::database::sqlite::{ sqlite_insert_metadata, }; use clarity::vm::database::{ClarityBackingStore, SpecialCaseHandler, SqliteConnection}; -use clarity::vm::errors::{ - IncomparableError, InterpreterError, InterpreterResult, RuntimeErrorType, -}; +use clarity::vm::errors::{IncomparableError, RuntimeError, VmExecutionError, VmInternalError}; use clarity::vm::types::QualifiedContractIdentifier; use rusqlite; use rusqlite::Connection; @@ -67,16 +65,15 @@ impl MarfedKV { path_str: &str, unconfirmed: bool, marf_opts: Option, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { let mut path = PathBuf::from(path_str); - std::fs::create_dir_all(&path) - .map_err(|_| InterpreterError::FailedToCreateDataDirectory)?; + std::fs::create_dir_all(&path).map_err(|_| VmInternalError::FailedToCreateDataDirectory)?; path.push("marf.sqlite"); let marf_path = path .to_str() - .ok_or_else(|| InterpreterError::BadFileName)? + .ok_or_else(|| VmInternalError::BadFileName)? .to_string(); let mut marf_opts = marf_opts.unwrap_or(MARFOpenOpts::default()); @@ -84,10 +81,10 @@ impl MarfedKV { let mut marf: MARF = if unconfirmed { MARF::from_path_unconfirmed(&marf_path, marf_opts) - .map_err(|err| InterpreterError::MarfFailure(err.to_string()))? + .map_err(|err| VmInternalError::MarfFailure(err.to_string()))? } else { MARF::from_path(&marf_path, marf_opts) - .map_err(|err| InterpreterError::MarfFailure(err.to_string()))? + .map_err(|err| VmInternalError::MarfFailure(err.to_string()))? }; if SqliteConnection::check_schema(marf.sqlite_conn()).is_ok() { @@ -97,11 +94,11 @@ impl MarfedKV { let tx = marf .storage_tx() - .map_err(|err| InterpreterError::DBError(err.to_string()))?; + .map_err(|err| VmInternalError::DBError(err.to_string()))?; SqliteConnection::initialize_conn(&tx)?; tx.commit() - .map_err(|err| InterpreterError::SqliteError(IncomparableError { err }))?; + .map_err(|err| VmInternalError::SqliteError(IncomparableError { err }))?; Ok(marf) } @@ -110,7 +107,7 @@ impl MarfedKV { path_str: &str, miner_tip: Option<&StacksBlockId>, marf_opts: Option, - ) -> InterpreterResult { + ) -> Result { let marf = MarfedKV::setup_db(path_str, false, marf_opts)?; let chain_tip = match miner_tip { Some(miner_tip) => miner_tip.clone(), @@ -128,7 +125,7 @@ impl MarfedKV { path_str: &str, miner_tip: Option<&StacksBlockId>, marf_opts: Option, - ) -> InterpreterResult { + ) -> Result { let marf = MarfedKV::setup_db(path_str, true, marf_opts)?; let chain_tip = match miner_tip { Some(miner_tip) => miner_tip.clone(), @@ -200,14 +197,14 @@ impl MarfedKV { pub fn begin_read_only_checked<'a>( &'a mut self, at_block: Option<&StacksBlockId>, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { let chain_tip = if let Some(at_block) = at_block { self.marf.open_block(at_block).map_err(|e| { debug!( "Failed to open read only connection at {}: {:?}", at_block, &e ); - InterpreterError::MarfFailure(Error::NotFoundError.to_string()) + VmInternalError::MarfFailure(Error::NotFoundError.to_string()) })?; at_block.clone() } else { @@ -290,14 +287,14 @@ impl MarfedKV { &'a mut self, base_tip: &StacksBlockId, ephemeral_next: &StacksBlockId, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { // sanity check -- `base_tip` must be mapped self.marf.open_block(&base_tip).map_err(|e| { debug!( "Failed to open read only connection at {}: {:?}", &base_tip, &e ); - InterpreterError::MarfFailure(Error::NotFoundError.to_string()) + VmInternalError::MarfFailure(Error::NotFoundError.to_string()) })?; // set up ephemeral MARF @@ -306,17 +303,17 @@ impl MarfedKV { MARFOpenOpts::new(TrieHashCalculationMode::Deferred, "noop", false), ) .map_err(|e| { - InterpreterError::Expect(format!("Failed to instantiate ephemeral MARF: {:?}", &e)) + VmInternalError::Expect(format!("Failed to instantiate ephemeral MARF: {:?}", &e)) })?; let mut ephemeral_marf = MARF::from_storage(ephemeral_marf_storage); let tx = ephemeral_marf .storage_tx() - .map_err(|err| InterpreterError::DBError(err.to_string()))?; + .map_err(|err| VmInternalError::DBError(err.to_string()))?; SqliteConnection::initialize_conn(&tx)?; tx.commit() - .map_err(|err| InterpreterError::SqliteError(IncomparableError { err }))?; + .map_err(|err| VmInternalError::SqliteError(IncomparableError { err }))?; self.ephemeral_marf = Some(ephemeral_marf); @@ -333,7 +330,7 @@ impl MarfedKV { // attach the disk-backed MARF to the ephemeral MARF EphemeralMarfStore::attach_read_only_marf(&ephemeral_marf, &read_only_marf).map_err( |e| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "Failed to attach read-only MARF to ephemeral MARF: {:?}", &e )) @@ -341,19 +338,19 @@ impl MarfedKV { )?; let mut tx = ephemeral_marf.begin_tx().map_err(|e| { - InterpreterError::Expect(format!("Failed to open ephemeral MARF tx: {:?}", &e)) + VmInternalError::Expect(format!("Failed to open ephemeral MARF tx: {:?}", &e)) })?; tx.begin(&StacksBlockId::sentinel(), ephemeral_next) .map_err(|e| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "Failed to begin first ephemeral MARF block: {:?}", &e )) })?; let ephemeral_marf_store = EphemeralMarfStore::new(read_only_marf, tx).map_err(|e| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "Failed to instantiate ephemeral MARF store: {:?}", &e )) @@ -406,8 +403,8 @@ impl ClarityMarfStoreTransaction for PersistentWritableMarfStore<'_> { /// metadata rows with `self.chain_tip` as their block identifier to have `target` instead. /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn commit_metadata_for_trie(&mut self, target: &StacksBlockId) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn commit_metadata_for_trie(&mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { SqliteConnection::commit_metadata_to(self.marf.sqlite_tx(), &self.chain_tip, target) } @@ -415,8 +412,8 @@ impl ClarityMarfStoreTransaction for PersistentWritableMarfStore<'_> { /// as their block identifier. /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn drop_metadata_for_trie(&mut self, target: &StacksBlockId) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn drop_metadata_for_trie(&mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { SqliteConnection::drop_metadata(self.marf.sqlite_tx(), target) } @@ -438,8 +435,8 @@ impl ClarityMarfStoreTransaction for PersistentWritableMarfStore<'_> { /// also any unconfirmed trie data from the sqlite DB as well as its associated metadata. /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn drop_unconfirmed(mut self) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn drop_unconfirmed(mut self) -> Result<(), VmExecutionError> { let chain_tip = self.chain_tip.clone(); debug!("Drop unconfirmed MARF trie {}", &chain_tip); self.drop_metadata_for_trie(&chain_tip)?; @@ -452,13 +449,13 @@ impl ClarityMarfStoreTransaction for PersistentWritableMarfStore<'_> { /// drops this MARF store. /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn commit_to_processed_block(mut self, target: &StacksBlockId) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn commit_to_processed_block(mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { debug!("commit_to({})", target); self.commit_metadata_for_trie(target)?; let _ = self.marf.commit_to(target).map_err(|e| { error!("Failed to commit to MARF block {target}: {e:?}"); - InterpreterError::Expect("Failed to commit to MARF block".into()) + VmInternalError::Expect("Failed to commit to MARF block".into()) })?; Ok(()) } @@ -468,8 +465,8 @@ impl ClarityMarfStoreTransaction for PersistentWritableMarfStore<'_> { /// the transaction and drops this MARF store. /// /// Returns Ok(()) on success - /// Returns Err(InterpreterError(..)) on sqlite failure - fn commit_to_mined_block(mut self, target: &StacksBlockId) -> InterpreterResult<()> { + /// Returns Err(VmInternalError(..)) on sqlite failure + fn commit_to_mined_block(mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { debug!("commit_mined_block: ({}->{})", &self.chain_tip, target); // rollback the side_store // the side_store shouldn't commit data for blocks that won't be @@ -480,7 +477,7 @@ impl ClarityMarfStoreTransaction for PersistentWritableMarfStore<'_> { self.drop_metadata_for_trie(&chain_tip)?; let _ = self.marf.commit_mined(target).map_err(|e| { error!("Failed to commit to mined MARF block {target}: {e:?}",); - InterpreterError::Expect("Failed to commit to MARF block".into()) + VmInternalError::Expect("Failed to commit to MARF block".into()) })?; Ok(()) } @@ -540,13 +537,13 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { } /// Sets the chain tip at which queries will happen. Used for `(at-block ..)` - fn set_block_hash(&mut self, bhh: StacksBlockId) -> InterpreterResult { + fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result { self.marf .check_ancestor_block_hash(&bhh) .map_err(|e| match e { Error::NotFoundError => { test_debug!("No such block {:?} (NotFoundError)", &bhh); - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) } Error::NonMatchingForks(_bh1, _bh2) => { test_debug!( @@ -555,7 +552,7 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { BlockHeaderHash(_bh1), BlockHeaderHash(_bh2) ); - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) } _ => panic!("ERROR: Unexpected MARF failure: {}", e), })?; @@ -629,19 +626,22 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { .expect("Attempted to get the open chain tip from an unopened context.") } - fn get_data_with_proof(&mut self, key: &str) -> InterpreterResult)>> { + fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError> { self.marf .get_with_proof(&self.chain_tip, key) .or_else(|e| match e { Error::NotFoundError => Ok(None), _ => Err(e), }) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? .map(|(marf_value, proof)| { let side_key = marf_value.to_hex(); let data = SqliteConnection::get(self.get_side_store(), &side_key)?.ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -654,19 +654,19 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { fn get_data_with_proof_from_path( &mut self, hash: &TrieHash, - ) -> InterpreterResult)>> { + ) -> Result)>, VmExecutionError> { self.marf .get_with_proof_from_hash(&self.chain_tip, hash) .or_else(|e| match e { Error::NotFoundError => Ok(None), _ => Err(e), }) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? .map(|(marf_value, proof)| { let side_key = marf_value.to_hex(); let data = SqliteConnection::get(self.get_side_store(), &side_key)?.ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -676,7 +676,7 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { .transpose() } - fn get_data(&mut self, key: &str) -> InterpreterResult> { + fn get_data(&mut self, key: &str) -> Result, VmExecutionError> { self.marf .get(&self.chain_tip, key) .or_else(|e| match e { @@ -698,11 +698,11 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { Err(e) } }) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? .map(|marf_value| { let side_key = marf_value.to_hex(); SqliteConnection::get(self.get_side_store(), &side_key)?.ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -712,7 +712,7 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { .transpose() } - fn get_data_from_path(&mut self, hash: &TrieHash) -> InterpreterResult> { + fn get_data_from_path(&mut self, hash: &TrieHash) -> Result, VmExecutionError> { trace!("MarfedKV get_from_hash: {:?} tip={}", hash, &self.chain_tip); self.marf .get_from_hash(&self.chain_tip, hash) @@ -727,12 +727,12 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { } _ => Err(e), }) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? .map(|marf_value| { let side_key = marf_value.to_hex(); trace!("MarfedKV get side-key for {:?}: {:?}", hash, &side_key); SqliteConnection::get(self.get_side_store(), &side_key)?.ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -742,7 +742,7 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { .transpose() } - fn put_all_data(&mut self, _items: Vec<(String, String)>) -> InterpreterResult<()> { + fn put_all_data(&mut self, _items: Vec<(String, String)>) -> Result<(), VmExecutionError> { error!("Attempted to commit changes to read-only MARF"); panic!("BUG: attempted commit to read-only MARF"); } @@ -750,7 +750,7 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { fn get_contract_hash( &mut self, contract: &QualifiedContractIdentifier, - ) -> InterpreterResult<(StacksBlockId, Sha512Trunc256Sum)> { + ) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError> { sqlite_get_contract_hash(self, contract) } @@ -759,7 +759,7 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { _contract: &QualifiedContractIdentifier, _key: &str, _value: &str, - ) -> InterpreterResult<()> { + ) -> Result<(), VmExecutionError> { error!("Attempted to commit metadata changes to read-only MARF"); panic!("BUG: attempted metadata commit to read-only MARF"); } @@ -768,7 +768,7 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { &mut self, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { sqlite_get_metadata(self, contract, key) } @@ -777,7 +777,7 @@ impl ClarityBackingStore for ReadOnlyMarfStore<'_> { at_height: u32, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { sqlite_get_metadata_manual(self, at_height, contract, key) } } @@ -791,13 +791,13 @@ impl PersistentWritableMarfStore<'_> { } impl ClarityBackingStore for PersistentWritableMarfStore<'_> { - fn set_block_hash(&mut self, bhh: StacksBlockId) -> InterpreterResult { + fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result { self.marf .check_ancestor_block_hash(&bhh) .map_err(|e| match e { Error::NotFoundError => { test_debug!("No such block {:?} (NotFoundError)", &bhh); - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) } Error::NonMatchingForks(_bh1, _bh2) => { test_debug!( @@ -806,7 +806,7 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { BlockHeaderHash(_bh1), BlockHeaderHash(_bh2) ); - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)) } _ => panic!("ERROR: Unexpected MARF failure: {}", e), })?; @@ -821,7 +821,7 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { Some(&handle_contract_call_special_cases) } - fn get_data(&mut self, key: &str) -> InterpreterResult> { + fn get_data(&mut self, key: &str) -> Result, VmExecutionError> { trace!("MarfedKV get: {:?} tip={}", key, &self.chain_tip); self.marf .get(&self.chain_tip, key) @@ -836,12 +836,12 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { } _ => Err(e), }) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? .map(|marf_value| { let side_key = marf_value.to_hex(); trace!("MarfedKV get side-key for {:?}: {:?}", key, &side_key); SqliteConnection::get(self.marf.sqlite_tx(), &side_key)?.ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -851,7 +851,7 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { .transpose() } - fn get_data_from_path(&mut self, hash: &TrieHash) -> InterpreterResult> { + fn get_data_from_path(&mut self, hash: &TrieHash) -> Result, VmExecutionError> { trace!("MarfedKV get_from_hash: {:?} tip={}", hash, &self.chain_tip); self.marf .get_from_hash(&self.chain_tip, hash) @@ -866,12 +866,12 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { } _ => Err(e), }) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? .map(|marf_value| { let side_key = marf_value.to_hex(); trace!("MarfedKV get side-key for {:?}: {:?}", hash, &side_key); SqliteConnection::get(self.marf.sqlite_tx(), &side_key)?.ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -881,19 +881,22 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { .transpose() } - fn get_data_with_proof(&mut self, key: &str) -> InterpreterResult)>> { + fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError> { self.marf .get_with_proof(&self.chain_tip, key) .or_else(|e| match e { Error::NotFoundError => Ok(None), _ => Err(e), }) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? .map(|(marf_value, proof)| { let side_key = marf_value.to_hex(); let data = SqliteConnection::get(self.marf.sqlite_tx(), &side_key)?.ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -906,19 +909,19 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { fn get_data_with_proof_from_path( &mut self, hash: &TrieHash, - ) -> InterpreterResult)>> { + ) -> Result)>, VmExecutionError> { self.marf .get_with_proof_from_hash(&self.chain_tip, hash) .or_else(|e| match e { Error::NotFoundError => Ok(None), _ => Err(e), }) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure on GET".into()))? .map(|(marf_value, proof)| { let side_key = marf_value.to_hex(); let data = SqliteConnection::get(self.marf.sqlite_tx(), &side_key)?.ok_or_else(|| { - InterpreterError::Expect(format!( + VmInternalError::Expect(format!( "ERROR: MARF contained value_hash not found in side storage: {}", side_key )) @@ -991,7 +994,7 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { } } - fn put_all_data(&mut self, items: Vec<(String, String)>) -> InterpreterResult<()> { + fn put_all_data(&mut self, items: Vec<(String, String)>) -> Result<(), VmExecutionError> { let mut keys = Vec::with_capacity(items.len()); let mut values = Vec::with_capacity(items.len()); for (key, value) in items.into_iter() { @@ -1002,13 +1005,13 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { } self.marf .insert_batch(&keys, values) - .map_err(|_| InterpreterError::Expect("ERROR: Unexpected MARF Failure".into()).into()) + .map_err(|_| VmInternalError::Expect("ERROR: Unexpected MARF Failure".into()).into()) } fn get_contract_hash( &mut self, contract: &QualifiedContractIdentifier, - ) -> InterpreterResult<(StacksBlockId, Sha512Trunc256Sum)> { + ) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError> { sqlite_get_contract_hash(self, contract) } @@ -1017,7 +1020,7 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { contract: &QualifiedContractIdentifier, key: &str, value: &str, - ) -> InterpreterResult<()> { + ) -> Result<(), VmExecutionError> { sqlite_insert_metadata(self, contract, key, value) } @@ -1025,7 +1028,7 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { &mut self, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { sqlite_get_metadata(self, contract, key) } @@ -1034,7 +1037,7 @@ impl ClarityBackingStore for PersistentWritableMarfStore<'_> { at_height: u32, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { sqlite_get_metadata_manual(self, at_height, contract, key) } } @@ -1060,15 +1063,15 @@ impl WritableMarfStore for PersistentWritableMarfStore<'_> {} /// corresponding function in `ClarityMarfStoreTransaction` with a reference to the boxed instance. pub trait BoxedClarityMarfStoreTransaction { fn boxed_drop_current_trie(self: Box); - fn boxed_drop_unconfirmed(self: Box) -> InterpreterResult<()>; + fn boxed_drop_unconfirmed(self: Box) -> Result<(), VmExecutionError>; fn boxed_commit_to_processed_block( self: Box, target: &StacksBlockId, - ) -> InterpreterResult<()>; + ) -> Result<(), VmExecutionError>; fn boxed_commit_to_mined_block( self: Box, target: &StacksBlockId, - ) -> InterpreterResult<()>; + ) -> Result<(), VmExecutionError>; fn boxed_commit_unconfirmed(self: Box); #[cfg(test)] @@ -1080,21 +1083,21 @@ impl BoxedClarityMarfStoreTransaction for T { ::drop_current_trie(*self) } - fn boxed_drop_unconfirmed(self: Box) -> InterpreterResult<()> { + fn boxed_drop_unconfirmed(self: Box) -> Result<(), VmExecutionError> { ::drop_unconfirmed(*self) } fn boxed_commit_to_processed_block( self: Box, target: &StacksBlockId, - ) -> InterpreterResult<()> { + ) -> Result<(), VmExecutionError> { ::commit_to_processed_block(*self, target) } fn boxed_commit_to_mined_block( self: Box, target: &StacksBlockId, - ) -> InterpreterResult<()> { + ) -> Result<(), VmExecutionError> { ::commit_to_mined_block(*self, target) } @@ -1109,11 +1112,11 @@ impl BoxedClarityMarfStoreTransaction for T { } impl<'a> ClarityMarfStoreTransaction for Box { - fn commit_metadata_for_trie(&mut self, target: &StacksBlockId) -> InterpreterResult<()> { + fn commit_metadata_for_trie(&mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { ClarityMarfStoreTransaction::commit_metadata_for_trie(self.deref_mut(), target) } - fn drop_metadata_for_trie(&mut self, target: &StacksBlockId) -> InterpreterResult<()> { + fn drop_metadata_for_trie(&mut self, target: &StacksBlockId) -> Result<(), VmExecutionError> { ClarityMarfStoreTransaction::drop_metadata_for_trie(self.deref_mut(), target) } @@ -1125,14 +1128,14 @@ impl<'a> ClarityMarfStoreTransaction for Box { BoxedClarityMarfStoreTransaction::boxed_drop_current_trie(self) } - fn drop_unconfirmed(self) -> InterpreterResult<()> { + fn drop_unconfirmed(self) -> Result<(), VmExecutionError> { BoxedClarityMarfStoreTransaction::boxed_drop_unconfirmed(self) } - fn commit_to_processed_block(self, target: &StacksBlockId) -> InterpreterResult<()> { + fn commit_to_processed_block(self, target: &StacksBlockId) -> Result<(), VmExecutionError> { BoxedClarityMarfStoreTransaction::boxed_commit_to_processed_block(self, target) } - fn commit_to_mined_block(self, target: &StacksBlockId) -> InterpreterResult<()> { + fn commit_to_mined_block(self, target: &StacksBlockId) -> Result<(), VmExecutionError> { BoxedClarityMarfStoreTransaction::boxed_commit_to_mined_block(self, target) } @@ -1147,30 +1150,33 @@ impl<'a> ClarityMarfStoreTransaction for Box { } impl<'a> ClarityBackingStore for Box { - fn put_all_data(&mut self, items: Vec<(String, String)>) -> InterpreterResult<()> { + fn put_all_data(&mut self, items: Vec<(String, String)>) -> Result<(), VmExecutionError> { ClarityBackingStore::put_all_data(self.deref_mut(), items) } - fn get_data(&mut self, key: &str) -> InterpreterResult> { + fn get_data(&mut self, key: &str) -> Result, VmExecutionError> { ClarityBackingStore::get_data(self.deref_mut(), key) } - fn get_data_from_path(&mut self, hash: &TrieHash) -> InterpreterResult> { + fn get_data_from_path(&mut self, hash: &TrieHash) -> Result, VmExecutionError> { ClarityBackingStore::get_data_from_path(self.deref_mut(), hash) } - fn get_data_with_proof(&mut self, key: &str) -> InterpreterResult)>> { + fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError> { ClarityBackingStore::get_data_with_proof(self.deref_mut(), key) } fn get_data_with_proof_from_path( &mut self, hash: &TrieHash, - ) -> InterpreterResult)>> { + ) -> Result)>, VmExecutionError> { ClarityBackingStore::get_data_with_proof_from_path(self.deref_mut(), hash) } - fn set_block_hash(&mut self, bhh: StacksBlockId) -> InterpreterResult { + fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result { ClarityBackingStore::set_block_hash(self.deref_mut(), bhh) } @@ -1201,7 +1207,7 @@ impl<'a> ClarityBackingStore for Box { fn get_contract_hash( &mut self, contract: &QualifiedContractIdentifier, - ) -> InterpreterResult<(StacksBlockId, Sha512Trunc256Sum)> { + ) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError> { ClarityBackingStore::get_contract_hash(self.deref_mut(), contract) } @@ -1210,7 +1216,7 @@ impl<'a> ClarityBackingStore for Box { contract: &QualifiedContractIdentifier, key: &str, value: &str, - ) -> InterpreterResult<()> { + ) -> Result<(), VmExecutionError> { ClarityBackingStore::insert_metadata(self.deref_mut(), contract, key, value) } @@ -1218,7 +1224,7 @@ impl<'a> ClarityBackingStore for Box { &mut self, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { ClarityBackingStore::get_metadata(self.deref_mut(), contract, key) } @@ -1227,7 +1233,7 @@ impl<'a> ClarityBackingStore for Box { at_height: u32, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { ClarityBackingStore::get_metadata_manual(self.deref_mut(), at_height, contract, key) } } diff --git a/stackslib/src/clarity_vm/database/mod.rs b/stackslib/src/clarity_vm/database/mod.rs index e76aae4dd2c..65041ce4585 100644 --- a/stackslib/src/clarity_vm/database/mod.rs +++ b/stackslib/src/clarity_vm/database/mod.rs @@ -11,7 +11,7 @@ use clarity::vm::database::{ BurnStateDB, ClarityBackingStore, ClarityDatabase, HeadersDB, SpecialCaseHandler, SqliteConnection, NULL_BURN_STATE_DB, NULL_HEADER_DB, }; -use clarity::vm::errors::{InterpreterResult, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError}; use clarity::vm::types::{QualifiedContractIdentifier, TupleData}; use rusqlite::{params, Connection, OptionalExtension, Row}; use stacks_common::types::chainstate::{ @@ -1212,26 +1212,29 @@ impl MemoryBackingStore { } impl ClarityBackingStore for MemoryBackingStore { - fn set_block_hash(&mut self, bhh: StacksBlockId) -> InterpreterResult { - Err(RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)).into()) + fn set_block_hash(&mut self, bhh: StacksBlockId) -> Result { + Err(RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash(bhh.0)).into()) } - fn get_data(&mut self, key: &str) -> InterpreterResult> { + fn get_data(&mut self, key: &str) -> Result, VmExecutionError> { SqliteConnection::get(self.get_side_store(), key) } - fn get_data_from_path(&mut self, hash: &TrieHash) -> InterpreterResult> { + fn get_data_from_path(&mut self, hash: &TrieHash) -> Result, VmExecutionError> { SqliteConnection::get(self.get_side_store(), hash.to_string().as_str()) } - fn get_data_with_proof(&mut self, key: &str) -> InterpreterResult)>> { + fn get_data_with_proof( + &mut self, + key: &str, + ) -> Result)>, VmExecutionError> { Ok(SqliteConnection::get(self.get_side_store(), key)?.map(|x| (x, vec![]))) } fn get_data_with_proof_from_path( &mut self, key: &TrieHash, - ) -> InterpreterResult)>> { + ) -> Result)>, VmExecutionError> { Ok( SqliteConnection::get(self.get_side_store(), key.to_string().as_str())? .map(|x| (x, vec![])), @@ -1266,7 +1269,7 @@ impl ClarityBackingStore for MemoryBackingStore { Some(&handle_contract_call_special_cases) } - fn put_all_data(&mut self, items: Vec<(String, String)>) -> InterpreterResult<()> { + fn put_all_data(&mut self, items: Vec<(String, String)>) -> Result<(), VmExecutionError> { for (key, value) in items.into_iter() { SqliteConnection::put(self.get_side_store(), &key, &value)?; } @@ -1276,7 +1279,7 @@ impl ClarityBackingStore for MemoryBackingStore { fn get_contract_hash( &mut self, contract: &QualifiedContractIdentifier, - ) -> InterpreterResult<(StacksBlockId, Sha512Trunc256Sum)> { + ) -> Result<(StacksBlockId, Sha512Trunc256Sum), VmExecutionError> { sqlite_get_contract_hash(self, contract) } @@ -1285,7 +1288,7 @@ impl ClarityBackingStore for MemoryBackingStore { contract: &QualifiedContractIdentifier, key: &str, value: &str, - ) -> InterpreterResult<()> { + ) -> Result<(), VmExecutionError> { sqlite_insert_metadata(self, contract, key, value) } @@ -1293,7 +1296,7 @@ impl ClarityBackingStore for MemoryBackingStore { &mut self, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { sqlite_get_metadata(self, contract, key) } @@ -1302,7 +1305,7 @@ impl ClarityBackingStore for MemoryBackingStore { at_height: u32, contract: &QualifiedContractIdentifier, key: &str, - ) -> InterpreterResult> { + ) -> Result, VmExecutionError> { sqlite_get_metadata_manual(self, at_height, contract, key) } } diff --git a/stackslib/src/clarity_vm/special.rs b/stackslib/src/clarity_vm/special.rs index 64e41881280..9f01c8526ee 100644 --- a/stackslib/src/clarity_vm/special.rs +++ b/stackslib/src/clarity_vm/special.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use clarity::vm::contexts::GlobalContext; -use clarity::vm::errors::Error as ClarityError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, Value}; /// Handle special cases of contract-calls -- namely, those into PoX that should lock up STX @@ -27,7 +27,7 @@ pub fn handle_contract_call_special_cases( function_name: &str, args: &[Value], result: &Value, -) -> Result<(), ClarityError> { +) -> Result<(), VmExecutionError> { pox_locking::handle_contract_call_special_cases( global_context, sender, diff --git a/stackslib/src/clarity_vm/tests/analysis_costs.rs b/stackslib/src/clarity_vm/tests/analysis_costs.rs index bee1055261c..45b03e4f5b6 100644 --- a/stackslib/src/clarity_vm/tests/analysis_costs.rs +++ b/stackslib/src/clarity_vm/tests/analysis_costs.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use clarity::vm::clarity::{Error as ClarityError, TransactionConnection}; +use clarity::vm::clarity::{ClarityError, TransactionConnection}; use clarity::vm::costs::ExecutionCost; -use clarity::vm::errors::CheckErrors; +use clarity::vm::errors::CheckErrorKind; use clarity::vm::functions::NativeFunctions; use clarity::vm::test_util::TEST_HEADER_DB; use clarity::vm::tests::{test_only_mainnet_to_chain_id, UnitTestBurnStateDB}; @@ -317,10 +317,10 @@ fn undefined_top_variable_error(#[case] use_mainnet: bool, #[case] epoch: Stacks ClarityVersion::Clarity1, &contract_self, ); - let Err(ClarityError::Analysis(check_error)) = analysis_result else { + let Err(ClarityError::StaticCheck(check_error)) = analysis_result else { panic!("Bad analysis result: {analysis_result:?}"); }; - let CheckErrors::UndefinedVariable(var_name) = *check_error.err else { + let CheckErrorKind::UndefinedVariable(var_name) = *check_error.err else { panic!("Bad analysis error: {check_error:?}"); }; assert_eq!(var_name, "foo".to_string()); diff --git a/stackslib/src/clarity_vm/tests/contracts.rs b/stackslib/src/clarity_vm/tests/contracts.rs index 9f01a0e8549..bc8a2c96dd5 100644 --- a/stackslib/src/clarity_vm/tests/contracts.rs +++ b/stackslib/src/clarity_vm/tests/contracts.rs @@ -15,8 +15,8 @@ // along with this program. If not, see . use clarity::types::StacksEpochId; -use clarity::vm::clarity::Error as ClarityError; -use clarity::vm::errors::{CheckErrors, Error}; +use clarity::vm::clarity::ClarityError; +use clarity::vm::errors::{CheckErrorKind, VmExecutionError}; use clarity::vm::types::SequenceData::Buffer; use clarity::vm::types::{ BuffData, OptionalData, PrincipalData, QualifiedContractIdentifier, TupleData, TypeSignature, @@ -48,8 +48,8 @@ fn test_get_burn_block_info_eval() { let clarity_version = ClarityVersion::default_for_epoch(epoch); let res = clarity_db.analyze_smart_contract(&contract_identifier, clarity_version, contract); - if let Err(ClarityError::Analysis(check_error)) = res { - if let CheckErrors::UnknownFunction(func_name) = *check_error.err { + if let Err(ClarityError::StaticCheck(check_error)) = res { + if let CheckErrorKind::UnknownFunction(func_name) = *check_error.err { assert_eq!(func_name, "get-burn-block-info?"); } else { panic!("Bad analysis error: {:?}", &check_error); @@ -69,8 +69,8 @@ fn test_get_burn_block_info_eval() { let clarity_version = ClarityVersion::default_for_epoch(epoch); let res = clarity_db.analyze_smart_contract(&contract_identifier, clarity_version, contract); - if let Err(ClarityError::Analysis(check_error)) = res { - if let CheckErrors::UnknownFunction(func_name) = *check_error.err { + if let Err(ClarityError::StaticCheck(check_error)) = res { + if let CheckErrorKind::UnknownFunction(func_name) = *check_error.err { assert_eq!(func_name, "get-burn-block-info?"); } else { panic!("Bad analysis error: {:?}", &check_error); @@ -161,8 +161,8 @@ fn test_get_block_info_eval_v210() { let clarity_version = ClarityVersion::default_for_epoch(epoch); let res = clarity_db.analyze_smart_contract(&contract_identifier, clarity_version, contract); - if let Err(ClarityError::Analysis(check_error)) = res { - if let CheckErrors::NoSuchBlockInfoProperty(name) = *check_error.err { + if let Err(ClarityError::StaticCheck(check_error)) = res { + if let CheckErrorKind::NoSuchBlockInfoProperty(name) = *check_error.err { assert_eq!(name, "block-reward"); } else { panic!("Bad analysis error: {:?}", &check_error); @@ -182,8 +182,8 @@ fn test_get_block_info_eval_v210() { let clarity_version = ClarityVersion::default_for_epoch(epoch); let res = clarity_db.analyze_smart_contract(&contract_identifier, clarity_version, contract); - if let Err(ClarityError::Analysis(check_error)) = res { - if let CheckErrors::NoSuchBlockInfoProperty(name) = *check_error.err { + if let Err(ClarityError::StaticCheck(check_error)) = res { + if let CheckErrorKind::NoSuchBlockInfoProperty(name) = *check_error.err { assert_eq!(name, "block-reward"); } else { panic!("Bad analysis error: {:?}", &check_error); @@ -282,7 +282,7 @@ fn publish_contract( contract_id: &QualifiedContractIdentifier, contract: &str, version: ClarityVersion, -) -> Result<(), clarity::vm::clarity::Error> { +) -> Result<(), ClarityError> { bc.as_transaction(|tx| { let (ast, analysis) = tx.analyze_smart_contract(contract_id, version, contract)?; tx.initialize_smart_contract( @@ -344,8 +344,8 @@ fn trait_invocation_205_with_stored_principal() { let error = publish_contract(conn, &invoke_contract_id, invoke_contract, clarity_version) .unwrap_err(); match error { - ClarityError::Analysis(ref e) => match *e.err { - CheckErrors::TypeError(..) => (), + ClarityError::StaticCheck(ref e) => match *e.err { + CheckErrorKind::TypeError(..) => (), _ => panic!("Unexpected error: {:?}", error), }, _ => panic!("Unexpected error: {:?}", error), @@ -438,7 +438,7 @@ fn trait_invocation_cross_epoch() { ) .unwrap_err(); - if let ClarityError::Interpreter(Error::Unchecked(CheckErrors::TypeValueError(trait_ref_type, value))) = error { + if let ClarityError::Interpreter(VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(trait_ref_type, value))) = error { assert!(matches!(*trait_ref_type, TypeSignature::TraitReferenceType(_))); } else { panic!("Expected an Interpreter(UncheckedError(TypeValue(TraitReferenceType, Principal))) during Epoch-2.2"); @@ -462,7 +462,7 @@ fn trait_invocation_cross_epoch() { ) .unwrap_err(); - if let ClarityError::Interpreter(Error::Unchecked(CheckErrors::TypeValueError(trait_ref_type, value))) = error { + if let ClarityError::Interpreter(VmExecutionError::Unchecked(CheckErrorKind::TypeValueError(trait_ref_type, value))) = error { assert!(matches!(*trait_ref_type, TypeSignature::TraitReferenceType(_))); } else { panic!("Expected an Interpreter(UncheckedError(TypeValue(TraitReferenceType, Principal))) during Epoch-2.2"); @@ -875,8 +875,8 @@ fn test_block_heights() { ClarityVersion::Clarity1, contract_clarity3, ); - if let Err(ClarityError::Analysis(check_error)) = res { - if let CheckErrors::UndefinedVariable(var_name) = *check_error.err { + if let Err(ClarityError::StaticCheck(check_error)) = res { + if let CheckErrorKind::UndefinedVariable(var_name) = *check_error.err { assert_eq!(var_name, "stacks-block-height"); } else { panic!("Bad analysis error: {:?}", &check_error); @@ -909,8 +909,8 @@ fn test_block_heights() { ClarityVersion::Clarity2, contract_clarity3, ); - if let Err(ClarityError::Analysis(check_error)) = res { - if let CheckErrors::UndefinedVariable(var_name) = *check_error.err { + if let Err(ClarityError::StaticCheck(check_error)) = res { + if let CheckErrorKind::UndefinedVariable(var_name) = *check_error.err { assert_eq!(var_name, "stacks-block-height"); } else { panic!("Bad analysis error: {:?}", &check_error); @@ -925,8 +925,8 @@ fn test_block_heights() { ClarityVersion::Clarity3, contract_clarity1, ); - if let Err(ClarityError::Analysis(check_error)) = res { - if let CheckErrors::UndefinedVariable(var_name) = *check_error.err { + if let Err(ClarityError::StaticCheck(check_error)) = res { + if let CheckErrorKind::UndefinedVariable(var_name) = *check_error.err { assert_eq!(var_name, "block-height"); } else { panic!("Bad analysis error: {:?}", &check_error); diff --git a/stackslib/src/clarity_vm/tests/costs.rs b/stackslib/src/clarity_vm/tests/costs.rs index 62cf5d616ea..8df9c9d1c93 100644 --- a/stackslib/src/clarity_vm/tests/costs.rs +++ b/stackslib/src/clarity_vm/tests/costs.rs @@ -22,7 +22,7 @@ use clarity::vm::costs::{ DefaultVersion, ExecutionCost, LimitedCostTracker, COSTS_1_NAME, COSTS_2_NAME, COSTS_3_NAME, COSTS_4_NAME, }; -use clarity::vm::errors::Error; +use clarity::vm::errors::VmExecutionError; use clarity::vm::events::StacksTransactionEvent; use clarity::vm::functions::NativeFunctions; use clarity::vm::representations::SymbolicExpression; @@ -205,7 +205,7 @@ fn execute_transaction( contract_identifier: &QualifiedContractIdentifier, tx: &str, args: &[SymbolicExpression], -) -> Result<(Value, AssetMap, Vec), Error> { +) -> Result<(Value, AssetMap, Vec), VmExecutionError> { env.execute_transaction(issuer, None, contract_identifier.clone(), tx, args) } diff --git a/stackslib/src/clarity_vm/tests/ephemeral.rs b/stackslib/src/clarity_vm/tests/ephemeral.rs index 9972bb80d12..ae4d4783191 100644 --- a/stackslib/src/clarity_vm/tests/ephemeral.rs +++ b/stackslib/src/clarity_vm/tests/ephemeral.rs @@ -43,6 +43,7 @@ use crate::chainstate::stacks::{ use crate::clarity::vm::database::ClarityBackingStore; use crate::clarity_vm::clarity::ClarityMarfStoreTransaction; use crate::clarity_vm::database::marf::MarfedKV; +use crate::config::DEFAULT_MAX_TENURE_BYTES; use crate::net::test::TestEventObserver; use crate::net::tests::inv::nakamoto::make_nakamoto_peer_from_invs; use crate::net::tests::{NakamotoBootPlan, NakamotoBootStep, NakamotoBootTenure}; @@ -346,6 +347,7 @@ fn replay_block( None, Some(100), Some(original_block.header.timestamp), + u64::from(DEFAULT_MAX_TENURE_BYTES), ) .unwrap(); @@ -358,16 +360,16 @@ fn replay_block( .unwrap(); let mut receipts = vec![]; - + let mut total_receipts = 0; for (i, tx) in original_block.txs.iter().enumerate() { let tx_len = tx.tx_len(); - let tx_result = builder.try_mine_tx_with_len( &mut tenure_tx, tx, tx_len, &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut total_receipts, ); let err = match &tx_result { TransactionResult::Success(_) => Ok(()), diff --git a/stackslib/src/clarity_vm/tests/forking.rs b/stackslib/src/clarity_vm/tests/forking.rs index ef0f4367db3..2b25330e486 100644 --- a/stackslib/src/clarity_vm/tests/forking.rs +++ b/stackslib/src/clarity_vm/tests/forking.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use clarity::vm::analysis::errors::CheckErrors; +use clarity::vm::analysis::errors::CheckErrorKind; use clarity::vm::contexts::OwnedEnvironment; -use clarity::vm::errors::{Error, InterpreterResult as Result, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError}; use clarity::vm::test_util::{ execute, is_committed, is_err_code, symbols_from_values, TEST_BURN_STATE_DB, TEST_HEADER_DB, }; @@ -75,7 +75,7 @@ fn test_at_block_mutations(#[case] version: ClarityVersion, #[case] epoch: Stack version: ClarityVersion, expected_value: i128, to_exec: &str, - ) -> Result { + ) -> Result { let c = QualifiedContractIdentifier::local("contract").unwrap(); let p1 = execute(p1_str).expect_principal().unwrap(); let placeholder_context = @@ -152,7 +152,7 @@ fn test_at_block_good(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc version: ClarityVersion, expected_value: i128, to_exec: &str, - ) -> Result { + ) -> Result { let c = QualifiedContractIdentifier::local("contract").unwrap(); let p1 = execute(p1_str).expect_principal().unwrap(); let placeholder_context = @@ -185,9 +185,9 @@ fn test_at_block_good(#[case] version: ClarityVersion, #[case] epoch: StacksEpoc let resp = branch(x, version, 1, "reset").unwrap_err(); eprintln!("{}", resp); match resp { - Error::Runtime(x, _) => assert_eq!( + VmExecutionError::Runtime(x, _) => assert_eq!( x, - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash::from( + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash::from( vec![2; 32].as_slice() )) ), @@ -219,7 +219,7 @@ fn test_at_block_missing_defines(#[case] version: ClarityVersion, #[case] epoch: owned_env.initialize_contract(c_a, contract, None).unwrap(); } - fn initialize_2(owned_env: &mut OwnedEnvironment) -> Error { + fn initialize_2(owned_env: &mut OwnedEnvironment) -> VmExecutionError { let c_b = QualifiedContractIdentifier::local("contract-b").unwrap(); let contract = "(define-private (problematic-cc) @@ -245,7 +245,7 @@ fn test_at_block_missing_defines(#[case] version: ClarityVersion, #[case] epoch: let err = initialize_2(env); assert_eq!( err, - CheckErrors::NoSuchContract( + CheckErrorKind::NoSuchContract( "S1G2081040G2081040G2081040G208105NK8PE5.contract-a".into() ) .into() diff --git a/stackslib/src/clarity_vm/tests/large_contract.rs b/stackslib/src/clarity_vm/tests/large_contract.rs index 3e1ec77cd0f..06a154ffd1d 100644 --- a/stackslib/src/clarity_vm/tests/large_contract.rs +++ b/stackslib/src/clarity_vm/tests/large_contract.rs @@ -19,7 +19,7 @@ use clarity::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; use clarity::vm::clarity::{ClarityConnection, TransactionConnection}; use clarity::vm::contexts::OwnedEnvironment; use clarity::vm::database::HeadersDB; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::test_util::*; use clarity::vm::tests::{test_clarity_versions, BurnStateDB}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier, Value}; @@ -35,7 +35,7 @@ use stacks_common::types::StacksEpochId; use crate::chainstate::stacks::boot::{BOOT_CODE_COSTS_2, BOOT_CODE_COSTS_3, BOOT_CODE_COSTS_4}; use crate::chainstate::stacks::index::ClarityMarfTrieId; -use crate::clarity_vm::clarity::{ClarityBlockConnection, ClarityInstance, Error as ClarityError}; +use crate::clarity_vm::clarity::{ClarityBlockConnection, ClarityError, ClarityInstance}; use crate::clarity_vm::database::marf::MarfedKV; use crate::clarity_vm::database::MemoryBackingStore; use crate::util_lib::boot::boot_code_id; @@ -1210,7 +1210,7 @@ fn test_deep_tuples() { }); match error { - ClarityError::Interpreter(InterpreterError::Runtime(r_e, _)) => { + ClarityError::Interpreter(VmExecutionError::Runtime(r_e, _)) => { eprintln!("Runtime error: {:?}", r_e); } other => { @@ -1278,7 +1278,7 @@ fn test_deep_tuples_ast_precheck() { }); match error { - ClarityError::Interpreter(InterpreterError::Runtime(r_e, _)) => { + ClarityError::Interpreter(VmExecutionError::Runtime(r_e, _)) => { eprintln!("Runtime error: {:?}", r_e); } other => { @@ -1349,7 +1349,7 @@ fn test_deep_type_nesting() { }); match error { - ClarityError::Interpreter(InterpreterError::Runtime(r_e, _)) => { + ClarityError::Interpreter(VmExecutionError::Runtime(r_e, _)) => { eprintln!("Runtime error: {:?}", r_e); } other => { diff --git a/stackslib/src/clarity_vm/tests/simple_tests.rs b/stackslib/src/clarity_vm/tests/simple_tests.rs index 9257e0a4abd..dce0049bc63 100644 --- a/stackslib/src/clarity_vm/tests/simple_tests.rs +++ b/stackslib/src/clarity_vm/tests/simple_tests.rs @@ -1,5 +1,5 @@ use clarity::vm::contexts::OwnedEnvironment; -use clarity::vm::errors::{Error, RuntimeErrorType}; +use clarity::vm::errors::{RuntimeError, VmExecutionError}; use clarity::vm::test_util::{TEST_BURN_STATE_DB, TEST_HEADER_DB}; use clarity::vm::types::QualifiedContractIdentifier; use stacks_common::consts::{FIRST_BURNCHAIN_CONSENSUS_HASH, FIRST_STACKS_BLOCK_HASH}; @@ -62,11 +62,9 @@ fn test_at_unknown_block() { .unwrap_err(); eprintln!("{err}"); match err { - Error::Runtime(x, _) => assert_eq!( + VmExecutionError::Runtime(x, _) => assert_eq!( x, - RuntimeErrorType::UnknownBlockHeaderHash(BlockHeaderHash::from( - vec![2; 32].as_slice() - )) + RuntimeError::UnknownBlockHeaderHash(BlockHeaderHash::from(vec![2; 32].as_slice())) ), _ => panic!("Unexpected error"), } diff --git a/stackslib/src/config/mod.rs b/stackslib/src/config/mod.rs index 407744f57db..4305a1bcc89 100644 --- a/stackslib/src/config/mod.rs +++ b/stackslib/src/config/mod.rs @@ -126,6 +126,9 @@ const DEFAULT_TENURE_TIMEOUT_SECS: u64 = 180; /// Default percentage of block budget that must be used before attempting a /// time-based tenure extend const DEFAULT_TENURE_EXTEND_COST_THRESHOLD: u64 = 50; +/// Default percentage of block budget that must be used before attempting a +/// time-based read-count extend +const DEFAULT_READ_COUNT_EXTEND_COST_THRESHOLD: u64 = 25; /// Default number of milliseconds that the miner should sleep between mining /// attempts when the mempool is empty. const DEFAULT_EMPTY_MEMPOOL_SLEEP_MS: u64 = 2_500; @@ -134,6 +137,8 @@ const DEFAULT_EMPTY_MEMPOOL_SLEEP_MS: u64 = 2_500; const DEFAULT_MAX_EXECUTION_TIME_SECS: u64 = 30; /// Default number of seconds that a miner should wait before timing out an HTTP request to StackerDB. const DEFAULT_STACKERDB_TIMEOUT_SECS: u64 = 120; +/// Default maximum size for a tenure (note: the counter is reset on tenure extend). +pub const DEFAULT_MAX_TENURE_BYTES: u64 = 10 * 1024 * 1024; // 10 MB static HELIUM_DEFAULT_CONNECTION_OPTIONS: LazyLock = LazyLock::new(|| ConnectionOptions { @@ -582,33 +587,19 @@ impl Config { fn check_nakamoto_config(&self, burnchain: &Burnchain) { let epochs = self.burnchain.get_epoch_list(); - let Some(epoch_30) = epochs.get(StacksEpochId::Epoch30) else { - // no Epoch 3.0, so just return + if epochs + .iter() + .all(|epoch| epoch.epoch_id < StacksEpochId::Epoch30) + { return; - }; + } if burnchain.pox_constants.prepare_length < 3 { panic!( "FATAL: Nakamoto rules require a prepare length >= 3. Prepare length set to {}", burnchain.pox_constants.prepare_length ); } - if burnchain.is_in_prepare_phase(epoch_30.start_height) { - panic!( - "FATAL: Epoch 3.0 must start *during* a reward phase, not a prepare phase. Epoch 3.0 start set to: {}. PoX Parameters: {:?}", - epoch_30.start_height, - &burnchain.pox_constants - ); - } - let activation_reward_cycle = burnchain - .block_height_to_reward_cycle(epoch_30.start_height) - .expect("FATAL: Epoch 3.0 starts before the first burnchain block"); - if activation_reward_cycle < 2 { - panic!( - "FATAL: Epoch 3.0 must start at or after the second reward cycle. Epoch 3.0 start set to: {}. PoX Parameters: {:?}", - epoch_30.start_height, - &burnchain.pox_constants - ); - } + StacksEpoch::validate_nakamoto_transition_schedule(&epochs, burnchain); } /// Connect to the MempoolDB using the configured cost estimation @@ -684,6 +675,7 @@ impl Config { "FATAL: v1 unlock height is at a reward cycle boundary\nburnchain: {burnchain:?}" ); } + StacksEpoch::validate_nakamoto_transition_schedule(epochs, burnchain); } // TODO: add tests from mutation testing results #4866 @@ -1150,12 +1142,14 @@ impl Config { tenure_cost_limit_per_block_percentage: miner_config .tenure_cost_limit_per_block_percentage, contract_cost_limit_percentage: miner_config.contract_cost_limit_percentage, + log_skipped_transactions: miner_config.log_skipped_transactions, }, miner_status, confirm_microblocks: false, max_execution_time: miner_config .max_execution_time_secs .map(Duration::from_secs), + max_tenure_bytes: miner_config.max_tenure_bytes, } } @@ -1197,12 +1191,14 @@ impl Config { tenure_cost_limit_per_block_percentage: miner_config .tenure_cost_limit_per_block_percentage, contract_cost_limit_percentage: miner_config.contract_cost_limit_percentage, + log_skipped_transactions: miner_config.log_skipped_transactions, }, miner_status, confirm_microblocks: true, max_execution_time: miner_config .max_execution_time_secs .map(Duration::from_secs), + max_tenure_bytes: miner_config.max_tenure_bytes, } } @@ -3010,6 +3006,21 @@ pub struct MinerConfig { /// @notes: /// - Values: 0-100. pub tenure_extend_cost_threshold: u64, + /// Percentage of block budget that must be used before attempting a time-based tenure extend. + /// + /// This sets a minimum threshold for the accumulated execution cost within a + /// tenure before a time-based tenure extension ([`MinerConfig::tenure_timeout`]) + /// can be initiated. The miner checks if the proportion of the total tenure + /// budget consumed so far exceeds this percentage. If the cost usage is below + /// this threshold, a time-based extension will not be attempted, even if the + /// [`MinerConfig::tenure_timeout`] duration has elapsed. This prevents miners + /// from extending tenures very early if they have produced only low-cost blocks. + /// --- + /// @default: [`DEFAULT_READ_COUNT_EXTEND_COST_THRESHOLD`] + /// @units: percent + /// @notes: + /// - Values: 0-100. + pub read_count_extend_cost_threshold: u64, /// Defines adaptive timeouts for waiting for signer responses, based on the /// accumulated weight of rejections. /// @@ -3061,6 +3072,18 @@ pub struct MinerConfig { /// @default: [`DEFAULT_STACKERDB_TIMEOUT_SECS`] /// @units: seconds. pub stackerdb_timeout: Duration, + /// Defines them maximum numnber of bytes to allow in a tenure. + /// The miner will stop mining if the limit is reached. + /// --- + /// @default: [`DEFAULT_MAX_TENURE_BYTES`] + /// @units: bytes. + pub max_tenure_bytes: u64, + /// Enable logging of skipped transactions (generally used for tests) + /// --- + /// @default: `false` + /// @notes: + /// - Primarily intended for testing purposes. + pub log_skipped_transactions: bool, } impl Default for MinerConfig { @@ -3104,6 +3127,7 @@ impl Default for MinerConfig { tenure_extend_wait_timeout: Duration::from_millis(DEFAULT_TENURE_EXTEND_WAIT_MS), tenure_timeout: Duration::from_secs(DEFAULT_TENURE_TIMEOUT_SECS), tenure_extend_cost_threshold: DEFAULT_TENURE_EXTEND_COST_THRESHOLD, + read_count_extend_cost_threshold: DEFAULT_READ_COUNT_EXTEND_COST_THRESHOLD, block_rejection_timeout_steps: { let mut rejections_timeouts_default_map = HashMap::::new(); @@ -3116,6 +3140,8 @@ impl Default for MinerConfig { max_execution_time_secs: Some(DEFAULT_MAX_EXECUTION_TIME_SECS), replay_transactions: false, stackerdb_timeout: Duration::from_secs(DEFAULT_STACKERDB_TIMEOUT_SECS), + max_tenure_bytes: DEFAULT_MAX_TENURE_BYTES, + log_skipped_transactions: false, } } } @@ -4061,6 +4087,8 @@ pub struct MinerConfigFile { /// TODO: remove this config option once its no longer a testing feature pub replay_transactions: Option, pub stackerdb_timeout_secs: Option, + pub max_tenure_bytes: Option, + pub log_skipped_transactions: Option, } impl MinerConfigFile { @@ -4253,6 +4281,9 @@ impl MinerConfigFile { max_execution_time_secs: self.max_execution_time_secs, replay_transactions: self.replay_transactions.unwrap_or_default(), stackerdb_timeout: self.stackerdb_timeout_secs.map(Duration::from_secs).unwrap_or(miner_default_config.stackerdb_timeout), + max_tenure_bytes: self.max_tenure_bytes.unwrap_or(miner_default_config.max_tenure_bytes), + log_skipped_transactions: self.log_skipped_transactions.unwrap_or(miner_default_config.log_skipped_transactions), + read_count_extend_cost_threshold: miner_default_config.read_count_extend_cost_threshold, }) } } diff --git a/stackslib/src/core/mempool.rs b/stackslib/src/core/mempool.rs index 099e24b7713..a2e2445e312 100644 --- a/stackslib/src/core/mempool.rs +++ b/stackslib/src/core/mempool.rs @@ -569,6 +569,8 @@ pub struct MemPoolWalkSettings { /// further non-boot contract calls and instead consider only boot contract calls /// and STX transfers. pub contract_cost_limit_percentage: Option, + /// Enable logging of skipped transactions (disabled by default, generally used for tests) + pub log_skipped_transactions: bool, } impl Default for MemPoolWalkSettings { @@ -583,6 +585,7 @@ impl Default for MemPoolWalkSettings { filter_origins: HashSet::new(), tenure_cost_limit_per_block_percentage: None, contract_cost_limit_percentage: None, + log_skipped_transactions: false, } } } @@ -598,6 +601,7 @@ impl MemPoolWalkSettings { filter_origins: HashSet::new(), tenure_cost_limit_per_block_percentage: None, contract_cost_limit_percentage: None, + log_skipped_transactions: false, } } } @@ -1905,7 +1909,10 @@ impl MemPoolDB { output_events.push(tx_event); } TransactionEvent::Skipped(_) => { - // don't push `Skipped` events to the observer + // don't push `Skipped` events to the observer by default + if settings.log_skipped_transactions { + output_events.push(tx_event); + } } _ => { output_events.push(tx_event); diff --git a/stackslib/src/core/mod.rs b/stackslib/src/core/mod.rs index 1b6eaf0e2dd..f32a4d7ffd1 100644 --- a/stackslib/src/core/mod.rs +++ b/stackslib/src/core/mod.rs @@ -29,6 +29,7 @@ use stacks_common::types::{EpochList as GenericEpochList, StacksEpoch as Generic pub use self::mempool::MemPoolDB; use crate::burnchains::bitcoin::indexer::get_bitcoin_stacks_epochs; use crate::burnchains::bitcoin::BitcoinNetworkType; +use crate::burnchains::Burnchain; use crate::chainstate::burn::ConsensusHash; pub mod mempool; pub mod nonce_cache; @@ -883,6 +884,9 @@ pub trait StacksEpochExtension { bitcoin_network: BitcoinNetworkType, configured_epochs: Option<&EpochList>, ) -> EpochList; + /// Validates that Epoch 3.0 activation (if present) satisfies all required safety + /// invariants for Nakamoto transition, using the provided burnchain configuration. + fn validate_nakamoto_transition_schedule(epochs: &[StacksEpoch], burnchain: &Burnchain); } impl StacksEpochExtension for StacksEpoch { @@ -2347,6 +2351,118 @@ impl StacksEpochExtension for StacksEpoch { } assert_eq!(epoch_end_height, STACKS_EPOCH_MAX); + EpochList::new(&epochs) } + + /// Validates that Epoch 3.0 activation (if present) satisfies all required safety + /// invariants for Nakamoto transition, using the provided burnchain configuration. + /// + /// This function is only relevant when **Nakamoto epochs** (Epoch 3.0+) exist in the + /// epoch list. If no post Epoch 2.5 is defined, the function returns early with no checks. + /// + /// ### Required Invariants for Safe Epoch 3.0 Activation + /// + /// 1. **Epoch 2.5 must exist** and start **before** the prepare phase of the reward + /// cycle immediately preceding Epoch 3.0. + /// 2. **Epoch 2.5 must end exactly at the start of Epoch 3.0** — they are contiguous. + /// 3. **Epoch 2.5 and Epoch 3.0 must be in different reward cycles** + /// 4. **Epoch 3.0 must start during a reward phase**, not in a prepare phase. + /// 5. **Epoch 3.0 must not start at a reward cycle boundary** (i.e., block height + /// modulo `reward_cycle_length` must not be 0 or 1). + /// 6. **Epoch 3.0 must activate at or after reward cycle 2** (cycle 0 and 1 are + /// reserved for early network bootstrapping). + /// + /// # Parameters + /// + /// - `epochs`: List of defined Stacks epochs. + /// - `burnchain`: Burnchain configuration, providing PoX reward cycle parameters + /// (`reward_cycle_length`, `prepare_length`) and height-to-cycle utilities. + /// + /// # Panics + /// + /// This function panics if any of the invariants fail. + /// These panics are intended to catch **misconfigured networks** at startup + fn validate_nakamoto_transition_schedule(epochs: &[StacksEpoch], burnchain: &Burnchain) { + // Early return if no Nakamoto epochs are defined + if epochs + .iter() + .all(|epoch| epoch.epoch_id < StacksEpochId::Epoch30) + { + return; + } + let epoch_3_0 = epochs + .iter() + .find(|e| e.epoch_id == StacksEpochId::Epoch30) + .expect("FATAL: Cannot activate Epoch 3.0 without specifying its activation height"); + let epoch_2_5 = epochs + .iter() + .find(|e| e.epoch_id == StacksEpochId::Epoch25) + .expect("FATAL: Epoch 2.5 not found"); + let epoch_3_0_start = epoch_3_0.start_height; + let epoch_2_5_start = epoch_2_5.start_height; + let epoch_2_5_end = epoch_2_5.end_height; + + let reward_cycle_length = u64::from(burnchain.pox_constants.reward_cycle_length); + let prepare_length = u64::from(burnchain.pox_constants.prepare_length); + + assert!( + !burnchain.is_in_prepare_phase(epoch_3_0_start), + "FATAL: Epoch 3.0 must start *during* a reward phase, not prepare phase. \ + Activation height: {epoch_3_0_start}, PoX Parameters: {:?}", + burnchain.pox_constants + ); + + let activation_reward_cycle = burnchain + .block_height_to_reward_cycle(epoch_3_0_start) + .expect("FATAL: Epoch 3.0 cannot start before the first burnchain block"); + assert!( + activation_reward_cycle >= 2, + "FATAL: Epoch 3.0 must start at or after reward cycle 2. \ + Activation height: {epoch_3_0_start}, cycle: {activation_reward_cycle}, \ + PoX Parameters: {:?}", + burnchain.pox_constants + ); + + let epoch_2_5_reward_cycle = epoch_2_5_start / reward_cycle_length; + let epoch_3_0_reward_cycle = epoch_3_0_start / reward_cycle_length; + // Start of prepare phase in the cycle before Epoch 3.0 + let prior_cycle = epoch_3_0_reward_cycle.saturating_sub(1); + let epoch_3_0_prepare_phase_start = + prior_cycle * reward_cycle_length + (reward_cycle_length - prepare_length); + assert!( + epoch_2_5_start < epoch_3_0_prepare_phase_start, + "FATAL: Epoch 2.5 must start before the prepare phase of the cycle prior to Epoch 3.0. \ + Epoch 2.5 start: {epoch_2_5_start}, \ + Epoch 3.0 prior cycle prepare phase start: {epoch_3_0_prepare_phase_start}, \ + PoX Parameters: {:?}", + burnchain.pox_constants + ); + + assert_eq!( + epoch_2_5_end, epoch_3_0_start, + "FATAL: Epoch 2.5 end must equal Epoch 3.0 start. \ + End: {epoch_2_5_end}, Start: {epoch_3_0_start}" + ); + + assert_ne!( + epoch_2_5_reward_cycle, epoch_3_0_reward_cycle, + "FATAL: Epoch 2.5 and Epoch 3.0 must not be in the same reward cycle. \ + Epoch 2.5 cycle: {epoch_2_5_reward_cycle}, \ + Epoch 3.0 cycle: {epoch_3_0_reward_cycle}, \ + PoX Parameters: {:?}", + burnchain.pox_constants + ); + + // Epoch 2.5 has some confusing boundary logic for calculating the reward set hence why + // the boundary is viewed as both 0 and 1. + assert!( + epoch_3_0_start % reward_cycle_length > 1, + "FATAL: Epoch 3.0 must not start at a reward cycle boundary (offset 0 or 1). \ + Activation height: {epoch_3_0_start}, \ + offset: {}, PoX Parameters: {:?}", + epoch_3_0_start % reward_cycle_length, + burnchain.pox_constants + ); + } } diff --git a/stackslib/src/core/test_util.rs b/stackslib/src/core/test_util.rs index 5827f0dfd6f..50307195e04 100644 --- a/stackslib/src/core/test_util.rs +++ b/stackslib/src/core/test_util.rs @@ -104,7 +104,7 @@ pub fn sign_standard_single_sig_tx_anchor_mode_version( } #[allow(clippy::too_many_arguments)] -pub fn sign_tx_anchor_mode_version( +pub fn make_unsigned_tx( payload: TransactionPayload, sender: &StacksPrivateKey, payer: Option<&StacksPrivateKey>, @@ -139,6 +139,32 @@ pub fn sign_tx_anchor_mode_version( unsigned_tx.anchor_mode = anchor_mode; unsigned_tx.post_condition_mode = TransactionPostConditionMode::Allow; unsigned_tx.chain_id = chain_id; + unsigned_tx +} + +#[allow(clippy::too_many_arguments)] +pub fn sign_tx_anchor_mode_version( + payload: TransactionPayload, + sender: &StacksPrivateKey, + payer: Option<&StacksPrivateKey>, + sender_nonce: u64, + payer_nonce: Option, + tx_fee: u64, + chain_id: u32, + anchor_mode: TransactionAnchorMode, + version: TransactionVersion, +) -> StacksTransaction { + let unsigned_tx = make_unsigned_tx( + payload, + sender, + payer, + sender_nonce, + payer_nonce, + tx_fee, + chain_id, + anchor_mode, + version, + ); let mut tx_signer = StacksTransactionSigner::new(&unsigned_tx); tx_signer.sign_origin(sender).unwrap(); @@ -178,7 +204,7 @@ pub fn serialize_sign_tx_anchor_mode_version( buf } -pub fn make_contract_publish_versioned( +pub fn make_contract_publish_tx( sender: &StacksPrivateKey, nonce: u64, tx_fee: u64, @@ -186,17 +212,35 @@ pub fn make_contract_publish_versioned( contract_name: &str, contract_content: &str, version: Option, -) -> Vec { +) -> StacksTransaction { let name = ContractName::from(contract_name); let code_body = StacksString::from_string(&contract_content.to_string()).unwrap(); let payload = TransactionPayload::SmartContract(TransactionSmartContract { name, code_body }, version); - let tx = sign_standard_single_sig_tx(payload, sender, nonce, tx_fee, chain_id); - let mut tx_bytes = vec![]; - tx.consensus_serialize(&mut tx_bytes).unwrap(); - tx_bytes + sign_standard_single_sig_tx(payload, sender, nonce, tx_fee, chain_id) +} + +pub fn make_contract_publish_versioned( + sender: &StacksPrivateKey, + nonce: u64, + tx_fee: u64, + chain_id: u32, + contract_name: &str, + contract_content: &str, + version: Option, +) -> Vec { + make_contract_publish_tx( + sender, + nonce, + tx_fee, + chain_id, + contract_name, + contract_content, + version, + ) + .serialize_to_vec() } pub fn make_contract_publish( @@ -381,7 +425,7 @@ pub fn make_coinbase(sender: &StacksPrivateKey, nonce: u64, tx_fee: u64, chain_i } #[allow(clippy::too_many_arguments)] -pub fn make_contract_call( +pub fn make_contract_call_tx( sender: &StacksPrivateKey, nonce: u64, tx_fee: u64, @@ -390,7 +434,7 @@ pub fn make_contract_call( contract_name: &str, function_name: &str, function_args: &[Value], -) -> Vec { +) -> StacksTransaction { let contract_name = ContractName::from(contract_name); let function_name = ClarityName::from(function_name); @@ -401,10 +445,31 @@ pub fn make_contract_call( function_args: function_args.to_vec(), }; - let tx = sign_standard_single_sig_tx(payload.into(), sender, nonce, tx_fee, chain_id); - let mut tx_bytes = vec![]; - tx.consensus_serialize(&mut tx_bytes).unwrap(); - tx_bytes + sign_standard_single_sig_tx(payload.into(), sender, nonce, tx_fee, chain_id) +} + +#[allow(clippy::too_many_arguments)] +pub fn make_contract_call( + sender: &StacksPrivateKey, + nonce: u64, + tx_fee: u64, + chain_id: u32, + contract_addr: &StacksAddress, + contract_name: &str, + function_name: &str, + function_args: &[Value], +) -> Vec { + make_contract_call_tx( + sender, + nonce, + tx_fee, + chain_id, + contract_addr, + contract_name, + function_name, + function_args, + ) + .serialize_to_vec() } #[allow(clippy::too_many_arguments)] diff --git a/stackslib/src/core/tests/mod.rs b/stackslib/src/core/tests/mod.rs index 3e0a5224c30..4977c2e85c3 100644 --- a/stackslib/src/core/tests/mod.rs +++ b/stackslib/src/core/tests/mod.rs @@ -123,6 +123,7 @@ pub fn make_block( burn_header_timestamp: 0, anchored_block_size: 1, burn_view: None, + total_tenure_size: 0, }; c_tx.commit_block(); diff --git a/stackslib/src/cost_estimates/tests/common.rs b/stackslib/src/cost_estimates/tests/common.rs index 56e7269f365..7f169393d3c 100644 --- a/stackslib/src/cost_estimates/tests/common.rs +++ b/stackslib/src/cost_estimates/tests/common.rs @@ -37,6 +37,7 @@ pub fn make_block_receipt(tx_receipts: Vec) -> StacksE burn_header_timestamp: 2, anchored_block_size: 1, burn_view: None, + total_tenure_size: 0, }, tx_receipts, matured_rewards: vec![], diff --git a/stackslib/src/lib.rs b/stackslib/src/lib.rs index b490a291268..90559fa4898 100644 --- a/stackslib/src/lib.rs +++ b/stackslib/src/lib.rs @@ -61,9 +61,6 @@ pub extern crate libstackerdb; pub mod chainstate; pub mod burnchains; -/// Allow panics in CLI commands -#[allow(clippy::indexing_slicing)] -pub mod clarity_cli; /// A high level library for interacting with the Clarity vm pub mod clarity_vm; pub mod config; diff --git a/stackslib/src/net/api/blockreplay.rs b/stackslib/src/net/api/blockreplay.rs index 44ca42e1c74..5937e8dfa5e 100644 --- a/stackslib/src/net/api/blockreplay.rs +++ b/stackslib/src/net/api/blockreplay.rs @@ -21,6 +21,7 @@ use stacks_common::types::chainstate::{BlockHeaderHash, ConsensusHash, StacksBlo use stacks_common::types::net::PeerHost; use stacks_common::util::hash::Sha512Trunc256Sum; use stacks_common::util::secp256k1::MessageSignature; +use stacks_common::util::serde_serializers::prefix_hex_codec; use crate::burnchains::Txid; use crate::chainstate::burn::db::sortdb::SortitionDB; @@ -30,6 +31,7 @@ use crate::chainstate::stacks::db::StacksChainState; use crate::chainstate::stacks::events::{StacksTransactionReceipt, TransactionOrigin}; use crate::chainstate::stacks::miner::{BlockBuilder, BlockLimitFunction, TransactionResult}; use crate::chainstate::stacks::{Error as ChainError, StacksTransaction, TransactionPayload}; +use crate::config::DEFAULT_MAX_TENURE_BYTES; use crate::net::http::{ parse_json, Error, HttpNotFound, HttpRequest, HttpRequestContents, HttpRequestPreamble, HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble, HttpServerError, @@ -134,6 +136,7 @@ impl RPCNakamotoBlockReplayRequestHandler { None, None, Some(block.header.timestamp), + u64::from(DEFAULT_MAX_TENURE_BYTES), ) { Ok(builder) => builder, Err(e) => return Err(e), @@ -153,7 +156,7 @@ impl RPCNakamotoBlockReplayRequestHandler { let mut block_fees: u128 = 0; let mut txs_receipts = vec![]; - + let mut total_receipts = 0u64; for (i, tx) in block.txs.iter().enumerate() { let tx_len = tx.tx_len(); @@ -163,6 +166,7 @@ impl RPCNakamotoBlockReplayRequestHandler { tx_len, &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut total_receipts, ); let err = match tx_result { TransactionResult::Success(tx_result) => { @@ -215,12 +219,17 @@ pub struct RPCReplayedBlockTransaction { pub hex: String, /// result of transaction execution (clarity value) pub result: Value, + /// result of the transaction execution (hex string) + #[serde(with = "prefix_hex_codec")] + pub result_hex: Value, /// amount of burned stx pub stx_burned: u128, /// execution cost infos pub execution_cost: ExecutionCost, /// generated events pub events: Vec, + /// Whether the tx was aborted by a post-condition + pub post_condition_aborted: bool, /// optional vm error pub vm_error: Option, } @@ -233,7 +242,11 @@ impl RPCReplayedBlockTransaction { .enumerate() .map(|(event_index, event)| { event - .json_serialize(event_index, &receipt.transaction.txid(), true) + .json_serialize( + event_index, + &receipt.transaction.txid(), + !receipt.post_condition_aborted, + ) .unwrap() }) .collect(); @@ -244,6 +257,11 @@ impl RPCReplayedBlockTransaction { }; let txid = receipt.transaction.txid(); + let mut serialized_result = vec![]; + receipt + .result + .serialize_write(&mut serialized_result) + .expect("failed to serialize transaction result"); Self { txid, @@ -251,9 +269,11 @@ impl RPCReplayedBlockTransaction { data: transaction_data, hex: receipt.transaction.serialize_to_dbstring(), result: receipt.result.clone(), + result_hex: receipt.result.clone(), stx_burned: receipt.stx_burned, execution_cost: receipt.execution_cost.clone(), events, + post_condition_aborted: receipt.post_condition_aborted, vm_error: receipt.vm_error.clone(), } } diff --git a/stackslib/src/net/api/callreadonly.rs b/stackslib/src/net/api/callreadonly.rs index cc9715b1727..3f62d0ac210 100644 --- a/stackslib/src/net/api/callreadonly.rs +++ b/stackslib/src/net/api/callreadonly.rs @@ -14,11 +14,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use clarity::vm::analysis::CheckErrors; +use clarity::vm::analysis::CheckErrorKind; use clarity::vm::ast::parser::v1::CLARITY_NAME_REGEX; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; -use clarity::vm::errors::Error::Unchecked; +use clarity::vm::errors::VmExecutionError::Unchecked; use clarity::vm::representations::{CONTRACT_NAME_REGEX_STRING, STANDARD_PRINCIPAL_REGEX_STRING}; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use clarity::vm::{ClarityName, ContractName, SymbolicExpression, Value}; @@ -265,7 +265,7 @@ impl RPCRequestHandler for RPCCallReadOnlyRequestHandler { } } Ok(Some(Err(e))) => match e { - Unchecked(CheckErrors::CostBalanceExceeded(actual_cost, _)) + Unchecked(CheckErrorKind::CostBalanceExceeded(actual_cost, _)) if actual_cost.write_count > 0 => { CallReadOnlyResponse { diff --git a/stackslib/src/net/api/fastcallreadonly.rs b/stackslib/src/net/api/fastcallreadonly.rs index cabd8c9db2d..67ca10529e2 100644 --- a/stackslib/src/net/api/fastcallreadonly.rs +++ b/stackslib/src/net/api/fastcallreadonly.rs @@ -15,11 +15,11 @@ use std::time::Duration; -use clarity::vm::analysis::CheckErrors; +use clarity::vm::analysis::CheckErrorKind; use clarity::vm::ast::parser::v1::CLARITY_NAME_REGEX; use clarity::vm::clarity::ClarityConnection; use clarity::vm::costs::{ExecutionCost, LimitedCostTracker}; -use clarity::vm::errors::Error::Unchecked; +use clarity::vm::errors::VmExecutionError::Unchecked; use clarity::vm::representations::{CONTRACT_NAME_REGEX_STRING, STANDARD_PRINCIPAL_REGEX_STRING}; use clarity::vm::types::PrincipalData; use clarity::vm::{ClarityName, ContractName, SymbolicExpression, Value}; @@ -266,7 +266,7 @@ impl RPCRequestHandler for RPCFastCallReadOnlyRequestHandler { } } Ok(Some(Err(e))) => match e { - Unchecked(CheckErrors::CostBalanceExceeded(actual_cost, _)) + Unchecked(CheckErrorKind::CostBalanceExceeded(actual_cost, _)) if actual_cost.write_count > 0 => { CallReadOnlyResponse { @@ -275,7 +275,7 @@ impl RPCRequestHandler for RPCFastCallReadOnlyRequestHandler { cause: Some("NotReadOnly".to_string()), } } - Unchecked(CheckErrors::ExecutionTimeExpired) => { + Unchecked(CheckErrorKind::ExecutionTimeExpired) => { return StacksHttpResponse::new_error( &preamble, &HttpRequestTimeout::new("ExecutionTime expired".to_string()), diff --git a/stackslib/src/net/api/getblockbyheight.rs b/stackslib/src/net/api/getblockbyheight.rs index 916f995fd00..3b908dd694a 100644 --- a/stackslib/src/net/api/getblockbyheight.rs +++ b/stackslib/src/net/api/getblockbyheight.rs @@ -21,14 +21,15 @@ use stacks_common::types::net::PeerHost; use crate::chainstate::stacks::Error as ChainError; use crate::net::api::getblock_v3::NakamotoBlockStream; use crate::net::http::{ - parse_bytes, Error, HttpContentType, HttpNotFound, HttpRequest, HttpRequestContents, - HttpRequestPreamble, HttpResponse, HttpResponseContents, HttpResponsePayload, - HttpResponsePreamble, HttpServerError, + parse_bytes, Error, HttpBadRequest, HttpContentType, HttpNotFound, HttpRequest, + HttpRequestContents, HttpRequestPreamble, HttpResponse, HttpResponseContents, + HttpResponsePayload, HttpResponsePreamble, HttpServerError, }; use crate::net::httpcore::{ HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest, StacksHttpResponse, }; use crate::net::{Error as NetError, StacksNodeState, TipRequest}; +use crate::util_lib::db::Error as DBError; #[derive(Clone)] pub struct RPCNakamotoBlockByHeightRequestHandler { @@ -134,9 +135,12 @@ impl RPCRequestHandler for RPCNakamotoBlockByHeightRequestHandler { // error querying the db let msg = format!("Failed to load block #{}: {:?}\n", block_height, &e); warn!("{}", &msg); - return StacksHttpResponse::new_error(&preamble, &HttpServerError::new(msg)) - .try_into_contents() - .map_err(NetError::from); + let resp = if matches!(e, DBError::BlockHeightOutOfRange) { + StacksHttpResponse::new_error(&preamble, &HttpBadRequest::new(msg)) + } else { + StacksHttpResponse::new_error(&preamble, &HttpServerError::new(msg)) + }; + return resp.try_into_contents().map_err(NetError::from); } }; diff --git a/stackslib/src/net/api/getpoxinfo.rs b/stackslib/src/net/api/getpoxinfo.rs index ccd844c1d40..f00a3008f60 100644 --- a/stackslib/src/net/api/getpoxinfo.rs +++ b/stackslib/src/net/api/getpoxinfo.rs @@ -111,6 +111,7 @@ pub struct RPCPoxInfoData { pub current_cycle: RPCPoxCurrentCycleInfo, pub next_cycle: RPCPoxNextCycleInfo, pub epochs: Vec, + pub current_epoch: StacksEpochId, // below are included for backwards-compatibility pub min_amount_ustx: u64, @@ -354,11 +355,21 @@ impl RPCPoxInfoData { as u64; let cur_cycle_pox_active = sortdb.is_pox_active(burnchain, &burnchain_tip)?; - let epochs = SortitionDB::get_stacks_epochs(sortdb.conn())? + let epochs: Vec = SortitionDB::get_stacks_epochs(sortdb.conn())? .to_vec() .into_iter() .map(RPCPoxEpoch::from) .collect(); + let burn_height = burnchain_tip.block_height; + let current_epoch = epochs + .iter() + .fold(StacksEpochId::Epoch10, |acc, epoch_data| { + if burn_height >= epoch_data.start_height { + epoch_data.epoch_id + } else { + acc + } + }); Ok(RPCPoxInfoData { contract_id: boot_code_id(cur_block_pox_contract, chainstate.mainnet).to_string(), @@ -388,6 +399,7 @@ impl RPCPoxInfoData { ustx_until_pox_rejection: rejection_votes_left_required, }, epochs, + current_epoch, min_amount_ustx: next_threshold, prepare_cycle_length, reward_cycle_id, diff --git a/stackslib/src/net/api/getsortition.rs b/stackslib/src/net/api/getsortition.rs index b6e317af7fc..365b6588cd9 100644 --- a/stackslib/src/net/api/getsortition.rs +++ b/stackslib/src/net/api/getsortition.rs @@ -30,8 +30,9 @@ use crate::chainstate::nakamoto::{NakamotoChainState, StacksDBIndexed}; use crate::chainstate::stacks::db::StacksChainState; use crate::chainstate::stacks::Error as ChainError; use crate::net::http::{ - parse_json, Error, HttpNotFound, HttpRequest, HttpRequestContents, HttpRequestPreamble, - HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble, HttpServerError, + parse_json, Error, HttpBadRequest, HttpNotFound, HttpRequest, HttpRequestContents, + HttpRequestPreamble, HttpResponse, HttpResponseContents, HttpResponsePayload, + HttpResponsePreamble, HttpServerError, }; use crate::net::httpcore::{RPCRequestHandler, StacksHttpRequest, StacksHttpResponse}; use crate::net::{Error as NetError, StacksNodeState}; @@ -358,6 +359,11 @@ impl RPCRequestHandler for GetSortitionHandler { // nope -- error trying to check let msg = format!("Failed to load snapshot for {:?}: {:?}\n", &self.query, &e); warn!("{msg}"); + if matches!(e, ChainError::DBError(DBError::BlockHeightOutOfRange)) { + return StacksHttpResponse::new_error(&preamble, &HttpBadRequest::new(msg)) + .try_into_contents() + .map_err(NetError::from); + } return StacksHttpResponse::new_error(&preamble, &HttpServerError::new(msg)) .try_into_contents() .map_err(NetError::from); diff --git a/stackslib/src/net/api/postblock_proposal.rs b/stackslib/src/net/api/postblock_proposal.rs index 9894454ab61..431af423519 100644 --- a/stackslib/src/net/api/postblock_proposal.rs +++ b/stackslib/src/net/api/postblock_proposal.rs @@ -41,7 +41,8 @@ use crate::chainstate::stacks::miner::{ TransactionSkipped, }; use crate::chainstate::stacks::{Error as ChainError, StacksTransaction, TransactionPayload}; -use crate::clarity_vm::clarity::Error as ClarityError; +use crate::clarity_vm::clarity::ClarityError; +use crate::config::DEFAULT_MAX_TENURE_BYTES; use crate::core::mempool::ProposalCallbackReceiver; use crate::net::http::{ http_reason, parse_json, Error, HttpContentType, HttpRequest, HttpRequestContents, @@ -580,6 +581,7 @@ impl NakamotoBlockProposal { None, None, Some(self.block.header.timestamp), + u64::from(DEFAULT_MAX_TENURE_BYTES), )?; let mut miner_tenure_info = @@ -588,7 +590,7 @@ impl NakamotoBlockProposal { let mut tenure_tx = builder.tenure_begin(&burn_dbconn, &mut miner_tenure_info)?; let block_deadline = Instant::now() + Duration::from_secs(timeout_secs); - + let mut receipts_total = 0u64; for (i, tx) in self.block.txs.iter().enumerate() { let now = Instant::now(); if now >= block_deadline { @@ -607,6 +609,7 @@ impl NakamotoBlockProposal { tx_len, &BlockLimitFunction::NO_LIMIT_HIT, Some(remaining), + &mut receipts_total, ); let err = match tx_result { TransactionResult::Success(_) => Ok(()), @@ -735,6 +738,7 @@ impl NakamotoBlockProposal { None, None, Some(self.block.header.timestamp), + u64::from(DEFAULT_MAX_TENURE_BYTES), )?; let (mut replay_chainstate, _) = StacksChainState::open(mainnet, chain_id, chainstate_path, None)?; @@ -743,6 +747,7 @@ impl NakamotoBlockProposal { let mut replay_tenure_tx = replay_builder.tenure_begin(&burn_dbconn, &mut replay_miner_tenure_info)?; + let mut total_receipts = 0; for (i, tx) in self.block.txs.iter().enumerate() { let tx_len = tx.tx_len(); @@ -784,6 +789,7 @@ impl NakamotoBlockProposal { replay_tx.tx_len(), &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut total_receipts, ); match tx_result { TransactionResult::Skipped(TransactionSkipped { error, .. }) @@ -848,6 +854,7 @@ impl NakamotoBlockProposal { tx_len, &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut total_receipts, ); } @@ -862,6 +869,7 @@ impl NakamotoBlockProposal { tx.tx_len(), &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut total_receipts, ); match tx_result { TransactionResult::Skipped(TransactionSkipped { error, .. }) diff --git a/stackslib/src/net/api/tests/blockreplay.rs b/stackslib/src/net/api/tests/blockreplay.rs index a7a3f7f06a9..305c1c79eaf 100644 --- a/stackslib/src/net/api/tests/blockreplay.rs +++ b/stackslib/src/net/api/tests/blockreplay.rs @@ -16,16 +16,24 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use clarity::types::chainstate::StacksPrivateKey; +use clarity::vm::{ClarityName, ContractName, Value as ClarityValue}; use stacks_common::consts::CHAIN_ID_TESTNET; use stacks_common::types::chainstate::StacksBlockId; -use crate::chainstate::stacks::{Error as ChainError, StacksTransaction}; -use crate::core::test_util::make_contract_publish; +use crate::chainstate::stacks::{ + Error as ChainError, StacksTransaction, StacksTransactionSigner, TransactionAnchorMode, + TransactionContractCall, TransactionPayload, TransactionPostConditionMode, TransactionVersion, +}; +use crate::core::test_util::{ + make_contract_publish, make_contract_publish_tx, make_unsigned_tx, to_addr, +}; use crate::net::api::blockreplay; use crate::net::api::tests::TestRPC; use crate::net::connection::ConnectionOptions; use crate::net::httpcore::{StacksHttp, StacksHttpRequest}; use crate::net::test::TestEventObserver; +use crate::net::tests::{NakamotoBootStep, NakamotoBootTenure}; use crate::net::ProtocolFamily; use crate::stacks_common::codec::StacksMessageCodec; @@ -147,19 +155,12 @@ fn test_try_make_response() { assert_eq!(resp.transactions.len(), tip_block.receipts.len()); - for tx_index in 0..resp.transactions.len() { - assert_eq!( - resp.transactions[tx_index].txid, - tip_block.receipts[tx_index].transaction.txid() - ); - assert_eq!( - resp.transactions[tx_index].events.len(), - tip_block.receipts[tx_index].events.len() - ); - assert_eq!( - resp.transactions[tx_index].result, - tip_block.receipts[tx_index].result - ); + for (resp_tx, tip_tx) in resp.transactions.iter().zip(tip_block.receipts.iter()) { + assert_eq!(resp_tx.txid, tip_tx.transaction.txid()); + assert_eq!(resp_tx.events.len(), tip_tx.events.len()); + assert_eq!(resp_tx.result, tip_tx.result); + assert_eq!(resp_tx.result_hex, tip_tx.result); + assert!(!resp_tx.post_condition_aborted); } // got a failure (404) @@ -183,6 +184,129 @@ fn test_try_make_response() { assert_eq!(preamble.status_code, 401); } +/// Test that events properly set the `committed` flag to `false` +/// when the transaction is aborted by a post-condition. +#[test] +fn replay_block_with_pc_failure() { + let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 33333); + + let test_observer = TestEventObserver::new(); + + // Set up the RPC test with a contract, so that we can test a post-condition failure + let rpc_test = + TestRPC::setup_nakamoto_with_boot_plan(function_name!(), &test_observer, |boot_plan| { + let private_key = StacksPrivateKey::from_seed("blockreplay".as_bytes()); + let addr = to_addr(&private_key); + + let code_body = + "(define-public (test) (stx-transfer? u100 tx-sender 'ST000000000000000000002AMW42H))"; + + let contract_deploy = make_contract_publish_tx( + &private_key, + 0, + 1000, + CHAIN_ID_TESTNET, + &"test", + &code_body, + None, + ); + + let contract_call = { + let contract_name = ContractName::from("test"); + let function_name = ClarityName::from("test"); + + let payload = TransactionContractCall { + address: addr.clone(), + contract_name, + function_name, + function_args: vec![], + }; + let mut unsigned_tx = make_unsigned_tx( + TransactionPayload::ContractCall(payload), + &private_key, + None, + 1, + None, + 1000, + CHAIN_ID_TESTNET, + TransactionAnchorMode::Any, + TransactionVersion::Testnet, + ); + unsigned_tx.post_condition_mode = TransactionPostConditionMode::Deny; + + let mut tx_signer = StacksTransactionSigner::new(&unsigned_tx); + tx_signer.sign_origin(&private_key).unwrap(); + tx_signer.get_tx().unwrap() + }; + + let boot_tenures = vec![NakamotoBootTenure::Sortition(vec![ + NakamotoBootStep::Block(vec![contract_deploy]), + NakamotoBootStep::Block(vec![contract_call]), + ])]; + + boot_plan + .with_boot_tenures(boot_tenures) + .with_ignore_transaction_errors(true) + .with_initial_balances(vec![(addr.into(), 1_000_000)]) + }); + + let nakamoto_consensus_hash = rpc_test.consensus_hash.clone(); + + let mut requests = vec![]; + + let mut request = + StacksHttpRequest::new_block_replay(addr.clone().into(), &rpc_test.canonical_tip); + request.add_header("authorization".into(), "password".into()); + requests.push(request); + + let mut responses = rpc_test.run(requests); + + let response = responses.remove(0); + + debug!( + "Response:\n{}\n", + std::str::from_utf8(&response.try_serialize().unwrap()).unwrap() + ); + + let contents = response.clone().get_http_payload_ok().unwrap(); + let response_json: serde_json::Value = contents.try_into().unwrap(); + + let result_hex = response_json + .get("transactions") + .expect("Expected JSON to have a transactions field") + .as_array() + .expect("Expected transactions to be an array") + .get(0) + .expect("Expected transactions to have at least one element") + .as_object() + .expect("Expected transaction to be an object") + .get("result_hex") + .expect("Expected JSON to have a result_hex field") + .as_str() + .unwrap(); + let result = ClarityValue::try_deserialize_hex_untyped(&result_hex).unwrap(); + result.expect_result_ok().expect("FATAL: result is not ok"); + + let resp = response.decode_replayed_block().unwrap(); + + let tip_block = test_observer.get_blocks().last().unwrap().clone(); + + assert_eq!(resp.transactions.len(), tip_block.receipts.len()); + + assert_eq!(resp.transactions.len(), 1); + + let resp_tx = &resp.transactions.get(0).unwrap(); + + assert!(resp_tx.vm_error.is_some()); + + for event in resp_tx.events.iter() { + let committed = event.get("committed").unwrap().as_bool().unwrap(); + assert!(!committed); + } + + assert!(resp_tx.post_condition_aborted); +} + #[test] fn test_try_make_response_with_unsuccessful_transaction() { let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 33333); @@ -250,19 +374,12 @@ fn test_try_make_response_with_unsuccessful_transaction() { assert_eq!(resp.transactions.len(), tip_block.receipts.len()); - for tx_index in 0..resp.transactions.len() { - assert_eq!( - resp.transactions[tx_index].txid, - tip_block.receipts[tx_index].transaction.txid() - ); - assert_eq!( - resp.transactions[tx_index].events.len(), - tip_block.receipts[tx_index].events.len() - ); - assert_eq!( - resp.transactions[tx_index].result, - tip_block.receipts[tx_index].result - ); + for (resp_tx, tip_tx) in resp.transactions.iter().zip(tip_block.receipts.iter()) { + assert_eq!(resp_tx.txid, tip_tx.transaction.txid()); + assert_eq!(resp_tx.events.len(), tip_tx.events.len()); + assert_eq!(resp_tx.result, tip_tx.result); + assert_eq!(resp_tx.result_hex, tip_tx.result); + assert!(!resp_tx.post_condition_aborted); } assert_eq!( diff --git a/stackslib/src/net/api/tests/postblock_proposal.rs b/stackslib/src/net/api/tests/postblock_proposal.rs index 0ffb2f582e2..db214af51b4 100644 --- a/stackslib/src/net/api/tests/postblock_proposal.rs +++ b/stackslib/src/net/api/tests/postblock_proposal.rs @@ -39,6 +39,7 @@ use crate::chainstate::stacks::db::StacksChainState; use crate::chainstate::stacks::miner::{BlockBuilder, BlockLimitFunction, TransactionResult}; use crate::chainstate::stacks::test::make_codec_test_nakamoto_block; use crate::chainstate::stacks::{StacksMicroblock, StacksTransaction}; +use crate::config::DEFAULT_MAX_TENURE_BYTES; use crate::core::mempool::{MemPoolDropReason, MemPoolEventDispatcher, ProposalCallbackReceiver}; use crate::core::test_util::{ make_big_read_count_contract, make_contract_call, make_contract_publish, @@ -275,6 +276,7 @@ fn test_try_make_response() { None, None, None, + u64::from(DEFAULT_MAX_TENURE_BYTES), ) .unwrap(); @@ -303,6 +305,7 @@ fn test_try_make_response() { tx.tx_len(), &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut 0, ); let block = builder.mine_nakamoto_block(&mut tenure_tx, burn_chain_height); Ok(block) @@ -577,6 +580,7 @@ fn test_block_proposal_validation_timeout() { None, None, None, + u64::from(DEFAULT_MAX_TENURE_BYTES), ) .unwrap(); @@ -605,6 +609,7 @@ fn test_block_proposal_validation_timeout() { deploy_tx.tx_len(), &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut 0, ); assert!(matches!(tx_result, TransactionResult::Success(_))); let tx_result = builder.try_mine_tx_with_len( @@ -613,6 +618,7 @@ fn test_block_proposal_validation_timeout() { call_tx.tx_len(), &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut 0, ); assert!(matches!(tx_result, TransactionResult::Success(_))); let block = builder.mine_nakamoto_block(&mut tenure_tx, burn_chain_height); @@ -724,6 +730,7 @@ fn replay_validation_test( None, None, None, + u64::from(DEFAULT_MAX_TENURE_BYTES), ) .unwrap(); @@ -753,6 +760,7 @@ fn replay_validation_test( tx.tx_len(), &BlockLimitFunction::NO_LIMIT_HIT, None, + &mut 0, ); } let block = builder.mine_nakamoto_block(&mut tenure_tx, burn_chain_height); diff --git a/stackslib/src/net/http/request.rs b/stackslib/src/net/http/request.rs index c5bf2d4a462..6b5b1a6e19b 100644 --- a/stackslib/src/net/http/request.rs +++ b/stackslib/src/net/http/request.rs @@ -16,6 +16,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::io::{Read, Write}; +use std::sync::Arc; use regex::{Captures, Regex}; use serde_json; @@ -449,6 +450,8 @@ pub enum HttpRequestPayload { Empty, /// JSON body JSON(serde_json::Value), + /// Pre-serialized JSON body + JSONBytes(Arc<[u8]>), /// Bytes body Bytes(Vec), /// Text body @@ -461,6 +464,7 @@ impl HttpRequestPayload { match self { Self::Empty => None, Self::JSON(..) => Some(HttpContentType::JSON), + Self::JSONBytes(..) => Some(HttpContentType::JSON), Self::Bytes(..) => Some(HttpContentType::Bytes), Self::Text(..) => Some(HttpContentType::Text), } @@ -476,6 +480,7 @@ impl HttpRequestPayload { let bytes = serde_json::to_vec(val)?; Ok(bytes.len() as u32) } + Self::JSONBytes(ref val) => Ok(val.len() as u32), Self::Bytes(ref val) => Ok(val.len() as u32), Self::Text(ref val) => Ok(val.as_str().as_bytes().len() as u32), } @@ -486,6 +491,7 @@ impl HttpRequestPayload { match self { Self::Empty => Ok(()), Self::JSON(ref value) => serde_json::to_writer(fd, value).map_err(Error::JsonError), + Self::JSONBytes(ref value) => fd.write_all(value.as_ref()).map_err(Error::WriteError), Self::Bytes(ref value) => fd.write_all(value).map_err(Error::WriteError), Self::Text(ref value) => fd.write_all(value.as_bytes()).map_err(Error::WriteError), } @@ -544,6 +550,22 @@ impl HttpRequestContents { self } + /// chain constructor -- set the payload to a shared, pre-serialized JSON blob + pub fn payload_json_bytes(mut self, bytes: Arc<[u8]>) -> Self { + self.payload = HttpRequestPayload::JSONBytes(bytes); + self + } + + /// chain constructor -- serialize a referenced JSON value once and reuse it + pub fn try_payload_json_ref( + mut self, + value: &serde_json::Value, + ) -> Result { + let bytes = serde_json::to_vec(value)?; + self.payload = HttpRequestPayload::JSONBytes(Arc::from(bytes)); + Ok(self) + } + /// chain constructor -- set the payload to bytes pub fn payload_bytes(mut self, value: Vec) -> Self { self.payload = HttpRequestPayload::Bytes(value); diff --git a/stackslib/src/net/mod.rs b/stackslib/src/net/mod.rs index 519474fb0ab..55e9e5de952 100644 --- a/stackslib/src/net/mod.rs +++ b/stackslib/src/net/mod.rs @@ -19,7 +19,7 @@ use std::io::{Read, Write}; use std::net::{IpAddr, SocketAddr}; use std::{error, fmt, io}; -use clarity::vm::errors::Error as InterpreterError; +use clarity::vm::errors::VmExecutionError; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use libstackerdb::{Error as libstackerdb_error, StackerDBChunkData}; use p2p::{DropReason, DropSource}; @@ -48,7 +48,7 @@ use crate::chainstate::stacks::{ Error as chainstate_error, Error as chain_error, StacksBlock, StacksMicroblock, StacksPublicKey, StacksTransaction, }; -use crate::clarity_vm::clarity::Error as clarity_error; +use crate::clarity_vm::clarity::ClarityError; use crate::core::mempool::*; use crate::cost_estimates::metrics::CostMetric; use crate::cost_estimates::{CostEstimator, FeeEstimator}; @@ -203,7 +203,7 @@ pub enum Error { /// MARF error, percolated up from chainstate MARFError(marf_error), /// Clarity VM error, percolated up from chainstate - ClarityError(clarity_error), + ClarityError(ClarityError), /// Catch-all for chainstate errors that don't map cleanly into network errors ChainstateError(String), /// Coordinator hung up @@ -527,14 +527,14 @@ impl From for Error { } } -impl From for Error { - fn from(e: clarity_error) -> Self { +impl From for Error { + fn from(e: ClarityError) -> Self { Error::ClarityError(e) } } -impl From for Error { - fn from(e: InterpreterError) -> Self { +impl From for Error { + fn from(e: VmExecutionError) -> Self { Error::ClarityError(e.into()) } } diff --git a/stackslib/src/net/relay.rs b/stackslib/src/net/relay.rs index 025f2815aca..88803b5b92b 100644 --- a/stackslib/src/net/relay.rs +++ b/stackslib/src/net/relay.rs @@ -18,7 +18,7 @@ use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::mem; use clarity::vm::ast::ast_check_size; -use clarity::vm::ast::errors::ParseErrors; +use clarity::vm::ast::errors::ParseErrorKind; use clarity::vm::types::{QualifiedContractIdentifier, StacksAddressExtensions}; use clarity::vm::ClarityVersion; use rand::prelude::*; @@ -1801,8 +1801,8 @@ impl Relayer { match ast_res { Ok(_) => {} Err(parse_error) => match *parse_error.err { - ParseErrors::ExpressionStackDepthTooDeep - | ParseErrors::VaryExpressionStackDepthTooDeep => { + ParseErrorKind::ExpressionStackDepthTooDeep + | ParseErrorKind::VaryExpressionStackDepthTooDeep => { // don't include this block info!("Transaction {} is problematic and will not be included, relayed, or built upon", &tx.txid()); return Err(Error::ClarityError(parse_error.into())); diff --git a/stackslib/src/net/tests/mod.rs b/stackslib/src/net/tests/mod.rs index 56d1f14b1cd..af525cd11e3 100644 --- a/stackslib/src/net/tests/mod.rs +++ b/stackslib/src/net/tests/mod.rs @@ -25,7 +25,7 @@ pub mod relay; use std::collections::{HashMap, HashSet}; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; -use clarity::types::EpochList; +use clarity::types::{EpochList, StacksEpochId}; use clarity::vm::costs::ExecutionCost; use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier}; use libstackerdb::StackerDBChunkData; @@ -105,6 +105,8 @@ pub struct NakamotoBootPlan { pub epochs: Option>, /// Additional transactions to include in the tip block pub tip_transactions: Vec, + /// Additional tenures to include at the end of the boot plan + pub extra_tenures: Vec, /// Do not fail if a transaction returns error (by default the BootPlan will stop on tx failure) pub ignore_transaction_errors: bool, } @@ -126,6 +128,7 @@ impl NakamotoBootPlan { malleablized_blocks: true, network_id: default_config.network_id, txindex: false, + extra_tenures: vec![], epochs: None, tip_transactions: vec![], ignore_transaction_errors: false, @@ -183,6 +186,13 @@ impl NakamotoBootPlan { chainstate_config.test_stackers = Some(self.test_stackers.clone()); chainstate_config.burnchain.pox_constants = self.pox_constants.clone(); + if let Some(epochs) = chainstate_config.epochs.as_ref() { + StacksEpoch::validate_nakamoto_transition_schedule( + epochs, + &chainstate_config.burnchain, + ); + } + chainstate_config } @@ -263,6 +273,11 @@ impl NakamotoBootPlan { self } + pub fn with_boot_tenures(mut self, boot_tenures: Vec) -> Self { + self.extra_tenures = boot_tenures; + self + } + /// This is the first tenure in which nakamoto blocks will be built. /// However, it is also the last sortition for an epoch 2.x block. pub fn nakamoto_start_burn_height(pox_consts: &PoxConstants) -> u64 { @@ -418,17 +433,19 @@ impl NakamotoBootPlan { } } - /// Make a chainstate and transition it into the Nakamoto epoch. + /// Make a chainstate capable of transitioning into the Nakamoto epoch. /// The node needs to be stacking; otherwise, Nakamoto won't activate. - pub fn boot_nakamoto_chainstate( + pub fn to_chainstate( self, observer: Option<&TestEventObserver>, + current_block: Option, ) -> TestChainstate<'_> { - let chainstate_config = self.build_nakamoto_chainstate_config(); + let mut chainstate_config = self.build_nakamoto_chainstate_config(); + if let Some(current_block) = current_block { + chainstate_config.current_block = current_block; + } let mut chain = TestChainstate::new_with_observer(chainstate_config, observer); chain.mine_malleablized_blocks = self.malleablized_blocks; - let mut chain_nonce = 0; - chain.advance_to_nakamoto_epoch(&self.private_key, &mut chain_nonce); chain } @@ -467,18 +484,13 @@ impl NakamotoBootPlan { other_peers.push(other_peer); } - let mut peer_nonce = 0; - let mut other_peer_nonces = vec![0; other_peers.len()]; - // Advance primary peer and other peers to Nakamoto epoch peer.chain - .advance_to_nakamoto_epoch(&self.private_key, &mut peer_nonce); - for (other_peer, other_peer_nonce) in - other_peers.iter_mut().zip(other_peer_nonces.iter_mut()) - { + .advance_to_epoch_boundary(&self.private_key, StacksEpochId::Epoch30); + for other_peer in &mut other_peers { other_peer .chain - .advance_to_nakamoto_epoch(&self.private_key, other_peer_nonce); + .advance_to_epoch_boundary(&self.private_key, StacksEpochId::Epoch30); } (peer, other_peers) @@ -486,7 +498,7 @@ impl NakamotoBootPlan { pub fn boot_into_nakamoto_peers( self, - boot_plan: Vec, + mut boot_plan: Vec, observer: Option<&TestEventObserver>, ) -> (TestPeer<'_>, Vec>) { let test_signers = self.test_signers.clone(); @@ -494,6 +506,8 @@ impl NakamotoBootPlan { let test_stackers = self.test_stackers.clone(); let ignore_transaction_errors = self.ignore_transaction_errors; + boot_plan.extend(self.extra_tenures.clone()); + let (mut peer, mut other_peers) = self.boot_nakamoto_peers(observer); if boot_plan.is_empty() { debug!("No boot plan steps supplied -- returning once nakamoto epoch has been reached"); @@ -840,16 +854,15 @@ impl NakamotoBootPlan { for (receipt, tx) in stacks_receipts.iter().zip(block.txs.iter()) { // transactions processed in the same order assert_eq!(receipt.transaction.txid(), tx.txid()); - // no CheckErrors + // no CheckErrorKind if !ignore_transaction_errors { assert!( receipt.vm_error.is_none(), - "Receipt had a CheckErrors: {:?}", - &receipt + "Receipt had a CheckErrorKind: {receipt:?}" ); + // transaction was not aborted post-hoc + assert!(!receipt.post_condition_aborted); } - // transaction was not aborted post-hoc - assert!(!receipt.post_condition_aborted); } } } diff --git a/stackslib/src/util_lib/db.rs b/stackslib/src/util_lib/db.rs index bb396e0e97d..e6d61d6e616 100644 --- a/stackslib/src/util_lib/db.rs +++ b/stackslib/src/util_lib/db.rs @@ -80,6 +80,8 @@ pub enum Error { OldSchema(u64), /// Database is too old for epoch TooOldForEpoch, + /// Block height is out of range + BlockHeightOutOfRange, /// Other error Other(String), } @@ -105,6 +107,7 @@ impl fmt::Display for Error { Error::TooOldForEpoch => { write!(f, "Database is not compatible with current system epoch") } + Error::BlockHeightOutOfRange => write!(f, "Block height is out of range"), Error::Other(ref s) => fmt::Display::fmt(s, f), } } @@ -129,6 +132,7 @@ impl error::Error for Error { Error::IndexError(ref e) => Some(e), Error::OldSchema(ref _s) => None, Error::TooOldForEpoch => None, + Error::BlockHeightOutOfRange => None, Error::Other(ref _s) => None, } } @@ -746,9 +750,11 @@ pub fn get_ancestor_block_hash( block_height: u64, tip_block_hash: &T, ) -> Result, Error> { - assert!(block_height <= u32::MAX as u64); + let block_height = block_height + .try_into() + .map_err(|_e| Error::BlockHeightOutOfRange)?; let mut read_only = index.reopen_connection()?; - let bh = read_only.get_block_at_height(block_height as u32, tip_block_hash)?; + let bh = read_only.get_block_at_height(block_height, tip_block_hash)?; Ok(bh) } diff --git a/stackslib/src/util_lib/strings.rs b/stackslib/src/util_lib/strings.rs index c76dbb6c610..86592ab5e35 100644 --- a/stackslib/src/util_lib/strings.rs +++ b/stackslib/src/util_lib/strings.rs @@ -19,7 +19,7 @@ use std::fmt; use std::io::{Read, Write}; use std::ops::{Deref, DerefMut}; -use clarity::vm::errors::RuntimeErrorType; +use clarity::vm::errors::RuntimeError; use clarity::vm::representations::{ ClarityName, ContractName, MAX_STRING_LEN as CLARITY_MAX_STRING_LENGTH, }; @@ -41,8 +41,8 @@ guarded_string!( "UrlString", URL_STRING_REGEX, CLARITY_MAX_STRING_LENGTH, - RuntimeErrorType, - RuntimeErrorType::BadNameValue + RuntimeError, + RuntimeError::BadNameValue ); /// printable-ASCII-only string, but encodable. diff --git a/versions.toml b/versions.toml index adfddfa30b0..2f541dd0180 100644 --- a/versions.toml +++ b/versions.toml @@ -1,4 +1,4 @@ # Update these values when a new release is created. # `stacks-common/build.rs` will automatically update `versions.rs` with these values. -stacks_node_version = "3.3.0.0.1" -stacks_signer_version = "3.3.0.0.1.0" +stacks_node_version = "3.3.0.0.2" +stacks_signer_version = "3.3.0.0.2.0"