diff --git a/.cargo/config b/.cargo/config index dda826266..c1dd5d640 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,3 +1,2 @@ [alias] -stacks-node = "run --package stacks-node --" -puppet-chain = "run --package puppet-chain --" +stacks-node = "run --package stacks-node --" \ No newline at end of file diff --git a/.github/workflows/bitcoin-tests.yml b/.github/workflows/bitcoin-tests.yml index 976c74dd1..27360d2f4 100644 --- a/.github/workflows/bitcoin-tests.yml +++ b/.github/workflows/bitcoin-tests.yml @@ -40,6 +40,7 @@ jobs: test-name: - tests::neon_integrations::miner_submit_twice - tests::neon_integrations::microblock_integration_test + - tests::neon_integrations::microblock_fork_poison_integration_test - tests::neon_integrations::size_check_integration_test - tests::neon_integrations::cost_voting_integration - tests::integrations::integration_test_get_info @@ -59,7 +60,6 @@ jobs: - tests::neon_integrations::antientropy_integration_test - tests::neon_integrations::filter_low_fee_tx_integration_test - tests::neon_integrations::filter_long_runtime_tx_integration_test - - tests::neon_integrations::mining_transactions_is_fair - tests::neon_integrations::microblock_large_tx_integration_test_FLAKY - tests::neon_integrations::block_large_tx_integration_test - tests::neon_integrations::microblock_limit_hit_integration_test @@ -70,6 +70,11 @@ jobs: - tests::neon_integrations::test_flash_block_skip_tenure - tests::neon_integrations::test_chainwork_first_intervals - tests::neon_integrations::test_chainwork_partial_interval + - tests::neon_integrations::test_problematic_txs_are_not_stored + - tests::neon_integrations::test_problematic_blocks_are_not_mined + - tests::neon_integrations::test_problematic_blocks_are_not_relayed_or_stored + - tests::neon_integrations::test_problematic_microblocks_are_not_mined + - tests::neon_integrations::test_problematic_microblocks_are_not_relayed_or_stored - tests::epoch_205::test_dynamic_db_method_costs - tests::epoch_205::transition_empty_blocks - tests::epoch_205::test_cost_limit_switch_version205 @@ -81,6 +86,7 @@ jobs: - tests::epoch_21::transition_adds_pay_to_contract - tests::epoch_21::transition_adds_get_pox_addr_recipients - tests::epoch_21::transition_adds_mining_from_segwit + - tests::epoch_21::transition_removes_pox_sunset steps: - uses: actions/checkout@v2 - name: Download docker image diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a48626df..bbd97d377 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: workflow_dispatch: inputs: tag: - description: 'The tag to create (optional)' + description: "The tag to create (optional)" required: false concurrency: @@ -110,7 +110,16 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - platform: [ windows-x64, macos-x64, macos-arm64, linux-x64, linux-musl-x64, linux-armv7, linux-arm64 ] + platform: + [ + windows-x64, + macos-x64, + macos-arm64, + linux-x64, + linux-musl-x64, + linux-armv7, + linux-arm64, + ] steps: - uses: actions/checkout@v2 @@ -131,7 +140,7 @@ jobs: STACKS_NODE_VERSION=${{ github.event.inputs.tag || env.GITHUB_SHA_SHORT }} GIT_BRANCH=${{ env.GITHUB_REF_SHORT }} GIT_COMMIT=${{ env.GITHUB_SHA_SHORT }} - + - name: Compress artifact run: zip --junk-paths ${{ matrix.platform }} ./dist/${{ matrix.platform }}/* @@ -141,14 +150,14 @@ jobs: name: ${{ matrix.platform }} path: ${{ matrix.platform }}.zip - call-docker-platforms-workflow: - if: ${{ github.event.inputs.tag != '' }} - uses: stacks-network/stacks-blockchain/.github/workflows/docker-platforms.yml@master - with: - tag: ${{ github.event.inputs.tag }} - secrets: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} +# call-docker-platforms-workflow: +# if: ${{ github.event.inputs.tag != '' }} +# uses: stacks-network/stacks-blockchain/.github/workflows/docker-platforms.yml@master +# with: +# tag: ${{ github.event.inputs.tag }} +# secrets: +# DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} +# DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }} # Build docker image, tag it with the git tag and `latest` if running on master branch, and publish under the following conditions # Will publish if: @@ -290,7 +299,16 @@ jobs: - create-release strategy: matrix: - platform: [ windows-x64, macos-x64, macos-arm64, linux-x64, linux-musl-x64, linux-armv7, linux-arm64 ] + platform: + [ + windows-x64, + macos-x64, + macos-arm64, + linux-x64, + linux-musl-x64, + linux-armv7, + linux-arm64, + ] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/docs-pr.yml b/.github/workflows/docs-pr.yml index 6f43ecb9c..ad293191b 100644 --- a/.github/workflows/docs-pr.yml +++ b/.github/workflows/docs-pr.yml @@ -19,7 +19,7 @@ on: push: branches: [master] -jobs: +jobs: dist: runs-on: ubuntu-latest env: diff --git a/.gitignore b/.gitignore index 49aea8d27..f1371be3b 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ testnet/index.html # will have compiled files and executables /target/ /testnet/helium/target/ +/contrib/tools/puppet-chain/target/ # These are backup files generated by rustfmt **/*.rs.bk @@ -82,3 +83,7 @@ net-test/mnt/archive/* *.profraw *.profdata lcov.info + +# patch +*.orig +*.rej diff --git a/.vscode/launch.json b/.vscode/launch.json index 225e311de..ea804a69a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,266 +1,208 @@ { - "version": "0.2.0", - "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "executable 'blockstack-core'", - "cargo": { - "args": [ - "build", - "--bin=stacks-inspect", - "--package=blockstack-core" - ], - "filter": { - "name": "stacks-inspect", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "executable 'clarity-cli'", - "cargo": { - "args": [ - "build", - "--bin=clarity-cli", - "--package=blockstack-core" - ], - "filter": { - "name": "clarity-cli", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "executable 'blockstack-cli'", - "cargo": { - "args": [ - "build", - "--bin=blockstack-cli", - "--package=blockstack-core" - ], - "filter": { - "name": "blockstack-cli", - "kind": "bin" - } - }, - "args": ["generate-sk"], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "executable 'puppet-chain'", - "cargo": { - "args": [ - "build", - "--bin=puppet-chain", - "--package=puppet-chain" - ], - "filter": { - "name": "puppet-chain", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "executable 'stacks-node' -- mocknet", - "cargo": { - "args": [ - "build", - "--bin=stacks-node", - "--package=stacks-node" - ], - "filter": { - "name": "stacks-node", - "kind": "bin" - } - }, - "args": ["mocknet"], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "unit tests in library 'blockstack_lib'", - "cargo": { - "args": [ - "test", - "--no-run", - "--lib", - "--package=blockstack-core" - ], - "filter": { - "name": "blockstack_lib", - "kind": "lib" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "unit tests in executable 'blockstack-core'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bin=stacks-inspect", - "--package=blockstack-core" - ], - "filter": { - "name": "stacks-inspect", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "unit tests in executable 'clarity-cli'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bin=clarity-cli", - "--package=blockstack-core" - ], - "filter": { - "name": "clarity-cli", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "unit tests in executable 'blockstack-cli'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bin=blockstack-cli", - "--package=blockstack-core" - ], - "filter": { - "name": "blockstack-cli", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "unit tests in executable 'stacks-node'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bin=stacks-node", - "--package=stacks-node" - ], - "filter": { - "name": "stacks-node", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "unit tests in executable 'puppet-chain'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bin=puppet-chain", - "--package=puppet-chain" - ], - "filter": { - "name": "puppet-chain", - "kind": "bin" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "benchmark 'marf_bench'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bench=marf_bench", - "--package=blockstack-core" - ], - "filter": { - "name": "marf_bench", - "kind": "bench" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "benchmark 'large_contract_bench'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bench=large_contract_bench", - "--package=blockstack-core" - ], - "filter": { - "name": "large_contract_bench", - "kind": "bench" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "benchmark 'block_limits'", - "cargo": { - "args": [ - "test", - "--no-run", - "--bench=block_limits", - "--package=blockstack-core" - ], - "filter": { - "name": "block_limits", - "kind": "bench" - } - }, - "args": [], - "cwd": "${workspaceFolder}" + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "executable 'blockstack-core'", + "cargo": { + "args": ["build", "--bin=stacks-inspect", "--package=blockstack-core"], + "filter": { + "name": "stacks-inspect", + "kind": "bin" } - ] + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "executable 'clarity-cli'", + "cargo": { + "args": ["build", "--bin=clarity-cli", "--package=blockstack-core"], + "filter": { + "name": "clarity-cli", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "executable 'blockstack-cli'", + "cargo": { + "args": ["build", "--bin=blockstack-cli", "--package=blockstack-core"], + "filter": { + "name": "blockstack-cli", + "kind": "bin" + } + }, + "args": ["generate-sk"], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "executable 'stacks-node' -- mocknet", + "cargo": { + "args": ["build", "--bin=stacks-node", "--package=stacks-node"], + "filter": { + "name": "stacks-node", + "kind": "bin" + } + }, + "args": ["mocknet"], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "unit tests in library 'blockstack_lib'", + "cargo": { + "args": ["test", "--no-run", "--lib", "--package=blockstack-core"], + "filter": { + "name": "blockstack_lib", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "unit tests in executable 'blockstack-core'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=stacks-inspect", + "--package=blockstack-core" + ], + "filter": { + "name": "stacks-inspect", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "unit tests in executable 'clarity-cli'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=clarity-cli", + "--package=blockstack-core" + ], + "filter": { + "name": "clarity-cli", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "unit tests in executable 'blockstack-cli'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=blockstack-cli", + "--package=blockstack-core" + ], + "filter": { + "name": "blockstack-cli", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "unit tests in executable 'stacks-node'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=stacks-node", + "--package=stacks-node" + ], + "filter": { + "name": "stacks-node", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "benchmark 'marf_bench'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bench=marf_bench", + "--package=blockstack-core" + ], + "filter": { + "name": "marf_bench", + "kind": "bench" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "benchmark 'large_contract_bench'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bench=large_contract_bench", + "--package=blockstack-core" + ], + "filter": { + "name": "large_contract_bench", + "kind": "bench" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "benchmark 'block_limits'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bench=block_limits", + "--package=blockstack-core" + ], + "filter": { + "name": "block_limits", + "kind": "bench" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index a35750f7f..e396d6fb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,10 +25,58 @@ This release will contain consensus-breaking changes. stacks-node uses for logging. Example: `STACKS_LOG_FORMAT_TIME="%Y-%m-%d %H:%M:%S" cargo stacks-node` +## [2.05.0.5.0] + ### Changed -- Updates to the logging of transaction events (#3139). + +- The new minimum Rust version is 1.61 +- The act of walking the mempool will now cache address nonces in RAM and to a + temporary mempool table used for the purpose, instead of unconditionally +querying them from the chainstate MARF. This builds upon improvements to mempool +goodput over 2.05.0.4.0 (#3337). +- The node and miner implementation has been refactored to remove write-lock + contention that can arise when the node's chains-coordinator thread attempts to store and +process newly-discovered (or newly-mined) blocks, and when the node's relayer +thread attempts to mine a new block. In addition, the miner logic has been +moved to a separate thread in order to avoid starving the relayer thread (which +must handle block and transaction propagation, as well as block-processing). +The refactored miner thread will be preemptively terminated and restarted +by the arrival of new Stacks blocks or burnchain blocks, which further +prevents the miner from holding open write-locks in the underlying +chainstate databases when there is new chain data to discover (which would +invalidate the miner's work anyway). (#3335). ### Fixed + +- Fixed `pow` documentation in Clarity (#3338). +- Backported unit tests that were omitted in the 2.05.0.3.0 release (#3348). + +## [2.05.0.4.0] + +### Fixed + +- Denormalize the mempool database so as to remove a `LEFT JOIN` from the SQL + query for choosing transactions in order by estimated fee rate. This +drastically speeds up mempool transaction iteration in the miner (#3314) + + +## [2.05.0.3.0] + +### Added + +- Added prometheus output for "transactions in last block" (#3138). +- Added envrionement variable STACKS_LOG_FORMAT_TIME to set the time format + stacks-node uses for logging. (#3219) + Example: STACKS_LOG_FORMAT_TIME="%Y-%m-%d %H:%M:%S" cargo stacks-node +- Added mock-miner sample config (#3225) + +### Changed + +- Updates to the logging of transaction events (#3139). +- Moved puppet-chain to `./contrib/tools` directory and disabled compiling by default (#3200) + +### Fixed + - Make it so that a new peer private key in the config file will propagate to the peer database (#3165). - Fixed default miner behavior regarding block assembly @@ -42,6 +90,10 @@ This release will contain consensus-breaking changes. from sockets, but instead propagate them to the outer caller. This would lead to a node crash in nodes connected to event observers, which expect the P2P state machine to only report fatal errors (#3228) +- Spawn the p2p thread before processing number of sortitions. Fixes issue (#3216) where sync from genesis paused (#3236) +- Drop well-formed "problematic" transactions that result in miner performance degradation (#3212) +- Ignore blocks that include problematic transactions + ## [2.05.0.2.1] diff --git a/Cargo.lock b/Cargo.lock index bed5a0e72..8551a2e46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1913,21 +1913,6 @@ dependencies = [ "cc", ] -[[package]] -name = "puppet-chain" -version = "0.1.0" -dependencies = [ - "async-h1", - "async-std", - "base64 0.12.3", - "http-types", - "rand 0.7.3", - "serde", - "serde_derive", - "serde_json", - "toml", -] - [[package]] name = "quick-error" version = "1.2.3" diff --git a/Cargo.toml b/Cargo.toml index 0d75d64b0..2b41cc29b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ keywords = [ "stacks", "stx", "bitcoin", "crypto", "blockstack", "decentralized" readme = "README.md" resolver = "2" edition = "2021" +rust-version = "1.61" [profile.release] debug = true @@ -135,5 +136,4 @@ members = [ ".", "clarity", "stx-genesis", - "testnet/stacks-node", - "testnet/puppet-chain"] + "testnet/stacks-node"] diff --git a/Dockerfile b/Dockerfile index 2b16c4155..055cc3df7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,10 +13,8 @@ RUN apk add --no-cache musl-dev RUN mkdir /out RUN cd testnet/stacks-node && cargo build --features monitoring_prom,slog_json --release -RUN cd testnet/puppet-chain && cargo build --release RUN cp target/release/stacks-node /out -RUN cp target/release/puppet-chain /out FROM alpine diff --git a/Dockerfile.stretch b/Dockerfile.stretch index 8cfc0a9db..7f5148dfe 100644 --- a/Dockerfile.stretch +++ b/Dockerfile.stretch @@ -11,10 +11,8 @@ COPY . . RUN mkdir /out RUN cd testnet/stacks-node && cargo build --features monitoring_prom,slog_json --release -RUN cd testnet/puppet-chain && cargo build --release RUN cp target/release/stacks-node /out -RUN cp target/release/puppet-chain /out FROM debian:stretch-slim diff --git a/README.md b/README.md index 0b736ff68..8025bc7dd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Stacks 2.0 is a layer-1 blockchain that connects to Bitcoin for security and ena ## Repository -| Blockstack Topic/Tech | Where to learn more more | +| Blockstack Topic/Tech | Where to learn more | | -------------------------- | --------------------------------------------------------------------------------- | | Stacks 2.0 | [master branch](https://github.com/blockstack/stacks-blockchain/tree/master) | | Stacks 1.0 | [legacy branch](https://github.com/blockstack/stacks-blockchain/tree/stacks-1.0) | @@ -55,7 +55,7 @@ to upgrade to `2.0.10.1.0` or `2.0.10.0.1`. However, upgrading to `2.0.11.0.0` w - [x] [SIP 001: Burn Election](https://github.com/stacksgov/sips/blob/main/sips/sip-001/sip-001-burn-election.md) - [x] [SIP 002: Clarity, a language for predictable smart contracts](https://github.com/stacksgov/sips/blob/main/sips/sip-002/sip-002-smart-contract-language.md) - [x] [SIP 003: Peer Network](https://github.com/stacksgov/sips/blob/main/sips/sip-003/sip-003-peer-network.md) -- [x] [SIP 004: Cryptographic Committment to Materialized Views](https://github.com/stacksgov/sips/blob/main/sips/sip-004/sip-004-materialized-view.md) +- [x] [SIP 004: Cryptographic Commitment to Materialized Views](https://github.com/stacksgov/sips/blob/main/sips/sip-004/sip-004-materialized-view.md) - [x] [SIP 005: Blocks, Transactions, and Accounts](https://github.com/stacksgov/sips/blob/main/sips/sip-005/sip-005-blocks-and-transactions.md) - [x] [SIP 006: Clarity Execution Cost Assessment](https://github.com/stacksgov/sips/blob/main/sips/sip-006/sip-006-runtime-cost-assessment.md) - [x] [SIP 007: Stacking Consensus](https://github.com/stacksgov/sips/blob/main/sips/sip-007/sip-007-stacking-consensus.md) @@ -330,9 +330,8 @@ miner = True seed = "YOUR PRIVATE KEY" # How long to wait for microblocks to arrive before mining a block to confirm them (in milliseconds) wait_time_for_microblocks = 10000 -# Run as a mock-miner, to test mining without spending BTC. -# Mutually exclusive with `miner`. -#mock_miner = True +# Run as a mock-miner, to test mining without spending BTC. Needs miner=True. +#mock_mining = True [miner] # Smallest allowed tx fee, in microSTX @@ -358,7 +357,7 @@ INFO [1630127492.062652] [testnet/stacks-node/src/run_loop/neon.rs:164] [main] U ### Configuring Cost and Fee Estimation -Fee and cost estimators can be configure via the config section `[fee_estimation]`: +Fee and cost estimators can be configured via the config section `[fee_estimation]`: ``` [fee_estimation] @@ -405,7 +404,7 @@ that the change is not consensus-breaking. So, the release manager must first determine whether there are any "non-consensus-breaking changes that require a fresh chainstate". This means, in other words, that the database schema has changed, but an automatic migration was not implemented. Then, the release manager -should determine whether this is a feature release, as opposed to a hot fix or a +should determine whether this is a feature release, as opposed to a hotfix or a patch. Given the answers to these questions, the version number can be computed. 1. The release manager enumerates the PRs or issues that would _block_ diff --git a/clarity/src/vm/analysis/mod.rs b/clarity/src/vm/analysis/mod.rs index 223aa3dbd..60cdaafe5 100644 --- a/clarity/src/vm/analysis/mod.rs +++ b/clarity/src/vm/analysis/mod.rs @@ -42,6 +42,8 @@ use self::contract_interface_builder::build_contract_interface; use self::read_only_checker::ReadOnlyChecker; use self::trait_checker::TraitChecker; use self::type_checker::TypeChecker; +use crate::vm::ast::build_ast_with_rules; +use crate::vm::ast::ASTRules; /// Used by CLI tools like the docs generator. Not used in production pub fn mem_type_check( @@ -49,9 +51,18 @@ pub fn mem_type_check( version: ClarityVersion, epoch: StacksEpochId, ) -> CheckResult<(Option, ContractAnalysis)> { - use crate::vm::ast::parse; let contract_identifier = QualifiedContractIdentifier::transient(); - let mut contract = parse(&contract_identifier, snippet, version, epoch).unwrap(); + let mut contract = build_ast_with_rules( + &contract_identifier, + snippet, + &mut (), + version, + epoch, + ASTRules::PrecheckSize, + ) + .unwrap() + .expressions; + let mut marf = MemoryBackingStore::new(); let mut analysis_db = marf.as_analysis_db(); let cost_tracker = LimitedCostTracker::new_free(); diff --git a/clarity/src/vm/analysis/type_checker/natives/mod.rs b/clarity/src/vm/analysis/type_checker/natives/mod.rs index 0fde0baec..e3596021d 100644 --- a/clarity/src/vm/analysis/type_checker/natives/mod.rs +++ b/clarity/src/vm/analysis/type_checker/natives/mod.rs @@ -213,7 +213,7 @@ pub fn check_special_tuple_cons( })?; let tuple_signature = TupleTypeSignature::try_from(tuple_type_data) - .map_err(|_| CheckErrors::BadTupleConstruction)?; + .map_err(|_e| CheckErrors::BadTupleConstruction)?; Ok(TypeSignature::TupleType(tuple_signature)) } diff --git a/clarity/src/vm/ast/errors.rs b/clarity/src/vm/ast/errors.rs index 659d9849b..1b8cbd1e8 100644 --- a/clarity/src/vm/ast/errors.rs +++ b/clarity/src/vm/ast/errors.rs @@ -33,6 +33,7 @@ pub enum ParseErrors { MemoryBalanceExceeded(u64, u64), TooManyExpressions, ExpressionStackDepthTooDeep, + VaryExpressionStackDepthTooDeep, FailedCapturingInput, SeparatorExpected(String), SeparatorExpectedAfterColon(String), @@ -262,6 +263,10 @@ impl DiagnosableError for ParseErrors { "AST has too deep of an expression nesting. The maximum stack depth is {}", MAX_CALL_STACK_DEPTH ), + ParseErrors::VaryExpressionStackDepthTooDeep => format!( + "AST has too deep of an expression nesting. The maximum stack depth is {}", + MAX_CALL_STACK_DEPTH + ), ParseErrors::InvalidCharactersDetected => format!("invalid characters detected"), ParseErrors::InvalidEscaping => format!("invalid escaping detected in string"), ParseErrors::CostComputationFailed(s) => format!("Cost computation failed: {}", s), diff --git a/clarity/src/vm/ast/mod.rs b/clarity/src/vm/ast/mod.rs index c63ebcc22..6708e96fe 100644 --- a/clarity/src/vm/ast/mod.rs +++ b/clarity/src/vm/ast/mod.rs @@ -32,7 +32,11 @@ use crate::vm::types::QualifiedContractIdentifier; use self::definition_sorter::DefinitionSorter; use self::errors::ParseResult; use self::expression_identifier::ExpressionIdentifier; +use self::parser::v1::parse as parse_v1; +use self::parser::v1::parse_no_stack_limit as parse_v1_no_stack_limit; +use self::parser::v2::parse as parse_v2; use self::stack_depth_checker::StackDepthChecker; +use self::stack_depth_checker::VaryStackDepthChecker; use self::sugar_expander::SugarExpander; use self::traits_resolver::TraitsResolver; use self::types::BuildASTPass; @@ -40,9 +44,11 @@ pub use self::types::ContractAST; use crate::types::StacksEpochId; use crate::vm::costs::cost_functions::ClarityCostFunction; use crate::vm::diagnostic::{Diagnostic, Level}; +use crate::vm::representations::PreSymbolicExpression; use crate::vm::ClarityVersion; /// Legacy function +#[cfg(any(test, features = "testing"))] pub fn parse( contract_identifier: &QualifiedContractIdentifier, source_code: &str, @@ -53,7 +59,74 @@ pub fn parse( Ok(ast.expressions) } -pub fn build_ast( +// AST parser rulesets to apply. +define_u8_enum!(ASTRules { + Typical = 0, + PrecheckSize = 1 +}); + +/// Parse a program based on which epoch is active +fn parse_in_epoch( + source_code: &str, + epoch_id: StacksEpochId, + ast_rules: ASTRules, +) -> ParseResult> { + if epoch_id >= StacksEpochId::Epoch21 { + parse_v2(source_code) + } else { + if ast_rules == ASTRules::Typical { + parse_v1_no_stack_limit(source_code) + } else { + parse_v1(source_code) + } + } +} + +/// This is the part of the AST parser that runs without respect to cost analysis, specifically +/// pertaining to verifying that the AST is reasonably-sized. +/// Used mainly to filter transactions that might be too costly, as an optimization heuristic. +pub fn ast_check_size( + contract_identifier: &QualifiedContractIdentifier, + source_code: &str, + clarity_version: ClarityVersion, + epoch_id: StacksEpochId, +) -> ParseResult { + let pre_expressions = parse_in_epoch(source_code, epoch_id, ASTRules::PrecheckSize)?; + let mut contract_ast = ContractAST::new(contract_identifier.clone(), pre_expressions); + StackDepthChecker::run_pass(&mut contract_ast, clarity_version)?; + VaryStackDepthChecker::run_pass(&mut contract_ast, clarity_version)?; + Ok(contract_ast) +} + +/// Build an AST according to a ruleset +pub fn build_ast_with_rules( + contract_identifier: &QualifiedContractIdentifier, + source_code: &str, + cost_track: &mut T, + clarity_version: ClarityVersion, + epoch: StacksEpochId, + ruleset: ASTRules, +) -> ParseResult { + match ruleset { + ASTRules::Typical => build_ast_typical( + contract_identifier, + source_code, + cost_track, + clarity_version, + epoch, + ), + ASTRules::PrecheckSize => build_ast_precheck_size( + contract_identifier, + source_code, + cost_track, + clarity_version, + epoch, + ), + } +} + +/// Build an AST with the typical rules +fn build_ast_typical( contract_identifier: &QualifiedContractIdentifier, source_code: &str, cost_track: &mut T, @@ -66,6 +139,7 @@ pub fn build_ast( cost_track, clarity_version, epoch, + ASTRules::Typical, true, )?; Ok(contract) @@ -88,17 +162,19 @@ pub fn build_ast_with_diagnostics( cost_track, clarity_version, epoch, + ASTRules::PrecheckSize, false, ) .unwrap() } -pub fn inner_build_ast( +fn inner_build_ast( contract_identifier: &QualifiedContractIdentifier, source_code: &str, cost_track: &mut T, clarity_version: ClarityVersion, epoch: StacksEpochId, + ast_rules: ASTRules, error_early: bool, ) -> ParseResult<(ContractAST, Vec, bool)> { let cost_err = match runtime_cost( @@ -119,7 +195,11 @@ pub fn inner_build_ast( parser::v2::parse_collect_diagnostics(source_code) } } else { - match parser::v1::parse(source_code) { + let parse_result = match ast_rules { + ASTRules::Typical => parse_v1_no_stack_limit(source_code), + ASTRules::PrecheckSize => parse_v1(source_code), + }; + match parse_result { Ok(pre_expressions) => (pre_expressions, vec![], true), Err(error) if error_early => return Err(error), Err(error) => (vec![], vec![error.diagnostic], false), @@ -137,6 +217,7 @@ pub fn inner_build_ast( }, ); } + let mut contract_ast = ContractAST::new(contract_identifier.clone(), pre_expressions); match StackDepthChecker::run_pass(&mut contract_ast, clarity_version) { Err(e) if error_early => return Err(e), @@ -146,6 +227,19 @@ pub fn inner_build_ast( } _ => (), } + + if ast_rules != ASTRules::Typical { + // run extra stack-depth pass for tuples + match VaryStackDepthChecker::run_pass(&mut contract_ast, clarity_version) { + Err(e) if error_early => return Err(e), + Err(e) => { + diagnostics.push(e.diagnostic); + success = false; + } + _ => (), + } + } + match ExpressionIdentifier::run_pre_expression_pass(&mut contract_ast, clarity_version) { Err(e) if error_early => return Err(e), Err(e) => { @@ -189,17 +283,316 @@ pub fn inner_build_ast( Ok((contract_ast, diagnostics, success)) } +/// Built an AST, but pre-check the size of the AST before doing more work +fn build_ast_precheck_size( + contract_identifier: &QualifiedContractIdentifier, + source_code: &str, + cost_track: &mut T, + clarity_version: ClarityVersion, + epoch: StacksEpochId, +) -> ParseResult { + let (contract, _, _) = inner_build_ast( + contract_identifier, + source_code, + cost_track, + clarity_version, + epoch, + ASTRules::PrecheckSize, + true, + )?; + Ok(contract) +} + +/// Test compatibility +#[cfg(any(test, feature = "testing"))] +pub fn build_ast( + contract_identifier: &QualifiedContractIdentifier, + source_code: &str, + cost_track: &mut T, + clarity_version: ClarityVersion, + epoch_id: StacksEpochId, +) -> ParseResult { + build_ast_typical( + contract_identifier, + source_code, + cost_track, + clarity_version, + epoch_id, + ) +} + #[cfg(test)] mod test { - use std::collections::HashMap; - - use stacks_common::types::StacksEpochId; - - use crate::vm::ast::build_ast; + use crate::vm::ast::errors::ParseErrors; + use crate::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; + use crate::vm::ast::{build_ast, build_ast_with_rules, ASTRules}; use crate::vm::costs::LimitedCostTracker; + use crate::vm::costs::*; use crate::vm::representations::depth_traverse; use crate::vm::types::QualifiedContractIdentifier; + use crate::vm::ClarityCostFunction; + use crate::vm::ClarityName; use crate::vm::ClarityVersion; + use crate::vm::MAX_CALL_STACK_DEPTH; + use stacks_common::types::StacksEpochId; + use std::collections::HashMap; + + #[derive(PartialEq, Debug)] + struct UnitTestTracker { + invoked_functions: Vec<(ClarityCostFunction, Vec)>, + invocation_count: u64, + cost_addition_count: u64, + } + impl UnitTestTracker { + pub fn new() -> Self { + UnitTestTracker { + invoked_functions: vec![], + invocation_count: 0, + cost_addition_count: 0, + } + } + } + impl CostTracker for UnitTestTracker { + fn compute_cost( + &mut self, + cost_f: ClarityCostFunction, + input: &[u64], + ) -> std::result::Result { + self.invoked_functions.push((cost_f, input.to_vec())); + self.invocation_count += 1; + Ok(ExecutionCost::zero()) + } + fn add_cost(&mut self, _cost: ExecutionCost) -> std::result::Result<(), CostErrors> { + self.cost_addition_count += 1; + Ok(()) + } + fn add_memory(&mut self, _memory: u64) -> std::result::Result<(), CostErrors> { + Ok(()) + } + fn drop_memory(&mut self, _memory: u64) {} + fn reset_memory(&mut self) {} + fn short_circuit_contract_call( + &mut self, + _contract: &QualifiedContractIdentifier, + _function: &ClarityName, + _input: &[u64], + ) -> Result { + Ok(false) + } + } + + #[test] + fn test_cost_tracking_deep_contracts_2_05() { + let clarity_version = ClarityVersion::Clarity1; + let stack_limit = + (AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64) + 1) as usize; + let exceeds_stack_depth_tuple = format!( + "{}u1 {}", + "{ a : ".repeat(stack_limit + 1), + "} ".repeat(stack_limit + 1) + ); + + // for deep lists, a test like this works: + // it can assert a limit, that you can also verify + // by disabling `VaryStackDepthChecker` and arbitrarily bumping up the parser lexer limits + // and see that it produces the same result + let exceeds_stack_depth_list = format!( + "{}u1 {}", + "(list ".repeat(stack_limit + 1), + ")".repeat(stack_limit + 1) + ); + + // with old rules, this is just ExpressionStackDepthTooDeep + let mut cost_track = UnitTestTracker::new(); + let err = build_ast_with_rules( + &QualifiedContractIdentifier::transient(), + &exceeds_stack_depth_list, + &mut cost_track, + clarity_version, + StacksEpochId::Epoch2_05, + ASTRules::Typical, + ) + .expect_err("Contract should error in parsing"); + + let expected_err = ParseErrors::ExpressionStackDepthTooDeep; + let expected_list_cost_state = UnitTestTracker { + invoked_functions: vec![(ClarityCostFunction::AstParse, vec![500])], + invocation_count: 1, + cost_addition_count: 1, + }; + + assert_eq!(&expected_err, &err.err); + assert_eq!(expected_list_cost_state, cost_track); + + // with new rules, this is now VaryExpressionStackDepthTooDeep + let mut cost_track = UnitTestTracker::new(); + let err = build_ast_with_rules( + &QualifiedContractIdentifier::transient(), + &exceeds_stack_depth_list, + &mut cost_track, + clarity_version, + StacksEpochId::Epoch2_05, + ASTRules::PrecheckSize, + ) + .expect_err("Contract should error in parsing"); + + let expected_err = ParseErrors::VaryExpressionStackDepthTooDeep; + let expected_list_cost_state = UnitTestTracker { + invoked_functions: vec![(ClarityCostFunction::AstParse, vec![500])], + invocation_count: 1, + cost_addition_count: 1, + }; + + assert_eq!(&expected_err, &err.err); + assert_eq!(expected_list_cost_state, cost_track); + + // you cannot do the same for tuples! + // in ASTRules::Typical, this passes + let mut cost_track = UnitTestTracker::new(); + let _ = build_ast_with_rules( + &QualifiedContractIdentifier::transient(), + &exceeds_stack_depth_tuple, + &mut cost_track, + clarity_version, + StacksEpochId::Epoch2_05, + ASTRules::Typical, + ) + .expect("Contract should parse with ASTRules::Typical"); + + // this actually won't even error without + // the VaryStackDepthChecker changes. + let mut cost_track = UnitTestTracker::new(); + let err = build_ast_with_rules( + &QualifiedContractIdentifier::transient(), + &exceeds_stack_depth_tuple, + &mut cost_track, + clarity_version, + StacksEpochId::Epoch2_05, + ASTRules::PrecheckSize, + ) + .expect_err("Contract should error in parsing with ASTRules::PrecheckSize"); + + let expected_err = ParseErrors::VaryExpressionStackDepthTooDeep; + let expected_list_cost_state = UnitTestTracker { + invoked_functions: vec![(ClarityCostFunction::AstParse, vec![571])], + invocation_count: 1, + cost_addition_count: 1, + }; + + assert_eq!(&expected_err, &err.err); + assert_eq!(expected_list_cost_state, cost_track); + } + + #[test] + fn test_cost_tracking_deep_contracts_2_1() { + for clarity_version in &[ClarityVersion::Clarity1, ClarityVersion::Clarity2] { + let stack_limit = + (AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64) + 1) as usize; + let exceeds_stack_depth_tuple = format!( + "{}u1 {}", + "{ a : ".repeat(stack_limit + 1), + "} ".repeat(stack_limit + 1) + ); + + // for deep lists, a test like this works: + // it can assert a limit, that you can also verify + // by disabling `VaryStackDepthChecker` and arbitrarily bumping up the parser lexer limits + // and see that it produces the same result + let exceeds_stack_depth_list = format!( + "{}u1 {}", + "(list ".repeat(stack_limit + 1), + ")".repeat(stack_limit + 1) + ); + + // with old rules, this is just ExpressionStackDepthTooDeep + let mut cost_track = UnitTestTracker::new(); + let err = build_ast_with_rules( + &QualifiedContractIdentifier::transient(), + &exceeds_stack_depth_list, + &mut cost_track, + *clarity_version, + StacksEpochId::Epoch21, + ASTRules::Typical, + ) + .expect_err("Contract should error in parsing"); + + let expected_err = ParseErrors::ExpressionStackDepthTooDeep; + let expected_list_cost_state = UnitTestTracker { + invoked_functions: vec![(ClarityCostFunction::AstParse, vec![500])], + invocation_count: 1, + cost_addition_count: 1, + }; + + assert_eq!(&expected_err, &err.err); + assert_eq!(expected_list_cost_state, cost_track); + + // in 2.1, this is still ExpressionStackDepthTooDeep + let mut cost_track = UnitTestTracker::new(); + let err = build_ast_with_rules( + &QualifiedContractIdentifier::transient(), + &exceeds_stack_depth_list, + &mut cost_track, + *clarity_version, + StacksEpochId::Epoch21, + ASTRules::PrecheckSize, + ) + .expect_err("Contract should error in parsing"); + + let expected_err = ParseErrors::ExpressionStackDepthTooDeep; + let expected_list_cost_state = UnitTestTracker { + invoked_functions: vec![(ClarityCostFunction::AstParse, vec![500])], + invocation_count: 1, + cost_addition_count: 1, + }; + + assert_eq!(&expected_err, &err.err); + assert_eq!(expected_list_cost_state, cost_track); + + // in 2.1, ASTRules::Typical is ignored -- this still fails to parse + let mut cost_track = UnitTestTracker::new(); + let _ = build_ast_with_rules( + &QualifiedContractIdentifier::transient(), + &exceeds_stack_depth_tuple, + &mut cost_track, + *clarity_version, + StacksEpochId::Epoch21, + ASTRules::Typical, + ) + .expect_err("Contract should error in parsing"); + + let expected_err = ParseErrors::ExpressionStackDepthTooDeep; + let expected_list_cost_state = UnitTestTracker { + invoked_functions: vec![(ClarityCostFunction::AstParse, vec![571])], + invocation_count: 1, + cost_addition_count: 1, + }; + + assert_eq!(&expected_err, &err.err); + assert_eq!(expected_list_cost_state, cost_track); + + // in 2.1, ASTRules::PrecheckSize is still ignored -- this still fails to parse + let mut cost_track = UnitTestTracker::new(); + let err = build_ast_with_rules( + &QualifiedContractIdentifier::transient(), + &exceeds_stack_depth_tuple, + &mut cost_track, + *clarity_version, + StacksEpochId::Epoch21, + ASTRules::PrecheckSize, + ) + .expect_err("Contract should error in parsing"); + + let expected_err = ParseErrors::ExpressionStackDepthTooDeep; + let expected_list_cost_state = UnitTestTracker { + invoked_functions: vec![(ClarityCostFunction::AstParse, vec![571])], + invocation_count: 1, + cost_addition_count: 1, + }; + + assert_eq!(&expected_err, &err.err); + assert_eq!(expected_list_cost_state, cost_track); + } + } #[test] fn test_expression_identification_tuples() { diff --git a/clarity/src/vm/ast/parser/mod.rs b/clarity/src/vm/ast/parser/mod.rs index ae6adc7cf..ced9f3aaf 100644 --- a/clarity/src/vm/ast/parser/mod.rs +++ b/clarity/src/vm/ast/parser/mod.rs @@ -1,2 +1,18 @@ +// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation +// Copyright (C) 2020 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 . + pub mod v1; pub mod v2; diff --git a/clarity/src/vm/ast/parser/v1.rs b/clarity/src/vm/ast/parser/v1.rs index 45c9541e2..68679dbd6 100644 --- a/clarity/src/vm/ast/parser/v1.rs +++ b/clarity/src/vm/ast/parser/v1.rs @@ -28,6 +28,9 @@ use stacks_common::util::hash::hex_bytes; use std::cmp; use std::convert::TryInto; +use crate::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; +use crate::vm::MAX_CALL_STACK_DEPTH; + pub enum LexItem { LeftParen, RightParen, @@ -108,14 +111,8 @@ fn get_lines_at(input: &str) -> Vec { lazy_static! { pub static ref CLARITY_NAME_REGEX_STRING: String = format!(r#"([[:word:]]|[-!?+<>=/*]){{1,{}}}"#, MAX_STRING_LEN); -} -pub fn lex(input: &str) -> ParseResult> { - // Aaron: I'd like these to be static, but that'd require using - // lazy_static (or just hand implementing that), and I'm not convinced - // it's worth either (1) an extern macro, or (2) the complexity of hand implementing. - - let lex_matchers: &[LexMatcher] = &[ + static ref lex_matchers: Vec = vec![ LexMatcher::new( r##"u"(?P((\\")|([[ -~]&&[^"]]))*)""##, TokenType::StringUTF8Literal, @@ -171,7 +168,10 @@ pub fn lex(input: &str) -> ParseResult> { TokenType::Variable, ), ]; +} +/// Lex the contract, permitting nesting of lists and tuples up to `max_nesting`. +fn inner_lex(input: &str, max_nesting: u64) -> ParseResult> { let mut context = LexContext::ExpectNothing; let mut line_indices = get_lines_at(input); @@ -182,6 +182,9 @@ pub fn lex(input: &str) -> ParseResult> { let mut munch_index = 0; let mut column_pos: u32 = 1; let mut did_match = true; + + let mut nesting_depth = 0; + while did_match && munch_index < input.len() { if let Some(next_line_ix) = next_line_break { if munch_index > next_line_ix { @@ -239,9 +242,19 @@ pub fn lex(input: &str) -> ParseResult> { let token = match matcher.handler { TokenType::LParens => { context = LexContext::ExpectNothing; + nesting_depth += 1; + if nesting_depth > max_nesting { + return Err(ParseError::new( + ParseErrors::VaryExpressionStackDepthTooDeep, + )); + } Ok(LexItem::LeftParen) } - TokenType::RParens => Ok(LexItem::RightParen), + TokenType::RParens => { + // if this underflows, the contract is invalid anyway + nesting_depth = nesting_depth.saturating_sub(1); + Ok(LexItem::RightParen) + } TokenType::Whitespace => { context = LexContext::ExpectNothing; Ok(LexItem::Whitespace) @@ -258,9 +271,19 @@ pub fn lex(input: &str) -> ParseResult> { } TokenType::LCurly => { context = LexContext::ExpectNothing; + nesting_depth += 1; + if nesting_depth > max_nesting { + return Err(ParseError::new( + ParseErrors::VaryExpressionStackDepthTooDeep, + )); + } Ok(LexItem::LeftCurly) } - TokenType::RCurly => Ok(LexItem::RightCurly), + TokenType::RCurly => { + // if this underflows, the contract is invalid anyway + nesting_depth = nesting_depth.saturating_sub(1); + Ok(LexItem::RightCurly) + } TokenType::Variable => { let value = get_value_or_err(current_slice, captures)?; if value.contains("#") { @@ -411,6 +434,13 @@ pub fn lex(input: &str) -> ParseResult> { } } +pub fn lex(input: &str) -> ParseResult> { + inner_lex( + input, + AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64) + 1, + ) +} + fn unescape_ascii_chars(escaped_str: String, allow_unicode_escape: bool) -> ParseResult { let mut unescaped_str = String::new(); let mut chars = escaped_str.chars().into_iter(); @@ -673,7 +703,15 @@ pub fn parse_lexed(mut input: Vec<(LexItem, u32, u32)>) -> ParseResult ParseResult> { - let lexed = lex(input)?; + let lexed = inner_lex( + input, + AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64) + 1, + )?; + parse_lexed(lexed) +} + +pub fn parse_no_stack_limit(input: &str) -> ParseResult> { + let lexed = inner_lex(input, u64::MAX)?; parse_lexed(lexed) } @@ -681,11 +719,13 @@ pub fn parse(input: &str) -> ParseResult> { mod test { use crate::vm::ast; use crate::vm::ast::errors::{ParseError, ParseErrors}; + use crate::vm::ast::stack_depth_checker::AST_CALL_STACK_DEPTH_BUFFER; use crate::vm::representations::{PreSymbolicExpression, PreSymbolicExpressionType}; use crate::vm::types::TraitIdentifier; use crate::vm::types::{ CharType, PrincipalData, QualifiedContractIdentifier, SequenceData, Value, }; + use crate::vm::MAX_CALL_STACK_DEPTH; fn make_atom( x: &str, @@ -1003,6 +1043,18 @@ mod test { let string_with_multiple_slashes = r#" "hello\\\"world" "#; + let stack_limit = + (AST_CALL_STACK_DEPTH_BUFFER + (MAX_CALL_STACK_DEPTH as u64) + 1) as usize; + let exceeds_stack_depth_tuple = format!( + "{}u1 {}", + "{ a : ".repeat(stack_limit + 1), + "} ".repeat(stack_limit + 1) + ); + let exceeds_stack_depth_list = format!( + "{}u1 {}", + "(list ".repeat(stack_limit + 1), + ")".repeat(stack_limit + 1) + ); assert!( match ast::parser::v1::parse(&split_tokens).unwrap_err().err { @@ -1227,5 +1279,25 @@ mod test { _ => false, } ); + + assert!(match ast::parser::v1::parse(&exceeds_stack_depth_tuple) + .unwrap_err() + .err + { + ParseErrors::VaryExpressionStackDepthTooDeep => true, + x => { + panic!("Got {:?}", &x); + } + }); + + assert!(match ast::parser::v1::parse(&exceeds_stack_depth_list) + .unwrap_err() + .err + { + ParseErrors::VaryExpressionStackDepthTooDeep => true, + x => { + panic!("Got {:?}", &x); + } + }); } } diff --git a/clarity/src/vm/ast/stack_depth_checker.rs b/clarity/src/vm/ast/stack_depth_checker.rs index a9af745c2..e9a62d8ec 100644 --- a/clarity/src/vm/ast/stack_depth_checker.rs +++ b/clarity/src/vm/ast/stack_depth_checker.rs @@ -18,6 +18,7 @@ use crate::vm::ast::errors::{ParseError, ParseErrors, ParseResult}; use crate::vm::ast::types::{BuildASTPass, ContractAST}; use crate::vm::representations::PreSymbolicExpression; use crate::vm::representations::PreSymbolicExpressionType::List; +use crate::vm::representations::PreSymbolicExpressionType::Tuple; use crate::vm::{ClarityVersion, MAX_CALL_STACK_DEPTH}; @@ -50,3 +51,29 @@ impl BuildASTPass for StackDepthChecker { check(&contract_ast.pre_expressions, 0) } } + +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()); + } + for expression in args.iter() { + match expression.pre_expr { + List(ref exprs) => check_vary(exprs, depth + 1), + Tuple(ref exprs) => check_vary(exprs, depth + 1), + _ => { + // Other symbolic expressions don't have depth + // impacts. + Ok(()) + } + }?; + } + Ok(()) +} + +pub struct VaryStackDepthChecker; + +impl BuildASTPass for VaryStackDepthChecker { + fn run_pass(contract_ast: &mut ContractAST, _version: ClarityVersion) -> ParseResult<()> { + check_vary(&contract_ast.pre_expressions, 0) + } +} diff --git a/clarity/src/vm/ast/traits_resolver/mod.rs b/clarity/src/vm/ast/traits_resolver/mod.rs index 84ab59c45..24644e44a 100644 --- a/clarity/src/vm/ast/traits_resolver/mod.rs +++ b/clarity/src/vm/ast/traits_resolver/mod.rs @@ -153,7 +153,9 @@ impl TraitsResolver { | DefineFunctions::PersistedVariable | DefineFunctions::FungibleToken | DefineFunctions::NonFungibleToken => { - self.probe_for_generics(args[1..].to_vec(), &mut referenced_traits, false)?; + if args.len() > 0 { + self.probe_for_generics(args[1..].to_vec(), &mut referenced_traits, false)?; + } } }; } diff --git a/clarity/src/vm/clarity.rs b/clarity/src/vm/clarity.rs index 69667925c..aeca615e5 100644 --- a/clarity/src/vm/clarity.rs +++ b/clarity/src/vm/clarity.rs @@ -2,6 +2,7 @@ use crate::vm::analysis; use crate::vm::analysis::ContractAnalysis; use crate::vm::analysis::{AnalysisDatabase, CheckError, CheckErrors}; use crate::vm::ast::errors::{ParseError, ParseErrors}; +use crate::vm::ast::ASTRules; use crate::vm::ast::ContractAST; use crate::vm::contexts::Environment; use crate::vm::contexts::{AssetMap, OwnedEnvironment}; @@ -181,16 +182,18 @@ pub trait TransactionConnection: ClarityConnection { identifier: &QualifiedContractIdentifier, clarity_version: ClarityVersion, contract_content: &str, + ast_rules: ASTRules, ) -> Result<(ContractAST, ContractAnalysis), Error> { let epoch_id = self.get_epoch(); self.with_analysis_db(|db, mut cost_track| { - let ast_result = ast::build_ast( + let ast_result = ast::build_ast_with_rules( identifier, contract_content, &mut cost_track, clarity_version, epoch_id, + ast_rules, ); let mut contract_ast = match ast_result { diff --git a/clarity/src/vm/contexts.rs b/clarity/src/vm/contexts.rs index 6073b39ab..fc272faf3 100644 --- a/clarity/src/vm/contexts.rs +++ b/clarity/src/vm/contexts.rs @@ -20,6 +20,7 @@ use std::fmt; use std::mem::replace; use crate::vm::ast; +use crate::vm::ast::ASTRules; use crate::vm::ast::ContractAST; use crate::vm::callables::{DefinedFunction, FunctionIdentifier}; use crate::vm::contracts::Contract; @@ -43,7 +44,6 @@ use crate::vm::types::{ TraitIdentifier, TypeSignature, Value, }; use crate::vm::{eval, is_reserved}; - use crate::{types::chainstate::StacksBlockId, types::StacksEpochId}; use crate::vm::costs::cost_functions::ClarityCostFunction; @@ -687,12 +687,15 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { contract_identifier: QualifiedContractIdentifier, contract_content: &str, sponsor: Option, + ast_rules: ASTRules, ) -> Result<((), AssetMap, Vec)> { self.execute_in_env( contract_identifier.issuer.clone().into(), sponsor.clone(), None, - |exec_env| exec_env.initialize_contract(contract_identifier, contract_content), + |exec_env| { + exec_env.initialize_contract(contract_identifier, contract_content, ast_rules) + }, ) } @@ -702,6 +705,7 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { version: ClarityVersion, contract_content: &str, sponsor: Option, + ast_rules: ASTRules, ) -> Result<((), AssetMap, Vec)> { self.execute_in_env( contract_identifier.issuer.clone().into(), @@ -710,7 +714,9 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { QualifiedContractIdentifier::transient(), version, )), - |exec_env| exec_env.initialize_contract(contract_identifier, contract_content), + |exec_env| { + exec_env.initialize_contract(contract_identifier, contract_content, ast_rules) + }, ) } @@ -805,19 +811,29 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { ) } - pub fn eval_read_only( + pub fn eval_read_only_with_rules( &mut self, contract: &QualifiedContractIdentifier, program: &str, + ast_rules: ast::ASTRules, ) -> Result<(Value, AssetMap, Vec)> { self.execute_in_env( QualifiedContractIdentifier::transient().issuer.into(), None, None, - |exec_env| exec_env.eval_read_only(contract, program), + |exec_env| exec_env.eval_read_only_with_rules(contract, program, ast_rules), ) } + #[cfg(any(test, feature = "testing"))] + pub fn eval_read_only( + &mut self, + contract: &QualifiedContractIdentifier, + program: &str, + ) -> Result<(Value, AssetMap, Vec)> { + self.eval_read_only_with_rules(contract, program, ast::ASTRules::Typical) + } + pub fn begin(&mut self) { self.context.begin(); } @@ -970,19 +986,21 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { ) } - pub fn eval_read_only( + pub fn eval_read_only_with_rules( &mut self, contract_identifier: &QualifiedContractIdentifier, program: &str, + rules: ast::ASTRules, ) -> Result { let clarity_version = self.contract_context.clarity_version.clone(); - let parsed = ast::build_ast( + let parsed = ast::build_ast_with_rules( contract_identifier, program, self, clarity_version, self.global_context.epoch_id, + rules, )? .expressions; @@ -1018,18 +1036,29 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { result } - pub fn eval_raw(&mut self, program: &str) -> Result { + #[cfg(any(test, feature = "testing"))] + pub fn eval_read_only( + &mut self, + contract_identifier: &QualifiedContractIdentifier, + program: &str, + ) -> Result { + self.eval_read_only_with_rules(contract_identifier, program, ast::ASTRules::Typical) + } + + pub fn eval_raw_with_rules(&mut self, program: &str, rules: ast::ASTRules) -> Result { let contract_id = QualifiedContractIdentifier::transient(); let clarity_version = self.contract_context.clarity_version.clone(); - let parsed = ast::build_ast( + let parsed = ast::build_ast_with_rules( &contract_id, program, self, clarity_version, self.global_context.epoch_id, + rules, )? .expressions; + if parsed.len() < 1 { return Err(RuntimeErrorType::ParseError( "Expected a program of at least length 1".to_string(), @@ -1041,6 +1070,11 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { result } + #[cfg(any(test, feature = "testing"))] + pub fn eval_raw(&mut self, program: &str) -> Result { + self.eval_raw_with_rules(program, ast::ASTRules::Typical) + } + /// Used only for contract-call! cost short-circuiting. Once the short-circuited cost /// has been evaluated and assessed, the contract-call! itself is executed "for free". pub fn run_free(&mut self, to_run: F) -> A @@ -1224,15 +1258,17 @@ impl<'a, 'b, 'hooks> Environment<'a, 'b, 'hooks> { &mut self, contract_identifier: QualifiedContractIdentifier, contract_content: &str, + ast_rules: ASTRules, ) -> Result<()> { let clarity_version = self.contract_context.clarity_version.clone(); - let contract_ast = ast::build_ast( + let contract_ast = ast::build_ast_with_rules( &contract_identifier, contract_content, self, clarity_version, self.global_context.epoch_id, + ast_rules, )?; self.initialize_contract_from_ast( contract_identifier, diff --git a/clarity/src/vm/database/clarity_db.rs b/clarity/src/vm/database/clarity_db.rs index 7871ba04e..91d2eca80 100644 --- a/clarity/src/vm/database/clarity_db.rs +++ b/clarity/src/vm/database/clarity_db.rs @@ -18,6 +18,7 @@ use std::collections::{HashMap, VecDeque}; use std::convert::{TryFrom, TryInto}; use crate::vm::analysis::{AnalysisDatabase, ContractAnalysis}; +use crate::vm::ast::ASTRules; use crate::vm::contracts::Contract; use crate::vm::costs::CostOverflowingMath; use crate::vm::costs::ExecutionCost; @@ -145,6 +146,8 @@ pub trait BurnStateDB { fn get_stacks_epoch(&self, height: u32) -> Option; fn get_stacks_epoch_by_epoch_id(&self, epoch_id: &StacksEpochId) -> Option; + fn get_ast_rules(&self, height: u32) -> ASTRules; + /// Get the PoX payout addresses for a given burnchain block fn get_pox_payout_addrs( &self, @@ -235,6 +238,11 @@ impl BurnStateDB for &dyn BurnStateDB { fn get_stacks_epoch_by_epoch_id(&self, epoch_id: &StacksEpochId) -> Option { (*self).get_stacks_epoch_by_epoch_id(epoch_id) } + + fn get_ast_rules(&self, height: u32) -> ASTRules { + (*self).get_ast_rules(height) + } + fn get_pox_payout_addrs( &self, height: u32, @@ -377,6 +385,10 @@ impl BurnStateDB for NullBurnStateDB { ) -> Option<(Vec, u128)> { None } + + fn get_ast_rules(&self, _height: u32) -> ASTRules { + ASTRules::Typical + } } impl<'a> ClarityDatabase<'a> { @@ -741,7 +753,9 @@ impl<'a> ClarityDatabase<'a> { /// Get the last-known burnchain block height. /// Note that this is _not_ the burnchain height in which this block was mined! - /// This is the burnchain block height of its parent. + /// 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) -> u32 { let cur_stacks_height = self.store.get_current_block_height(); let last_mined_bhh = if cur_stacks_height == 0 { diff --git a/clarity/src/vm/docs/contracts.rs b/clarity/src/vm/docs/contracts.rs index fc04192e4..23cd25f65 100644 --- a/clarity/src/vm/docs/contracts.rs +++ b/clarity/src/vm/docs/contracts.rs @@ -6,6 +6,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::iter::FromIterator; use crate::types::StacksEpochId; +use crate::vm::ast::{build_ast_with_rules, ASTRules}; use crate::vm::contexts::GlobalContext; use crate::vm::costs::LimitedCostTracker; use crate::vm::database::MemoryBackingStore; @@ -80,12 +81,13 @@ fn doc_execute(program: &str) -> Result, vm::Error> { DOCS_GENERATION_EPOCH, ); global_context.execute(|g| { - let parsed = vm::ast::build_ast( + let parsed = vm::ast::build_ast_with_rules( &contract_id, program, &mut (), ClarityVersion::latest(), StacksEpochId::latest(), + ASTRules::PrecheckSize, )? .expressions; vm::eval_all(&parsed, &mut contract_context, g, None) diff --git a/clarity/src/vm/docs/mod.rs b/clarity/src/vm/docs/mod.rs index bb481bbef..469f2eb02 100644 --- a/clarity/src/vm/docs/mod.rs +++ b/clarity/src/vm/docs/mod.rs @@ -521,7 +521,13 @@ const POW_API: SimpleFunctionAPI = SimpleFunctionAPI { name: None, snippet: "pow ${1:expr-1} ${2:expr-2}", signature: "(pow i1 i2)", - description: "Returns the result of raising `i1` to the power of `i2`. In the event of an _overflow_, throws a runtime error.", + description: "Returns the result of raising `i1` to the power of `i2`. In the event of an _overflow_, throws a runtime error. +Note: Corner cases are handled with the following rules: + * if both `i1` and `i2` are `0`, return `1` + * if `i1` is `1`, return `1` + * if `i1` is `0`, return `0` + * if `i2` is `1`, return `i1` + * if `i2` is negative or greater than `u32::MAX`, throw a runtime error", example: "(pow 2 3) ;; Returns 8 (pow 2 2) ;; Returns 4 (pow 7 1) ;; Returns 7 @@ -2465,6 +2471,7 @@ mod test { vm::database::{ClarityDatabase, MemoryBackingStore}, }; + use crate::vm::ast::ASTRules; use crate::vm::costs::ExecutionCost; use stacks_common::consts::CHAIN_ID_TESTNET; @@ -2588,6 +2595,9 @@ mod test { fn get_stacks_epoch_by_epoch_id(&self, epoch_id: &StacksEpochId) -> Option { self.get_stacks_epoch(0) } + fn get_ast_rules(&self, height: u32) -> ASTRules { + ASTRules::PrecheckSize + } fn get_pox_payout_addrs( &self, height: u32, @@ -2856,11 +2866,21 @@ mod test { ) .unwrap(); - env.initialize_contract(contract_id, &token_contract_content, None) - .unwrap(); + env.initialize_contract( + contract_id, + &token_contract_content, + None, + ASTRules::PrecheckSize, + ) + .unwrap(); - env.initialize_contract(trait_def_id, super::DEFINE_TRAIT_API.example, None) - .unwrap(); + env.initialize_contract( + trait_def_id, + super::DEFINE_TRAIT_API.example, + None, + ASTRules::PrecheckSize, + ) + .unwrap(); } let example = &func_api.example; diff --git a/clarity/src/vm/mod.rs b/clarity/src/vm/mod.rs index a1888ccb7..fa7a1d90b 100644 --- a/clarity/src/vm/mod.rs +++ b/clarity/src/vm/mod.rs @@ -85,11 +85,12 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use self::analysis::ContractAnalysis; +use self::ast::ASTRules; use self::ast::ContractAST; use self::costs::ExecutionCost; use self::diagnostic::Diagnostic; -const MAX_CALL_STACK_DEPTH: usize = 64; +pub const MAX_CALL_STACK_DEPTH: usize = 64; #[derive(Debug, Clone)] pub struct ParsedContract { @@ -487,14 +488,17 @@ pub fn execute_on_network(program: &str, use_mainnet: bool) -> Result Result> { use crate::vm::database::MemoryBackingStore; @@ -527,8 +532,15 @@ pub fn execute_with_parameters( epoch, ); global_context.execute(|g| { - let parsed = - ast::build_ast(&contract_id, program, &mut (), clarity_version, epoch)?.expressions; + let parsed = ast::build_ast_with_rules( + &contract_id, + program, + &mut (), + clarity_version, + epoch, + ast_rules, + )? + .expressions; eval_all(&parsed, &mut contract_context, g, None) }) } @@ -536,7 +548,13 @@ 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> { - execute_with_parameters(program, version, StacksEpochId::Epoch20, false) + execute_with_parameters( + program, + version, + StacksEpochId::Epoch20, + ast::ASTRules::PrecheckSize, + false, + ) } /// Execute for test in Clarity1, Epoch20, testnet. @@ -546,6 +564,7 @@ pub fn execute(program: &str) -> Result> { program, ClarityVersion::Clarity1, StacksEpochId::Epoch20, + ast::ASTRules::PrecheckSize, false, ) } @@ -557,6 +576,7 @@ pub fn execute_v2(program: &str) -> Result> { program, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false, ) } diff --git a/clarity/src/vm/test_util/mod.rs b/clarity/src/vm/test_util/mod.rs index 936f568fd..92d8daccd 100644 --- a/clarity/src/vm/test_util/mod.rs +++ b/clarity/src/vm/test_util/mod.rs @@ -1,3 +1,4 @@ +use crate::vm::ast::ASTRules; use crate::vm::costs::ExecutionCost; use crate::vm::database::{BurnStateDB, HeadersDB}; use crate::vm::execute as vm_execute; @@ -20,18 +21,22 @@ use stacks_common::types::{StacksEpochId, PEER_VERSION_EPOCH_2_0}; pub struct UnitTestBurnStateDB { pub epoch_id: StacksEpochId, + pub ast_rules: ASTRules, } pub struct UnitTestHeaderDB {} pub const TEST_HEADER_DB: UnitTestHeaderDB = UnitTestHeaderDB {}; pub const TEST_BURN_STATE_DB: UnitTestBurnStateDB = UnitTestBurnStateDB { epoch_id: StacksEpochId::Epoch20, + ast_rules: ASTRules::Typical, }; pub const TEST_BURN_STATE_DB_205: UnitTestBurnStateDB = UnitTestBurnStateDB { epoch_id: StacksEpochId::Epoch2_05, + ast_rules: ASTRules::PrecheckSize, }; pub const TEST_BURN_STATE_DB_21: UnitTestBurnStateDB = UnitTestBurnStateDB { epoch_id: StacksEpochId::Epoch21, + ast_rules: ASTRules::PrecheckSize, }; pub fn execute(s: &str) -> Value { @@ -225,6 +230,9 @@ impl BurnStateDB for UnitTestBurnStateDB { ) -> Option { None } + fn get_ast_rules(&self, _height: u32) -> ASTRules { + self.ast_rules + } fn get_pox_payout_addrs( &self, _height: u32, diff --git a/clarity/src/vm/tests/assets.rs b/clarity/src/vm/tests/assets.rs index 37f18ef19..12447437d 100644 --- a/clarity/src/vm/tests/assets.rs +++ b/clarity/src/vm/tests/assets.rs @@ -14,6 +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::ASTRules; use crate::vm::contexts::{AssetMap, AssetMapEntry, GlobalContext, OwnedEnvironment}; use crate::vm::contracts::Contract; use crate::vm::errors::{CheckErrors, Error, RuntimeErrorType}; @@ -180,10 +181,20 @@ fn test_native_stx_ops(owned_env: &mut OwnedEnvironment) { QualifiedContractIdentifier::new(p1_std_principal_data.clone(), "second".into()); owned_env - .initialize_contract(token_contract_id.clone(), contract, None) + .initialize_contract( + token_contract_id.clone(), + contract, + None, + ASTRules::PrecheckSize, + ) .unwrap(); owned_env - .initialize_contract(second_contract_id.clone(), contract_second, None) + .initialize_contract( + second_contract_id.clone(), + contract_second, + None, + ASTRules::PrecheckSize, + ) .unwrap(); owned_env.stx_faucet(&(p1_principal), u128::MAX - 1500); @@ -535,7 +546,12 @@ fn test_simple_token_system(owned_env: &mut OwnedEnvironment) { let contract_principal = PrincipalData::Contract(token_contract_id.clone()); owned_env - .initialize_contract(token_contract_id.clone(), tokens_contract, None) + .initialize_contract( + token_contract_id.clone(), + tokens_contract, + None, + ASTRules::PrecheckSize, + ) .unwrap(); let (result, asset_map, _events) = execute_transaction( @@ -826,7 +842,12 @@ fn test_total_supply(owned_env: &mut OwnedEnvironment) { let token_contract_id = QualifiedContractIdentifier::new(p1_std_principal_data.clone(), "tokens".into()); let err = owned_env - .initialize_contract(token_contract_id.clone(), bad_0, None) + .initialize_contract( + token_contract_id.clone(), + bad_0, + None, + ASTRules::PrecheckSize, + ) .unwrap_err(); assert!(match err { Error::Unchecked(CheckErrors::TypeValueError(_, _)) => true, @@ -834,7 +855,12 @@ fn test_total_supply(owned_env: &mut OwnedEnvironment) { }); let err = owned_env - .initialize_contract(token_contract_id.clone(), bad_1, None) + .initialize_contract( + token_contract_id.clone(), + bad_1, + None, + ASTRules::PrecheckSize, + ) .unwrap_err(); assert!(match err { Error::Unchecked(CheckErrors::TypeValueError(_, _)) => true, @@ -842,7 +868,12 @@ fn test_total_supply(owned_env: &mut OwnedEnvironment) { }); owned_env - .initialize_contract(token_contract_id.clone(), contract, None) + .initialize_contract( + token_contract_id.clone(), + contract, + None, + ASTRules::PrecheckSize, + ) .unwrap(); let (result, _asset_map, _events) = execute_transaction( @@ -909,13 +940,28 @@ fn test_overlapping_nfts(owned_env: &mut OwnedEnvironment) { QualifiedContractIdentifier::new(p1_std_principal_data.clone(), "names-2".into()); owned_env - .initialize_contract(tokens_contract_id.clone(), tokens_contract, None) + .initialize_contract( + tokens_contract_id.clone(), + tokens_contract, + None, + ASTRules::PrecheckSize, + ) .unwrap(); owned_env - .initialize_contract(names_contract_id.clone(), names_contract, None) + .initialize_contract( + names_contract_id.clone(), + names_contract, + None, + ASTRules::PrecheckSize, + ) .unwrap(); owned_env - .initialize_contract(names_2_contract_id.clone(), names_contract, None) + .initialize_contract( + names_2_contract_id.clone(), + names_contract, + None, + ASTRules::PrecheckSize, + ) .unwrap(); } @@ -967,13 +1013,23 @@ fn test_simple_naming_system(owned_env: &mut OwnedEnvironment) { let name_hash_cheap_0 = execute("(hash160 100001)"); owned_env - .initialize_contract(tokens_contract_id.clone(), tokens_contract, None) + .initialize_contract( + tokens_contract_id.clone(), + tokens_contract, + None, + ASTRules::PrecheckSize, + ) .unwrap(); let names_contract_id = QualifiedContractIdentifier::new(p1_std_principal_data.clone(), "names".into()); owned_env - .initialize_contract(names_contract_id.clone(), names_contract, None) + .initialize_contract( + names_contract_id.clone(), + names_contract, + None, + ASTRules::PrecheckSize, + ) .unwrap(); let (result, _asset_map, _events) = execute_transaction( diff --git a/clarity/src/vm/tests/contracts.rs b/clarity/src/vm/tests/contracts.rs index fb7555ed3..5f9b51ab6 100644 --- a/clarity/src/vm/tests/contracts.rs +++ b/clarity/src/vm/tests/contracts.rs @@ -24,6 +24,7 @@ use rstest_reuse::{self, *}; use crate::vm::ast; use crate::vm::ast::errors::ParseErrors; +use crate::vm::ast::ASTRules; use crate::vm::contexts::{Environment, GlobalContext, OwnedEnvironment}; use crate::vm::contracts::Contract; use crate::vm::costs::ExecutionCost; @@ -68,6 +69,38 @@ const FACTORIAL_CONTRACT: &str = "(define-map factorials { id: int } { current: (begin (init-factorial 1337 3) (init-factorial 8008 5))"; +const SIMPLE_TOKENS: &str = "(define-map tokens { account: principal } { balance: uint }) + (define-read-only (my-get-token-balance (account principal)) + (default-to u0 (get balance (map-get? tokens (tuple (account account)))))) + (define-read-only (explode (account principal)) + (map-delete tokens (tuple (account account)))) + (define-private (token-credit! (account principal) (amount uint)) + (if (<= amount u0) + (err \"must be positive\") + (let ((current-amount (my-get-token-balance account))) + (begin + (map-set tokens (tuple (account account)) + (tuple (balance (+ amount current-amount)))) + (ok 0))))) + (define-public (token-transfer (to principal) (amount uint)) + (let ((balance (my-get-token-balance tx-sender))) + (if (or (> amount balance) (<= amount u0)) + (err \"not enough balance\") + (begin + (map-set tokens (tuple (account tx-sender)) + (tuple (balance (- balance amount)))) + (token-credit! to amount))))) + (define-public (faucet) + (let ((original-sender tx-sender)) + (as-contract (print (token-transfer (print original-sender) u1))))) + (define-public (mint-after (block-to-release uint)) + (if (>= block-height block-to-release) + (faucet) + (err \"must be in the future\"))) + (begin (token-credit! 'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR u10000) + (token-credit! 'SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G u200) + (token-credit! .tokens u4))"; + fn get_principal() -> Value { StandardPrincipalData::transient().into() } @@ -110,7 +143,12 @@ fn test_get_block_info_eval() { let mut owned_env = OwnedEnvironment::new(marf.as_clarity_db()); let contract_identifier = QualifiedContractIdentifier::local("test-contract").unwrap(); owned_env - .initialize_contract(contract_identifier.clone(), contracts[i], None) + .initialize_contract( + contract_identifier.clone(), + contracts[i], + None, + ASTRules::PrecheckSize, + ) .unwrap(); let mut env = owned_env.get_exec_environment(None, None, &mut placeholder_context); @@ -163,11 +201,13 @@ fn test_contract_caller(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("contract-a").unwrap(), contract_a, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("contract-b").unwrap(), contract_b, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -306,11 +346,13 @@ fn test_tx_sponsor(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("contract-a").unwrap(), contract_a, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("contract-b").unwrap(), contract_b, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -360,11 +402,13 @@ fn test_fully_qualified_contract_call(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("contract-a").unwrap(), contract_a, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("contract-b").unwrap(), contract_b, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -421,6 +465,230 @@ fn test_fully_qualified_contract_call(owned_env: &mut OwnedEnvironment) { } } +fn test_simple_naming_system(owned_env: &mut OwnedEnvironment) { + let tokens_contract = SIMPLE_TOKENS; + + let names_contract = "(define-constant burn-address 'SP000000000000000000002Q6VF78) + (define-private (price-function (name int)) + (if (< name 100000) u1000 u100)) + + (define-map name-map + { name: int } { owner: principal }) + (define-map preorder-map + { name-hash: (buff 20) } + { buyer: principal, paid: uint }) + + (define-public (preorder + (name-hash (buff 20)) + (name-price uint)) + (let ((xfer-result (contract-call? .tokens token-transfer + burn-address name-price))) + (if (is-ok xfer-result) + (if + (map-insert preorder-map + (tuple (name-hash name-hash)) + (tuple (paid name-price) + (buyer tx-sender))) + (ok 0) (err 2)) + (if (is-eq (unwrap-err! xfer-result (err (- 1))) + \"not enough balance\") + (err 1) (err 3))))) + + (define-public (register + (recipient-principal principal) + (name int) + (salt int)) + (let ((preorder-entry + ;; preorder entry must exist! + (unwrap! (map-get? preorder-map + (tuple (name-hash (hash160 (xor name salt))))) (err 5))) + (name-entry + (map-get? name-map (tuple (name name))))) + (if (and + (is-none name-entry) + ;; preorder must have paid enough + (<= (price-function name) + (get paid preorder-entry)) + ;; preorder must have been the current principal + (is-eq tx-sender + (get buyer preorder-entry))) + (if (and + (map-insert name-map + (tuple (name name)) + (tuple (owner recipient-principal))) + (map-delete preorder-map + (tuple (name-hash (hash160 (xor name salt)))))) + (ok 0) + (err 3)) + (err 4))))"; + + let p1 = execute("'SZ2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQ9H6DPR"); + let p2 = execute("'SM2J6ZY48GV1EZ5V2V5RB9MP66SW86PYKKQVX8X0G"); + + let name_hash_expensive_0 = execute("(hash160 1)"); + let name_hash_expensive_1 = execute("(hash160 2)"); + let name_hash_cheap_0 = execute("(hash160 100001)"); + let mut placeholder_context = ContractContext::new( + QualifiedContractIdentifier::transient(), + ClarityVersion::Clarity2, + ); + + { + let mut env = owned_env.get_exec_environment(None, None, &mut placeholder_context); + + let contract_identifier = QualifiedContractIdentifier::local("tokens").unwrap(); + env.initialize_contract(contract_identifier, tokens_contract, ASTRules::PrecheckSize) + .unwrap(); + + let contract_identifier = QualifiedContractIdentifier::local("names").unwrap(); + env.initialize_contract(contract_identifier, names_contract, ASTRules::PrecheckSize) + .unwrap(); + } + + { + let mut env = owned_env.get_exec_environment( + Some(p2.clone().expect_principal()), + None, + &mut placeholder_context, + ); + + assert!(is_err_code( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "preorder", + &symbols_from_values(vec![name_hash_expensive_0.clone(), Value::UInt(1000)]), + false + ) + .unwrap(), + 1 + )); + } + + { + let mut env = owned_env.get_exec_environment( + Some(p1.clone().expect_principal()), + None, + &mut placeholder_context, + ); + assert!(is_committed( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "preorder", + &symbols_from_values(vec![name_hash_expensive_0.clone(), Value::UInt(1000)]), + false + ) + .unwrap() + )); + assert!(is_err_code( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "preorder", + &symbols_from_values(vec![name_hash_expensive_0.clone(), Value::UInt(1000)]), + false + ) + .unwrap(), + 2 + )); + } + + { + // shouldn't be able to register a name you didn't preorder! + let mut env = owned_env.get_exec_environment( + Some(p2.clone().expect_principal()), + None, + &mut placeholder_context, + ); + assert!(is_err_code( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "register", + &symbols_from_values(vec![p2.clone(), Value::Int(1), Value::Int(0)]), + false + ) + .unwrap(), + 4 + )); + } + + { + // should work! + let mut env = owned_env.get_exec_environment( + Some(p1.clone().expect_principal()), + None, + &mut placeholder_context, + ); + assert!(is_committed( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "register", + &symbols_from_values(vec![p2.clone(), Value::Int(1), Value::Int(0)]), + false + ) + .unwrap() + )); + } + + { + // try to underpay! + let mut env = owned_env.get_exec_environment( + Some(p2.clone().expect_principal()), + None, + &mut placeholder_context, + ); + assert!(is_committed( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "preorder", + &symbols_from_values(vec![name_hash_expensive_1.clone(), Value::UInt(100)]), + false + ) + .unwrap() + )); + assert!(is_err_code( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "register", + &symbols_from_values(vec![p2.clone(), Value::Int(2), Value::Int(0)]), + false + ) + .unwrap(), + 4 + )); + + // register a cheap name! + assert!(is_committed( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "preorder", + &symbols_from_values(vec![name_hash_cheap_0.clone(), Value::UInt(100)]), + false + ) + .unwrap() + )); + assert!(is_committed( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "register", + &symbols_from_values(vec![p2.clone(), Value::Int(100001), Value::Int(0)]), + false + ) + .unwrap() + )); + + // preorder must exist! + assert!(is_err_code( + &env.execute_contract( + &QualifiedContractIdentifier::local("names").unwrap(), + "register", + &symbols_from_values(vec![p2.clone(), Value::Int(100001), Value::Int(0)]), + false + ) + .unwrap(), + 5 + )); + } +} + fn test_simple_contract_call(owned_env: &mut OwnedEnvironment) { let contract_1 = FACTORIAL_CONTRACT; let contract_2 = "(define-public (proxy-compute) @@ -439,11 +707,11 @@ fn test_simple_contract_call(owned_env: &mut OwnedEnvironment) { ); let contract_identifier = QualifiedContractIdentifier::local("factorial-contract").unwrap(); - env.initialize_contract(contract_identifier, contract_1) + env.initialize_contract(contract_identifier, contract_1, ASTRules::PrecheckSize) .unwrap(); let contract_identifier = QualifiedContractIdentifier::local("proxy-compute").unwrap(); - env.initialize_contract(contract_identifier, contract_2) + env.initialize_contract(contract_identifier, contract_2, ASTRules::PrecheckSize) .unwrap(); let args = symbols_from_values(vec![]); @@ -518,11 +786,11 @@ fn test_aborts(owned_env: &mut OwnedEnvironment) { let mut env = owned_env.get_exec_environment(None, None, &mut placeholder_context); let contract_identifier = QualifiedContractIdentifier::local("contract-1").unwrap(); - env.initialize_contract(contract_identifier, contract_1) + env.initialize_contract(contract_identifier, contract_1, ASTRules::PrecheckSize) .unwrap(); let contract_identifier = QualifiedContractIdentifier::local("contract-2").unwrap(); - env.initialize_contract(contract_identifier, contract_2) + env.initialize_contract(contract_identifier, contract_2, ASTRules::PrecheckSize) .unwrap(); env.sender = Some(get_principal_as_principal_data()); @@ -629,8 +897,12 @@ fn test_factorial_contract(owned_env: &mut OwnedEnvironment) { let mut env = owned_env.get_exec_environment(None, None, &mut placeholder_context); let contract_identifier = QualifiedContractIdentifier::local("factorial").unwrap(); - env.initialize_contract(contract_identifier, FACTORIAL_CONTRACT) - .unwrap(); + env.initialize_contract( + contract_identifier, + FACTORIAL_CONTRACT, + ASTRules::PrecheckSize, + ) + .unwrap(); let tx_name = "compute"; let arguments_to_test = [ @@ -729,6 +1001,7 @@ fn test_at_unknown_block() { QualifiedContractIdentifier::local("contract").unwrap(), &contract, None, + ASTRules::PrecheckSize, ) .unwrap_err(); eprintln!("{}", err); @@ -758,6 +1031,7 @@ fn test_as_max_len() { QualifiedContractIdentifier::local("contract").unwrap(), &contract, None, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -781,7 +1055,7 @@ fn test_ast_stack_depth() { "; assert_eq!( vm_execute(program).unwrap_err(), - RuntimeErrorType::ASTError(ParseErrors::ExpressionStackDepthTooDeep.into()).into() + RuntimeErrorType::ASTError(ParseErrors::VaryExpressionStackDepthTooDeep.into()).into() ); } @@ -831,12 +1105,12 @@ fn test_cc_stack_depth() { let mut env = owned_env.get_exec_environment(None, None, &mut placeholder_context); let contract_identifier = QualifiedContractIdentifier::local("c-foo").unwrap(); - env.initialize_contract(contract_identifier, contract_one) + env.initialize_contract(contract_identifier, contract_one, ASTRules::PrecheckSize) .unwrap(); let contract_identifier = QualifiedContractIdentifier::local("c-bar").unwrap(); assert_eq!( - env.initialize_contract(contract_identifier, contract_two) + env.initialize_contract(contract_identifier, contract_two, ASTRules::PrecheckSize) .unwrap_err(), RuntimeErrorType::MaxStackDepthReached.into() ); @@ -873,12 +1147,12 @@ fn test_cc_trait_stack_depth() { let mut env = owned_env.get_exec_environment(None, None, &mut placeholder_context); let contract_identifier = QualifiedContractIdentifier::local("c-foo").unwrap(); - env.initialize_contract(contract_identifier, contract_one) + env.initialize_contract(contract_identifier, contract_one, ASTRules::PrecheckSize) .unwrap(); let contract_identifier = QualifiedContractIdentifier::local("c-bar").unwrap(); assert_eq!( - env.initialize_contract(contract_identifier, contract_two) + env.initialize_contract(contract_identifier, contract_two, ASTRules::PrecheckSize) .unwrap_err(), RuntimeErrorType::MaxStackDepthReached.into() ); @@ -895,6 +1169,7 @@ fn test_all() { test_contract_caller, test_tx_sponsor, test_fully_qualified_contract_call, + test_simple_naming_system, test_simple_contract_call, ]; for test in to_test.iter() { diff --git a/clarity/src/vm/tests/principals.rs b/clarity/src/vm/tests/principals.rs index 9d621898a..089a64719 100644 --- a/clarity/src/vm/tests/principals.rs +++ b/clarity/src/vm/tests/principals.rs @@ -1,3 +1,4 @@ +use crate::vm::ast::ASTRules; use crate::vm::execute_with_parameters; use crate::vm::types::BufferLength; use crate::vm::types::SequenceSubtype::{BufferType, StringType}; @@ -36,6 +37,7 @@ fn test_simple_is_standard_check_inputs() { wrong_type_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap_err(), @@ -52,6 +54,7 @@ fn test_simple_is_standard_testnet_cases() { testnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -63,6 +66,7 @@ fn test_simple_is_standard_testnet_cases() { testnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -76,6 +80,7 @@ fn test_simple_is_standard_testnet_cases() { testnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -87,6 +92,7 @@ fn test_simple_is_standard_testnet_cases() { testnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -100,6 +106,7 @@ fn test_simple_is_standard_testnet_cases() { testnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -111,6 +118,7 @@ fn test_simple_is_standard_testnet_cases() { testnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -124,6 +132,7 @@ fn test_simple_is_standard_testnet_cases() { testnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -135,6 +144,7 @@ fn test_simple_is_standard_testnet_cases() { testnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -150,6 +160,7 @@ fn test_simple_is_standard_mainnet_cases() { mainnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -161,6 +172,7 @@ fn test_simple_is_standard_mainnet_cases() { mainnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -174,6 +186,7 @@ fn test_simple_is_standard_mainnet_cases() { mainnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -185,6 +198,7 @@ fn test_simple_is_standard_mainnet_cases() { mainnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -198,6 +212,7 @@ fn test_simple_is_standard_mainnet_cases() { mainnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -209,6 +224,7 @@ fn test_simple_is_standard_mainnet_cases() { mainnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -222,6 +238,7 @@ fn test_simple_is_standard_mainnet_cases() { mainnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -233,6 +250,7 @@ fn test_simple_is_standard_mainnet_cases() { mainnet_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -250,6 +268,7 @@ fn test_simple_is_standard_undefined_cases() { invalid_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -261,6 +280,7 @@ fn test_simple_is_standard_undefined_cases() { invalid_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -274,6 +294,7 @@ fn test_simple_is_standard_undefined_cases() { invalid_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -285,6 +306,7 @@ fn test_simple_is_standard_undefined_cases() { invalid_addr_test, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -348,6 +370,7 @@ fn test_principal_destruct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -369,6 +392,7 @@ fn test_principal_destruct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -390,6 +414,7 @@ fn test_principal_destruct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -411,6 +436,7 @@ fn test_principal_destruct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -432,6 +458,7 @@ fn test_principal_destruct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -453,6 +480,7 @@ fn test_principal_destruct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -474,6 +502,7 @@ fn test_principal_destruct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -495,6 +524,7 @@ fn test_principal_destruct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -521,6 +551,7 @@ fn test_principal_destruct_bad_version_byte() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -542,6 +573,7 @@ fn test_principal_destruct_bad_version_byte() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -563,6 +595,7 @@ fn test_principal_destruct_bad_version_byte() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -584,6 +617,7 @@ fn test_principal_destruct_bad_version_byte() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -605,6 +639,7 @@ fn test_principal_destruct_bad_version_byte() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -626,6 +661,7 @@ fn test_principal_destruct_bad_version_byte() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -655,6 +691,7 @@ fn test_principal_construct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -674,6 +711,7 @@ fn test_principal_construct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -697,6 +735,7 @@ fn test_principal_construct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -720,6 +759,7 @@ fn test_principal_construct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -739,6 +779,7 @@ fn test_principal_construct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -758,6 +799,7 @@ fn test_principal_construct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -781,6 +823,7 @@ fn test_principal_construct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -804,6 +847,7 @@ fn test_principal_construct_good() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -870,6 +914,7 @@ fn test_principal_construct_version_byte_future() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -905,6 +950,7 @@ fn test_principal_construct_version_byte_future() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -931,6 +977,7 @@ fn test_principal_construct_check_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) ); @@ -944,6 +991,7 @@ fn test_principal_construct_check_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) ); @@ -956,6 +1004,7 @@ fn test_principal_construct_check_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap_err(), @@ -984,6 +1033,7 @@ fn test_principal_construct_check_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) ); @@ -1000,6 +1050,7 @@ fn test_principal_construct_response_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -1027,6 +1078,7 @@ fn test_principal_construct_response_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -1066,6 +1118,7 @@ fn test_principal_construct_response_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -1092,6 +1145,7 @@ fn test_principal_construct_response_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() @@ -1118,6 +1172,7 @@ fn test_principal_construct_response_errors() { input, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() diff --git a/clarity/src/vm/tests/simple_apply_eval.rs b/clarity/src/vm/tests/simple_apply_eval.rs index 172d9ac42..c97ab7943 100644 --- a/clarity/src/vm/tests/simple_apply_eval.rs +++ b/clarity/src/vm/tests/simple_apply_eval.rs @@ -21,7 +21,10 @@ use rstest::rstest; #[cfg(test)] use rstest_reuse::{self, *}; +#[cfg(test)] use crate::vm::ast::parse; + +use crate::vm::ast::ASTRules; use crate::vm::callables::DefinedFunction; use crate::vm::contexts::OwnedEnvironment; use crate::vm::costs::LimitedCostTracker; @@ -529,6 +532,7 @@ fn test_principal_of_fix() { principal_of_program, ClarityVersion::Clarity2, StacksEpochId::Epoch20, + ASTRules::PrecheckSize, true ) .unwrap() @@ -542,6 +546,7 @@ fn test_principal_of_fix() { principal_of_program, ClarityVersion::Clarity2, StacksEpochId::Epoch20, + ASTRules::PrecheckSize, false ) .unwrap() @@ -555,6 +560,7 @@ fn test_principal_of_fix() { principal_of_program, ClarityVersion::Clarity1, StacksEpochId::Epoch20, + ASTRules::PrecheckSize, true ) .unwrap() @@ -568,6 +574,7 @@ fn test_principal_of_fix() { principal_of_program, ClarityVersion::Clarity1, StacksEpochId::Epoch20, + ASTRules::PrecheckSize, false ) .unwrap() @@ -1261,6 +1268,7 @@ fn test_stx_ops_errors() { program, ClarityVersion::Clarity2, StacksEpochId::Epoch20, + ASTRules::PrecheckSize, false ) .unwrap_err() @@ -1611,6 +1619,7 @@ fn test_is_mainnet() { program, ClarityVersion::Clarity2, StacksEpochId::Epoch20, + ASTRules::PrecheckSize, true ) .unwrap() @@ -1630,6 +1639,7 @@ fn test_is_mainnet() { program, ClarityVersion::Clarity2, StacksEpochId::Epoch20, + ASTRules::PrecheckSize, false ) .unwrap() @@ -1654,6 +1664,7 @@ fn test_chain_id() { program, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, true ) .unwrap() @@ -1673,6 +1684,7 @@ fn test_chain_id() { program, ClarityVersion::Clarity2, StacksEpochId::Epoch21, + ASTRules::PrecheckSize, false ) .unwrap() diff --git a/clarity/src/vm/tests/traits.rs b/clarity/src/vm/tests/traits.rs index 0b74a174b..9bb7e399c 100644 --- a/clarity/src/vm/tests/traits.rs +++ b/clarity/src/vm/tests/traits.rs @@ -15,15 +15,16 @@ // along with this program. If not, see . use crate::vm::analysis::errors::CheckError; +use crate::vm::ast::ASTRules; use crate::vm::contexts::{Environment, GlobalContext, OwnedEnvironment}; use crate::vm::errors::{CheckErrors, Error, RuntimeErrorType}; use crate::vm::execute as vm_execute; +use crate::vm::tests::{execute, symbols_from_values, with_memory_environment}; use crate::vm::types::{ PrincipalData, QualifiedContractIdentifier, ResponseData, TypeSignature, Value, }; use std::convert::TryInto; -use crate::vm::tests::{execute, symbols_from_values, with_memory_environment}; use crate::vm::version::ClarityVersion; use crate::vm::ContractContext; @@ -76,11 +77,13 @@ fn test_dynamic_dispatch_by_defining_trait(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -128,11 +131,13 @@ fn test_dynamic_dispatch_pass_trait_nested_in_let(owned_env: &mut OwnedEnvironme env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -179,11 +184,13 @@ fn test_dynamic_dispatch_pass_trait(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -229,11 +236,13 @@ fn test_dynamic_dispatch_intra_contract_call(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("contract-defining-trait").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -282,16 +291,19 @@ fn test_dynamic_dispatch_by_implementing_imported_trait(owned_env: &mut OwnedEnv env.initialize_contract( QualifiedContractIdentifier::local("contract-defining-trait").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -342,16 +354,19 @@ fn test_dynamic_dispatch_by_implementing_imported_trait_mul_funcs( env.initialize_contract( QualifiedContractIdentifier::local("contract-defining-trait").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -397,16 +412,19 @@ fn test_dynamic_dispatch_by_importing_trait(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("contract-defining-trait").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -459,26 +477,31 @@ fn test_dynamic_dispatch_including_nested_trait(owned_env: &mut OwnedEnvironment env.initialize_contract( QualifiedContractIdentifier::local("contract-defining-nested-trait").unwrap(), contract_defining_nested_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("contract-defining-trait").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-nested-contract").unwrap(), target_nested_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -526,11 +549,13 @@ fn test_dynamic_dispatch_mismatched_args(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -577,11 +602,13 @@ fn test_dynamic_dispatch_mismatched_returned(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -631,11 +658,13 @@ fn test_reentrant_dynamic_dispatch(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -682,11 +711,13 @@ fn test_readwrite_dynamic_dispatch(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -733,11 +764,13 @@ fn test_readwrite_violation_dynamic_dispatch(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -791,21 +824,25 @@ fn test_bad_call_with_trait(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("defun").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatch").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("implem").unwrap(), impl_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("call").unwrap(), caller_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -851,21 +888,25 @@ fn test_good_call_with_trait(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("defun").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatch").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("implem").unwrap(), impl_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("call").unwrap(), caller_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -912,21 +953,25 @@ fn test_good_call_2_with_trait(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("defun").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatch").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("implem").unwrap(), impl_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("call").unwrap(), caller_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -977,16 +1022,19 @@ fn test_dynamic_dispatch_pass_literal_principal_as_trait_in_user_defined_functio env.initialize_contract( QualifiedContractIdentifier::local("contract-defining-trait").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -1033,16 +1081,19 @@ fn test_contract_of_value(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("defun").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatch").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("implem").unwrap(), impl_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -1093,16 +1144,19 @@ fn test_contract_of_no_impl(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("defun").unwrap(), contract_defining_trait, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("dispatch").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("implem").unwrap(), impl_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -1151,11 +1205,13 @@ fn test_return_trait_with_contract_of_wrapped_in_begin(owned_env: &mut OwnedEnvi env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -1202,11 +1258,13 @@ fn test_return_trait_with_contract_of_wrapped_in_let(owned_env: &mut OwnedEnviro env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } @@ -1251,11 +1309,13 @@ fn test_return_trait_with_contract_of(owned_env: &mut OwnedEnvironment) { env.initialize_contract( QualifiedContractIdentifier::local("dispatching-contract").unwrap(), dispatching_contract, + ASTRules::PrecheckSize, ) .unwrap(); env.initialize_contract( QualifiedContractIdentifier::local("target-contract").unwrap(), target_contract, + ASTRules::PrecheckSize, ) .unwrap(); } diff --git a/testnet/puppet-chain/.dockerignore b/contrib/tools/puppet-chain/.dockerignore similarity index 100% rename from testnet/puppet-chain/.dockerignore rename to contrib/tools/puppet-chain/.dockerignore diff --git a/contrib/tools/puppet-chain/Cargo.lock b/contrib/tools/puppet-chain/Cargo.lock new file mode 100644 index 000000000..e3d8d1088 --- /dev/null +++ b/contrib/tools/puppet-chain/Cargo.lock @@ -0,0 +1,1329 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher", +] + +[[package]] +name = "aes-gcm" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "anyhow" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-dup" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7427a12b8dc09291528cfb1da2447059adb4a257388c2acd6497a79d55cf6f7c" +dependencies = [ + "futures-io", + "simple-mutex", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5262ed948da60dd8956c6c5aca4d4163593dddb7b32d73267c93dab7b2e98940" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "num_cpus", + "once_cell", +] + +[[package]] +name = "async-h1" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8101020758a4fc3a7c326cb42aa99e9fa77cbfb76987c128ad956406fe1f70a7" +dependencies = [ + "async-channel", + "async-dup", + "async-std", + "futures-core", + "http-types", + "httparse", + "log", + "pin-project", +] + +[[package]] +name = "async-io" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07" +dependencies = [ + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" + +[[package]] +name = "atomic-waker" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blocking" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" +dependencies = [ + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", + "once_cell", +] + +[[package]] +name = "bumpalo" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" + +[[package]] +name = "cache-padded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "concurrent-queue" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +dependencies = [ + "cache-padded", +] + +[[package]] +name = "const_fn" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" + +[[package]] +name = "cookie" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +dependencies = [ + "aes-gcm", + "base64 0.13.0", + "hkdf", + "hmac", + "percent-encoding", + "rand 0.8.5", + "sha2", + "time", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + +[[package]] +name = "crossbeam-utils" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "crypto-mac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctor" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "event-listener" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "ghash" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gloo-timers" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "http-types" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" +dependencies = [ + "anyhow", + "async-channel", + "async-std", + "base64 0.13.0", + "cookie", + "futures-lite", + "infer", + "pin-project-lite", + "rand 0.7.3", + "serde", + "serde_json", + "serde_qs", + "serde_urlencoded", + "url", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "infer" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", + "value-bag", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "polling" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" +dependencies = [ + "cfg-if", + "libc", + "log", + "wepoll-ffi", + "winapi", +] + +[[package]] +name = "polyval" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +dependencies = [ + "cpuid-bool", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "puppet-chain" +version = "0.1.0" +dependencies = [ + "async-h1", + "async-std", + "base64 0.12.3", + "http-types", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_json", + "toml", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[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-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_qs" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" +dependencies = [ + "percent-encoding", + "serde", + "thiserror", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[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_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "simple-mutex" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38aabbeafa6f6dead8cebf246fe9fae1f9215c8d29b3a69f93bd62a9e4a3dcd6" +dependencies = [ + "event-listener", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "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", +] + +[[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", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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", + "version_check", + "winapi", +] + +[[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-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", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", + "serde", +] + +[[package]] +name = "value-bag" +version = "1.0.0-alpha.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" +dependencies = [ + "ctor", + "version_check", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "web-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wepoll-ffi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +dependencies = [ + "cc", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/testnet/puppet-chain/Cargo.toml b/contrib/tools/puppet-chain/Cargo.toml similarity index 91% rename from testnet/puppet-chain/Cargo.toml rename to contrib/tools/puppet-chain/Cargo.toml index d14a2c835..68bee027c 100644 --- a/testnet/puppet-chain/Cargo.toml +++ b/contrib/tools/puppet-chain/Cargo.toml @@ -14,3 +14,7 @@ serde_derive = "1" serde_json = { version = "1.0", features = ["arbitrary_precision"] } toml = "0.5" rand = "0.7.2" + +[workspace] +members = [ + "."] \ No newline at end of file diff --git a/testnet/puppet-chain/Dockerfile b/contrib/tools/puppet-chain/Dockerfile similarity index 100% rename from testnet/puppet-chain/Dockerfile rename to contrib/tools/puppet-chain/Dockerfile diff --git a/testnet/puppet-chain/README.md b/contrib/tools/puppet-chain/README.md similarity index 100% rename from testnet/puppet-chain/README.md rename to contrib/tools/puppet-chain/README.md diff --git a/testnet/puppet-chain/config.toml.default b/contrib/tools/puppet-chain/config.toml.default similarity index 100% rename from testnet/puppet-chain/config.toml.default rename to contrib/tools/puppet-chain/config.toml.default diff --git a/testnet/puppet-chain/local-leader.toml.default b/contrib/tools/puppet-chain/local-leader.toml.default similarity index 100% rename from testnet/puppet-chain/local-leader.toml.default rename to contrib/tools/puppet-chain/local-leader.toml.default diff --git a/testnet/puppet-chain/src/main.rs b/contrib/tools/puppet-chain/src/main.rs similarity index 100% rename from testnet/puppet-chain/src/main.rs rename to contrib/tools/puppet-chain/src/main.rs diff --git a/src/burnchains/bitcoin/spv.rs b/src/burnchains/bitcoin/spv.rs index fa21c5559..40ac7f6af 100644 --- a/src/burnchains/bitcoin/spv.rs +++ b/src/burnchains/bitcoin/spv.rs @@ -771,7 +771,7 @@ impl SpvClient { // check work let chain_tip = self.get_headers_height()?; self.validate_header_work( - (chain_tip - 1) / BLOCK_DIFFICULTY_CHUNK_SIZE, + (insert_height.saturating_sub(1)) / BLOCK_DIFFICULTY_CHUNK_SIZE, chain_tip / BLOCK_DIFFICULTY_CHUNK_SIZE + 1, ) .map_err(|e| { @@ -784,6 +784,7 @@ impl SpvClient { } else { // fetching headers in descending order, so verify that the last item in // `block_headers` connects to a child in the DB (if it has one) + let headers_len = block_headers.len() as u64; self.insert_block_headers_before(insert_height, block_headers) .map_err(|e| { error!("Failed to insert block headers: {:?}", &e); @@ -797,7 +798,9 @@ impl SpvClient { insert_height / BLOCK_DIFFICULTY_CHUNK_SIZE + 1 }; - self.validate_header_work(interval_start, interval_start + 1) + let interval_end = (insert_height + 1 + headers_len) / BLOCK_DIFFICULTY_CHUNK_SIZE + 1; + + self.validate_header_work(interval_start, interval_end) .map_err(|e| { error!( "Received headers with bad target, difficulty, or continuity: {:?}", @@ -1598,4 +1601,152 @@ mod test { spv_client.validate_header_work(i, i + 1).unwrap(); } } + + #[test] + fn test_spv_check_work_bad_blocks_rejected() { + if !env::var("BLOCKSTACK_SPV_HEADERS_DB").is_ok() { + eprintln!("Skipping test_spv_check_work_reorg_accepted -- no BLOCKSTACK_SPV_HEADERS_DB envar set"); + return; + } + let db_path_source = env::var("BLOCKSTACK_SPV_HEADERS_DB").unwrap(); + let db_path = "/tmp/test_spv_check_work_reorg_accepted.dat".to_string(); + + if fs::metadata(&db_path).is_ok() { + fs::remove_file(&db_path).unwrap(); + } + + fs::copy(&db_path_source, &db_path).unwrap(); + + // set up SPV client so we don't have chain work at first + let mut spv_client = + SpvClient::new(&db_path, 0, None, BitcoinNetworkType::Mainnet, true, false).unwrap(); + + assert!( + spv_client.get_headers_height().unwrap() >= 40317, + "This test needs headers up to 40317" + ); + spv_client.drop_headers(40317).unwrap(); + + // update chain work + let total_work_before = spv_client.update_chain_work().unwrap(); + + // fake block headers for mainnet 40319-40320, which is on a difficulty adjustment boundary + let bad_headers = vec![ + LoneBlockHeader { + header: BlockHeader { + version: 1, + prev_blockhash: Sha256dHash::from_hex( + "000000003ae696c44274e40817d4acaf40c1ff1853411d4f0573421caf5faa07", + ) + .unwrap(), + merkle_root: Sha256dHash::from_hex( + "f1b2e16f74ee0e90cad3dc2e5be4806ff0581ed50a9cb3dfeee591dac76b17a7", + ) + .unwrap(), + time: 1654939798, + bits: 386485098, + nonce: 1, + }, + tx_count: VarInt(0), + }, + LoneBlockHeader { + header: BlockHeader { + version: 1, + prev_blockhash: Sha256dHash::from_hex( + "2c32da7fbdcef6ba34bcc5cc9707f2b351dbf094b4df5d3a2a38ea47b3e61f35", + ) + .unwrap(), + merkle_root: Sha256dHash::from_hex( + "b4d736ca74838036ebd19b085c3eeb9ffec2307f6452347cdd8ddaa249686f39", + ) + .unwrap(), + time: 1654939798, + bits: 486575299, + nonce: 1, + }, + tx_count: VarInt(0), + }, + LoneBlockHeader { + header: BlockHeader { + version: 1, + prev_blockhash: Sha256dHash::from_hex( + "7c1d4fd424f626c13bcd5442db080df9000d8f3dbfa1809ba1b05ddcdba58dd5", + ) + .unwrap(), + merkle_root: Sha256dHash::from_hex( + "cd71b0c247cfa777748c84d5376ad6a4a19e7802793dfd27c4d5834aa4393299", + ) + .unwrap(), + time: 1654996886, + bits: 0x1d00ffff, + nonce: 178162936, + }, + tx_count: VarInt(0), + }, + LoneBlockHeader { + header: BlockHeader { + version: 1, + prev_blockhash: Sha256dHash::from_hex( + "000000008a8cab438b9c98599c5363c7a4eff5b246871dd7c3f46886da375170", + ) + .unwrap(), + merkle_root: Sha256dHash::from_hex( + "cd71b0c247cfa777748c84d5376ad6a4a19e7802793dfd27c4d5834aa4393299", + ) + .unwrap(), + time: 1655018902, + bits: 0x1d00ffff, + nonce: 168408960, + }, + tx_count: VarInt(0), + }, + ]; + + // should fail + if let btc_error::InvalidPoW = spv_client + .handle_headers(40317, bad_headers.clone()) + .unwrap_err() + { + } else { + panic!("Bad PoW headers accepted"); + } + } + + #[test] + fn test_witness_size() { + use stacks_common::deps_common::bitcoin::blockdata::script::Script; + use stacks_common::deps_common::bitcoin::blockdata::transaction::OutPoint; + use stacks_common::deps_common::bitcoin::blockdata::transaction::TxIn; + use stacks_common::deps_common::bitcoin::blockdata::transaction::TxOut; + use std::mem; + + println!("OutPoint size in memory {}", mem::size_of::()); + println!("TxIn in memory {}", mem::size_of::()); + println!("TxOut size in memory {}", mem::size_of::()); + println!("Script size in memory {}", mem::size_of::