From d9b911187b20b931610a02ed8a5670a0462b87b5 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Fri, 25 Nov 2022 10:13:17 -0500 Subject: [PATCH] Release 2.8.0 (#636) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Chore(docs): Additional documentation for xcc gas values (#590) * Feat(standalone): Conversion from standalone's TransactionKind to NormalizedEthTransaction (#586) * Add Backstage metadata (#534) * Add Backstage metadata * Fix(aurora-engine-transactions): remove hex feaure from std (#600) * Feat(tests): benchmark transaction Emufid2pv2UpxrZae4NyowF2N2ZHvYEPq16LsQc7Uoc6 (#599) * Connector-tests: Add tests for the case where an account other than aurora-engine is used for ETH deposit (#598) * [Docs] Eth Connector - extended documentation (#601) * feat: add serde JSON to JSON serializable structs in parameters (#605) * Pausable precompiles (#588) * Test(engine): Increase unit test coverage (#614) * Feat: allow xcc calls to perform any possible NEAR call (#610) * Test(engine): Increase unit test coverage (#618) * Refactor: Mark functions that create promises on NEAR as unsafe (#617) * Fix(xcc): Only update the router contract version in storage if the deploy is successful (#616) * Fix(CI): broken submodules checkout + Clippy warnings (#621) * Chore(standalone): Upgrade rocksdb to v0.19. (#615) * fix: remove sscache from CI (#626) * Tiny refactoring by clippy suggestions (#625) * Improvements in log macro (#630) * Fix (engine): update SputnikVM dependency to avoid stack overflow on deeply nested EVM calls (#628) * Fix(xcc): Ensure the xcc router attaches enough gas to the execute function (#622) * Release 2.8.0 notes * Build: Add reproducible build job. (#633) * fix: bn 256 regression (#637) * Update release notes * Update README to exclude version (#623) * Chore: Update to SputnikVM version v0.37.1-aurora. Includes some overflow-related fixes. (#638) * fix: modexp underestimated gas * chore: bump Cargo to 2.8 * chore: remove version from deployments in README.md Co-authored-by: Alexey Lapitsky Co-authored-by: Joshua J. Bouw Co-authored-by: Kirill Co-authored-by: Evgeny Ukhanov Co-authored-by: Roman Hodulák Co-authored-by: Dmitry Strokov Co-authored-by: Oleksandr Anyshchenko Co-authored-by: Oleksandr Anyshchenko --- .catalog-info.yaml | 11 + .env/custom_example.env | 3 + .env/local.env | 1 + .env/mainnet.env | 1 + .env/testnet.env | 1 + .github/workflows/builds.yml | 6 +- .github/workflows/lints.yml | 16 +- .github/workflows/scheduled_lints.yml | 3 + .github/workflows/tests.yml | 14 +- CHANGES.md | 24 +- Cargo.lock | 2025 ++++++++++------- Cargo.toml | 2 + Makefile.toml | 29 +- README.md | 24 +- VERSION | 2 +- doc/eth-connector.md | 122 +- engine-precompiles/.catalog-info.yaml | 41 + engine-precompiles/Cargo.toml | 7 +- engine-precompiles/src/alt_bn256.rs | 61 +- engine-precompiles/src/blake2.rs | 4 +- engine-precompiles/src/hash.rs | 4 +- engine-precompiles/src/identity.rs | 2 +- engine-precompiles/src/lib.rs | 151 +- engine-precompiles/src/modexp.rs | 29 +- engine-precompiles/src/native.rs | 4 + engine-precompiles/src/promise_result.rs | 2 +- engine-precompiles/src/secp256k1.rs | 4 +- engine-precompiles/src/xcc.rs | 10 +- engine-sdk/Cargo.toml | 1 + engine-sdk/src/env.rs | 4 +- engine-sdk/src/lib.rs | 4 +- engine-sdk/src/near_runtime.rs | 160 +- engine-sdk/src/promise.rs | 31 +- engine-standalone-storage/Cargo.toml | 6 +- engine-standalone-storage/src/engine_state.rs | 10 +- engine-standalone-storage/src/lib.rs | 22 +- engine-standalone-storage/src/promise.rs | 6 +- .../src/relayer_db/mod.rs | 2 +- engine-standalone-storage/src/sync/mod.rs | 20 +- engine-standalone-storage/src/sync/types.rs | 272 ++- engine-standalone-tracing/Cargo.toml | 8 +- engine-test-doubles/Cargo.toml | 22 + .../src/io.rs | 8 +- engine-test-doubles/src/lib.rs | 3 + .../src}/promise.rs | 11 +- .../src}/tracing.rs | 0 engine-tests/Cargo.toml | 30 +- .../src/benches/eth_standard_precompiles.rs | 2 +- engine-tests/src/benches/nft_pagination.rs | 2 +- .../src/test_utils/exit_precompile.rs | 61 +- engine-tests/src/test_utils/mod.rs | 23 +- engine-tests/src/test_utils/rust.rs | 2 +- engine-tests/src/test_utils/self_destruct.rs | 2 +- engine-tests/src/test_utils/solidity.rs | 2 +- .../src/test_utils/standalone/mocks/mod.rs | 9 +- engine-tests/src/test_utils/standalone/mod.rs | 61 +- engine-tests/src/test_utils/uniswap.rs | 2 +- .../src/tests/account_id_precompiles.rs | 2 +- engine-tests/src/tests/contract_call.rs | 11 +- engine-tests/src/tests/ecrecover.rs | 4 +- engine-tests/src/tests/erc20.rs | 2 +- engine-tests/src/tests/erc20_connector.rs | 24 +- engine-tests/src/tests/eth_connector.rs | 222 +- engine-tests/src/tests/mod.rs | 1 + engine-tests/src/tests/one_inch.rs | 4 +- .../src/tests/pausable_precompiles.rs | 155 ++ .../src/tests/promise_results_precompile.rs | 2 +- engine-tests/src/tests/repro.rs | 31 +- engine-tests/src/tests/res/CallTooDeep.sol | 12 + .../src/tests/res/aurora_state_Emufid2.json | 556 +++++ engine-tests/src/tests/res/input_Emufid2.hex | 1 + engine-tests/src/tests/sanity.rs | 56 +- .../src/tests/standalone/json_snapshot.rs | 8 +- engine-tests/src/tests/standalone/sanity.rs | 9 +- engine-tests/src/tests/standalone/storage.rs | 11 +- engine-tests/src/tests/standalone/sync.rs | 2 +- engine-tests/src/tests/standalone/tracing.rs | 6 +- .../src/tests/standard_precompiles.rs | 2 +- engine-tests/src/tests/state_migration.rs | 2 +- engine-tests/src/tests/uniswap.rs | 20 +- engine-tests/src/tests/xcc.rs | 471 +++- engine-transactions/Cargo.toml | 4 +- engine-transactions/src/legacy.rs | 2 +- engine-types/Cargo.toml | 4 +- engine-types/src/account_id.rs | 5 +- engine-types/src/lib.rs | 1 + engine-types/src/parameters.rs | 190 +- engine-types/src/types/address.rs | 7 +- engine-types/src/types/wei.rs | 1 + engine/.catalog-info.yaml | 22 + engine/Cargo.toml | 13 +- engine/src/accounting.rs | 92 + engine/src/admin_controlled.rs | 96 + engine/src/connector.rs | 69 +- engine/src/deposit_event.rs | 236 +- engine/src/engine.rs | 883 +++++-- engine/src/fungible_token.rs | 22 +- engine/src/json.rs | 252 +- engine/src/lib.rs | 99 +- engine/src/log_entry.rs | 28 + engine/src/map.rs | 36 + engine/src/parameters.rs | 38 +- engine/src/pausables.rs | 252 ++ engine/src/proof.rs | 75 +- engine/src/xcc.rs | 47 +- etc/eth-contracts/.catalog-info.yaml | 21 + etc/eth-contracts/package.json | 2 +- etc/eth-contracts/yarn.lock | 695 +++--- etc/state-migration-test/Cargo.lock | 7 + etc/tests/fibonacci/Cargo.toml | 19 + etc/tests/fibonacci/src/lib.rs | 86 + etc/xcc-router/Cargo.lock | 19 +- etc/xcc-router/Cargo.toml | 4 + etc/xcc-router/src/lib.rs | 154 +- rust-toolchain | 2 +- scripts/docker-entrypoint.sh | 3 + .../verify_evm_erc20.sh | 0 117 files changed, 6581 insertions(+), 1908 deletions(-) create mode 100644 .catalog-info.yaml create mode 100644 engine-precompiles/.catalog-info.yaml create mode 100644 engine-test-doubles/Cargo.toml rename engine-tests/src/test_utils/standalone/mocks/storage.rs => engine-test-doubles/src/io.rs (93%) create mode 100644 engine-test-doubles/src/lib.rs rename {engine-tests/src/test_utils/standalone/mocks => engine-test-doubles/src}/promise.rs (87%) rename {engine-tests/src/test_utils/standalone/mocks => engine-test-doubles/src}/tracing.rs (100%) create mode 100644 engine-tests/src/tests/pausable_precompiles.rs create mode 100644 engine-tests/src/tests/res/CallTooDeep.sol create mode 100644 engine-tests/src/tests/res/aurora_state_Emufid2.json create mode 100644 engine-tests/src/tests/res/input_Emufid2.hex create mode 100644 engine/.catalog-info.yaml create mode 100644 engine/src/pausables.rs create mode 100644 etc/eth-contracts/.catalog-info.yaml create mode 100644 etc/tests/fibonacci/Cargo.toml create mode 100644 etc/tests/fibonacci/src/lib.rs create mode 100755 scripts/docker-entrypoint.sh rename verify_evm_erc20.sh => scripts/verify_evm_erc20.sh (100%) diff --git a/.catalog-info.yaml b/.catalog-info.yaml new file mode 100644 index 000000000..d553cf1cb --- /dev/null +++ b/.catalog-info.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: aurora-engine-public + description: Public Aurora Engine repository +spec: + targets: + - ./engine/.catalog-info.yaml + - ./etc/eth-contracts/.catalog-info.yaml + - ./engine-precompiles/.catalog-info.yaml diff --git a/.env/custom_example.env b/.env/custom_example.env index 03b1a0afd..811891762 100644 --- a/.env/custom_example.env +++ b/.env/custom_example.env @@ -43,5 +43,8 @@ # instead use `local-near`. #NEAR_CLI = "local-near" +# The profile name. +#PROFILE = "testnet" + # The Rust compilier flags to use when compiling any binary. Does not work for the tests. #RUSTC_FLAGS_BUILD = "-C link-arg=-s" diff --git a/.env/local.env b/.env/local.env index ff9305700..cac2f4902 100644 --- a/.env/local.env +++ b/.env/local.env @@ -3,4 +3,5 @@ RUSTC_FLAGS_BUILD="-C link-arg=-s" NEAR_EVM_ACCOUNT="aurora.test.near" WASM_FILE="aurora-local.wasm" NEAR_CLI="local_near" +PROFILE="testnet" IS_PROD=false diff --git a/.env/mainnet.env b/.env/mainnet.env index d32440be1..6ae4ce5bb 100644 --- a/.env/mainnet.env +++ b/.env/mainnet.env @@ -6,4 +6,5 @@ NEAR_EVM_ACCOUNT="aurora" WASM_FILE="aurora-mainnet.wasm" WASM_FILE_TEST="aurora-mainnet-test.wasm" NEAR_CLI="near" +PROFILE="mainnet" IS_PROD=true diff --git a/.env/testnet.env b/.env/testnet.env index 5ee71be5b..e30726e0c 100644 --- a/.env/testnet.env +++ b/.env/testnet.env @@ -6,4 +6,5 @@ NEAR_EVM_ACCOUNT="aurora" WASM_FILE="aurora-testnet.wasm" WASM_FILE_TEST="aurora-testnet-test.wasm" NEAR_CLI="near" +PROFILE="testnet" IS_PROD=false diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 71cbea518..e36cee953 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -12,9 +12,12 @@ jobs: matrix: profile: [mainnet, testnet] steps: + - name: Potential broken submodules fix + run: | + git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || : - name: Clone the repository uses: actions/checkout@v3 - - run: cargo make --profile ${{ matrix.profile }} build + - run: cargo make --profile ${{ matrix.profile }} build-docker - run: ls -lH bin/aurora-${{ matrix.profile }}.wasm - name: Upload the aurora-${{ matrix.profile }}.wasm artifact uses: actions/upload-artifact@v2 @@ -33,4 +36,3 @@ jobs: env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 - RUSTC_WRAPPER: sccache diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index 8cd2d66d0..90162f3b2 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -12,6 +12,9 @@ jobs: name: Format runs-on: [self-hosted, light] steps: + - name: Potential broken submodules fix + run: | + git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || : - name: Clone the repository uses: actions/checkout@v3 - name: Run cargo fmt @@ -20,6 +23,9 @@ jobs: name: Clippy runs-on: [self-hosted, heavy] steps: + - name: Potential broken submodules fix + run: | + git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || : - name: Clone the repository uses: actions/checkout@v3 - run: cargo make build-contracts @@ -31,17 +37,25 @@ jobs: name: Udeps runs-on: [self-hosted, heavy] steps: + - name: Potential broken submodules fix + run: | + git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || : - name: Clone the repository uses: actions/checkout@v3 + - name: Update udeps + run: cargo install --force cargo-udeps - name: Run udeps run: cargo make udeps contracts: name: Contracts runs-on: [self-hosted, light] steps: + - name: Potential broken submodules fix + run: | + git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || : - name: Clone the repository uses: actions/checkout@v3 - name: Run yarn lint run: cargo make check-contracts - name: Check committed EvmErc20.bin - run: bash verify_evm_erc20.sh + run: bash scripts/verify_evm_erc20.sh diff --git a/.github/workflows/scheduled_lints.yml b/.github/workflows/scheduled_lints.yml index 44c760f6e..9ab9416e4 100644 --- a/.github/workflows/scheduled_lints.yml +++ b/.github/workflows/scheduled_lints.yml @@ -8,6 +8,9 @@ jobs: name: Nightly Clippy runs-on: [self-hosted, heavy] steps: + - name: Potential broken submodules fix + run: | + git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || : - name: Clone the repository uses: actions/checkout@v3 - run: make etc/eth-contracts/res/EvmErc20.bin diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e2d0c60ac..d3f5ea72b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,31 +12,35 @@ jobs: name: Test suite (mainnet, testnet) runs-on: [self-hosted, heavy] steps: + - name: Potential broken submodules fix + run: | + git checkout -f $(git -c user.name=x -c user.email=x@x commit-tree $(git hash-object -t tree /dev/null) < /dev/null) || : - name: Clone the repository uses: actions/checkout@v3 - name: Restore cache run: | - cache-util restore cargo_git cargo_registry sccache yarn_cache + cache-util restore cargo_git cargo_registry yarn_cache cache-util restore aurora-engine-target@generic@${{ hashFiles('**/Cargo.lock') }}:target - - name: List directories - run: ls -la target/wasm32-unknown-unknown/release && ls -la - name: Build contracts run: cargo make build-contracts - name: Test contracts run: cargo make test-contracts - name: Build mainnet test WASM run: cargo make --profile mainnet build-test + - name: List mainnet WASM directory and root directory + run: ls -la target/wasm32-unknown-unknown/release && ls -la - name: Test mainnet run: cargo make --profile mainnet test-workspace - name: Build testnet test WASM run: cargo make --profile testnet build-test + - name: List testnet WASM directory and root directory + run: ls -la target/wasm32-unknown-unknown/release && ls -la - name: Test testnet run: cargo make --profile testnet test-workspace - name: Save cache run: | - cache-util save cargo_git cargo_registry sccache yarn_cache + cache-util save cargo_git cargo_registry yarn_cache cache-util msave aurora-engine-target@generic@${{ hashFiles('**/Cargo.lock') }}:target env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 - RUSTC_WRAPPER: sccache diff --git a/CHANGES.md b/CHANGES.md index 941193048..5eb3e76de 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.8.0] 2022-11-15 + +### Added + +- New functions `pause_precompiles` and `resume_precompiles` to allow pausing/unpausing the exit precompiles on Aurora by [@RomanHodulak]. ([#588]) +- Reproducible build in Docker by [@RomanHodulak]. ([#633]) + +### Fixes + +- Update to latest SputnikVM by [@birchmd] (fixes some security issues including a potential call stack overflow and incorrect `is_static` indicator in exit precompiles). ([#628]) +- Minor fixes for the XCC functionality by [@birchmd]. ([#610] [#616] [#622]) +- Fix bn256 regression by [@joshuajbouw]. ([#637]) + +[#588]: https://github.com/aurora-is-near/aurora-engine/pull/588 +[#610]: https://github.com/aurora-is-near/aurora-engine/pull/610 +[#616]: https://github.com/aurora-is-near/aurora-engine/pull/616 +[#622]: https://github.com/aurora-is-near/aurora-engine/pull/622 +[#628]: https://github.com/aurora-is-near/aurora-engine/pull/628 +[#633]: https://github.com/aurora-is-near/aurora-engine/pull/633 +[#637]: https://github.com/aurora-is-near/aurora-engine/pull/637 + ## [2.7.0] 2022-08-19 ### Added @@ -300,7 +321,8 @@ struct SubmitResult { ## [1.0.0] - 2021-05-12 -[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.7.0...develop +[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.8.0...develop +[2.8.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.7.0...2.8.0 [2.7.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.6.1...2.7.0 [2.6.1]: https://github.com/aurora-is-near/aurora-engine/compare/2.6.0...2.6.1 [2.6.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.5.3...2.6.0 diff --git a/Cargo.lock b/Cargo.lock index 145b5a1ee..1261e44f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,34 +29,40 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", "once_cell", "version_check", ] [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" dependencies = [ "memchr", ] [[package]] -name = "ansi_term" -version = "0.12.1" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ - "winapi", + "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "anyhow" -version = "1.0.58" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" [[package]] name = "arrayref" @@ -76,11 +82,32 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "async-stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "async-trait" -version = "0.1.56" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" dependencies = [ "proc-macro2", "quote", @@ -100,23 +127,27 @@ dependencies = [ [[package]] name = "aurora-engine" -version = "2.7.0" +version = "2.8.0" dependencies = [ "aurora-engine-precompiles", "aurora-engine-sdk", + "aurora-engine-test-doubles", "aurora-engine-transactions", "aurora-engine-types", - "base64 0.13.0", + "base64", + "bitflags", "borsh", "byte-slice-cast", + "digest 0.10.5", "ethabi", "evm", "hex", - "rand 0.7.3", "rjson", "rlp", "serde", "serde_json", + "sha3", + "test-case", "wee_alloc", ] @@ -125,6 +156,7 @@ name = "aurora-engine-precompiles" version = "1.0.0" dependencies = [ "aurora-engine-sdk", + "aurora-engine-test-doubles", "aurora-engine-types", "borsh", "ethabi", @@ -132,12 +164,12 @@ dependencies = [ "hex", "libsecp256k1", "num", - "rand 0.7.3", + "rand 0.8.5", "ripemd", "serde", "serde_json", - "sha2 0.10.2", - "sha3 0.10.2", + "sha2 0.10.6", + "sha3", "zeropool-bn", ] @@ -147,8 +179,19 @@ version = "1.0.0" dependencies = [ "aurora-engine-types", "borsh", - "sha2 0.10.2", - "sha3 0.10.2", + "sha2 0.10.6", + "sha3", +] + +[[package]] +name = "aurora-engine-test-doubles" +version = "1.0.0" +dependencies = [ + "aurora-engine-sdk", + "aurora-engine-types", + "evm", + "evm-gasometer", + "evm-runtime", ] [[package]] @@ -158,9 +201,10 @@ dependencies = [ "aurora-engine", "aurora-engine-precompiles", "aurora-engine-sdk", + "aurora-engine-test-doubles", "aurora-engine-transactions", "aurora-engine-types", - "base64 0.13.0", + "base64", "borsh", "bstr", "byte-slice-cast", @@ -179,13 +223,14 @@ dependencies = [ "near-primitives-core", "near-sdk", "near-sdk-sim", + "near-vm-errors", "near-vm-logic", "near-vm-runner", "rand 0.8.5", "rlp", "serde", "serde_json", - "sha3 0.10.2", + "sha3", "tempfile", "walrus", ] @@ -209,16 +254,16 @@ version = "1.0.0" dependencies = [ "borsh", "hex", - "primitive-types 0.11.1", - "rand 0.7.3", + "primitive-types 0.12.1", + "rand 0.8.5", "serde", ] [[package]] name = "auto_impl" -version = "0.5.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" dependencies = [ "proc-macro-error", "proc-macro2", @@ -234,30 +279,24 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" dependencies = [ "addr2line", "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", - "object 0.28.4", + "object 0.29.0", "rustc-demangle", ] [[package]] name = "base64" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" - -[[package]] -name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "bincode" @@ -270,9 +309,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.59.2" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" dependencies = [ "bitflags", "cexpr", @@ -293,18 +332,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitvec" -version = "0.20.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" -dependencies = [ - "funty 1.1.0", - "radium 0.6.2", - "tap", - "wyz 0.2.0", -] - [[package]] name = "bitvec" version = "1.0.1" @@ -312,9 +339,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty 2.0.0", - "radium 0.7.0", + "radium", "tap", - "wyz 0.5.0", + "wyz", ] [[package]] @@ -349,25 +376,18 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "borsh" version = "0.9.3" @@ -421,33 +441,33 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "0.2.17" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" dependencies = [ - "lazy_static", "memchr", + "once_cell", "regex-automata", "serde", ] [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "byte-slice-cast" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytecheck" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a31f923c2db9513e4298b72df143e6e655a759b3d6a0966df18f81223fff54f" +checksum = "d11cac2c12b5adc6570dad2ee1b87eff4955dac476fe12d81e5fdd352e52406f" dependencies = [ "bytecheck_derive", "ptr_meta", @@ -455,9 +475,9 @@ dependencies = [ [[package]] name = "bytecheck_derive" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb17c862a905d912174daa27ae002326fff56dc8b8ada50a0a5f0976cb174f0" +checksum = "13e576ebe98e605500b3c8041bb888e966653577172df6dd97398714eb30b9bf" dependencies = [ "proc-macro2", "quote", @@ -472,9 +492,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "bytesize" @@ -508,18 +528,15 @@ dependencies = [ [[package]] name = "cast" -version = "0.2.7" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" -dependencies = [ - "rustc_version 0.4.0", -] +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574" dependencies = [ "jobserver", ] @@ -547,32 +564,61 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ - "libc", + "iana-time-zone", + "js-sys", "num-integer", "num-traits", "serde", "time 0.1.44", + "wasm-bindgen", "winapi", ] +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] name = "clang-sys" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a050e2153c5be08febd6734e29298e844fdb0fa21aeddd63b4eb7baa106c69b" +checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" dependencies = [ "glob", "libc", @@ -581,20 +627,9 @@ dependencies = [ [[package]] name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags", - "textwrap 0.11.0", - "unicode-width", -] - -[[package]] -name = "clap" -version = "3.2.7" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7b16274bb247b45177db843202209b12191b631a14a9d06e41b3777d6ecf14" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", "bitflags", @@ -604,14 +639,14 @@ dependencies = [ "once_cell", "strsim", "termcolor", - "textwrap 0.15.0", + "textwrap", ] [[package]] name = "clap_derive" -version = "3.2.7" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck 0.4.0", "proc-macro-error", @@ -638,6 +673,16 @@ dependencies = [ "bitflags", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -650,6 +695,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "cpp_demangle" version = "0.3.5" @@ -661,27 +712,27 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" dependencies = [ "libc", ] [[package]] name = "cranelift-bforest" -version = "0.80.1" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62fc68cdb867b7d27b5f33cd65eb11376dfb41a2d09568a1a2c2bc1dc204f4ef" +checksum = "2fa7c3188913c2d11a361e0431e135742372a2709a99b103e79758e11a0a797e" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.80.1" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31253a44ab62588f8235a996cc9b0636d98a299190069ced9628b8547329b47a" +checksum = "29285f70fd396a8f64455a15a6e1d390322e4a5f5186de513141313211b0a23e" dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", @@ -689,40 +740,40 @@ dependencies = [ "cranelift-entity", "gimli", "log", - "regalloc", + "regalloc2", "smallvec", "target-lexicon 0.12.4", ] [[package]] name = "cranelift-codegen-meta" -version = "0.80.1" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a20ab4627d30b702fb1b8a399882726d216b8164d3b3fa6189e3bf901506afe" +checksum = "057eac2f202ec95aebfd8d495e88560ac085f6a415b3c6c28529dc5eb116a141" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.80.1" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6687d9668dacfed4468361f7578d86bded8ca4db978f734d9b631494bebbb5b8" +checksum = "75d93869efd18874a9341cfd8ad66bcb08164e86357a694a0e939d29e87410b9" [[package]] name = "cranelift-entity" -version = "0.80.1" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c77c5d72db97ba2cb36f69037a709edbae0d29cb25503775891e7151c5c874bf" +checksum = "7e34bd7a1fefa902c90a921b36323f17a398b788fa56a75f07a29d83b6e28808" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.80.1" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426dca83f63c7c64ea459eb569aadc5e0c66536c0042ed5d693f91830e8750d0" +checksum = "457018dd2d6ee300953978f63215b5edf3ae42dbdf8c7c038972f10394599f72" dependencies = [ "cranelift-codegen", "log", @@ -732,9 +783,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.80.1" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8007864b5d0c49b026c861a15761785a2871124e401630c03ef1426e6d0d559e" +checksum = "bba027cc41bf1d0eee2ddf16caba2ee1be682d0214520fff0129d2c6557fda89" dependencies = [ "cranelift-codegen", "libc", @@ -743,9 +794,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.80.1" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94cf12c071415ba261d897387ae5350c4d83c238376c8c5a96514ecfa2ea66a3" +checksum = "9b17639ced10b9916c9be120d38c872ea4f9888aa09248568b10056ef0559bfa" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -753,7 +804,7 @@ dependencies = [ "itertools", "log", "smallvec", - "wasmparser 0.81.0", + "wasmparser 0.84.0", "wasmtime-types", ] @@ -768,15 +819,16 @@ dependencies = [ [[package]] name = "criterion" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ + "anes", "atty", "cast", - "clap 2.34.0", + "ciborium", + "clap", "criterion-plot", - "csv", "itertools", "lazy_static", "num-traits", @@ -785,7 +837,6 @@ dependencies = [ "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -794,19 +845,33 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", ] +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -814,9 +879,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", @@ -825,26 +890,34 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.9" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" +checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" dependencies = [ "autocfg", "cfg-if 1.0.0", "crossbeam-utils", "memoffset", - "once_cell", "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" -version = "0.8.10" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" +checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" dependencies = [ "cfg-if 1.0.0", - "once_cell", ] [[package]] @@ -855,11 +928,11 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", "typenum", ] @@ -869,50 +942,72 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", "subtle", ] [[package]] -name = "csv" -version = "1.1.6" +name = "curve25519-dalek" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", ] [[package]] -name = "csv-core" -version = "0.1.10" +name = "cxx" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a" dependencies = [ - "memchr", + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", ] [[package]] -name = "curve25519-dalek" -version = "3.2.1" +name = "cxx-build" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "darling" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" dependencies = [ "darling_core", "darling_macro", @@ -920,9 +1015,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" dependencies = [ "fnv", "ident_case", @@ -933,9 +1028,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.13.4" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" dependencies = [ "darling_core", "quote", @@ -970,16 +1065,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.5", + "generic-array 0.14.6", ] [[package]] name = "digest" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.3", "crypto-common", "subtle", ] @@ -1041,9 +1136,9 @@ dependencies = [ [[package]] name = "either" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] name = "elastic-array" @@ -1059,12 +1154,14 @@ name = "engine-standalone-storage" version = "0.1.0" dependencies = [ "aurora-engine", + "aurora-engine-precompiles", "aurora-engine-sdk", "aurora-engine-transactions", "aurora-engine-types", - "base64 0.13.0", + "base64", "borsh", "evm-core", + "hex", "postgres", "rocksdb", "serde", @@ -1084,20 +1181,40 @@ dependencies = [ "serde", ] +[[package]] +name = "enum-map" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a56d54c8dd9b3ad34752ed197a4eb2a6601bc010808eb097a04a58ae4c43e1" +dependencies = [ + "enum-map-derive", +] + +[[package]] +name = "enum-map-derive" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9045e2676cd5af83c3b167d917b0a5c90a4d8e266e2683d6631b235c457fc27" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "enumset" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4799cdb24d48f1f8a7a98d06b7fde65a85a2d1e42b25a889f5406aa1fbefe074" +checksum = "19be8061a06ab6f3a6cf21106c873578bf01bd42ad15e0311a9c76161cb1c753" dependencies = [ "enumset_derive", ] [[package]] name = "enumset_derive" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea83a3fbdc1d999ccfbcbee717eab36f8edf2d71693a23ce0d7cca19e085304c" +checksum = "03e7b551eba279bf0fa88b83a46330168c1560a52a94f5126f892f0b364ab3e0" dependencies = [ "darling", "proc-macro2", @@ -1134,9 +1251,9 @@ dependencies = [ [[package]] name = "ethabi" -version = "17.1.0" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f186de076b3e77b8e6d73c99d1b52edc2a229e604f4b5eb6992c06c11d79d537" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" dependencies = [ "ethereum-types", "hex", @@ -1144,20 +1261,20 @@ dependencies = [ "regex", "serde", "serde_json", - "sha3 0.10.2", + "sha3", "thiserror", "uint", ] [[package]] name = "ethbloom" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", - "fixed-hash", - "impl-codec 0.6.0", + "fixed-hash 0.8.0", + "impl-codec", "impl-rlp", "impl-serde", "scale-info", @@ -1166,43 +1283,42 @@ dependencies = [ [[package]] name = "ethereum" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23750149fe8834c0e24bb9adcbacbe06c45b9861f15df53e09f26cb7c4ab91ef" +checksum = "6a89fb87a9e103f71b903b80b670200b54cc67a07578f070681f1fffb7396fb7" dependencies = [ "bytes", "ethereum-types", "hash-db", "hash256-std-hasher", - "parity-scale-codec 3.1.5", + "parity-scale-codec", "rlp", - "rlp-derive", "scale-info", "serde", - "sha3 0.10.2", + "sha3", "triehash", ] [[package]] name = "ethereum-types" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +checksum = "81224dc661606574f5a0f28c9947d0ee1d93ff11c5f1c4e7272f52e8c0b5483c" dependencies = [ "ethbloom", - "fixed-hash", - "impl-codec 0.6.0", + "fixed-hash 0.8.0", + "impl-codec", "impl-rlp", "impl-serde", - "primitive-types 0.11.1", + "primitive-types 0.12.1", "scale-info", "uint", ] [[package]] name = "evm" -version = "0.35.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.36.0-aurora#7dfbeb535e7105a7531a4e6c559f0f5d45f20014" +version = "0.37.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.1-aurora#12a268120c0f6d4b3c3f35043e7f9482e7a6fd43" dependencies = [ "auto_impl", "environmental", @@ -1211,46 +1327,46 @@ dependencies = [ "evm-gasometer", "evm-runtime", "log", - "parity-scale-codec 3.1.5", - "primitive-types 0.11.1", + "parity-scale-codec", + "primitive-types 0.12.1", "rlp", "scale-info", "serde", - "sha3 0.10.2", + "sha3", ] [[package]] name = "evm-core" -version = "0.35.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.36.0-aurora#7dfbeb535e7105a7531a4e6c559f0f5d45f20014" +version = "0.37.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.1-aurora#12a268120c0f6d4b3c3f35043e7f9482e7a6fd43" dependencies = [ - "parity-scale-codec 3.1.5", - "primitive-types 0.11.1", + "parity-scale-codec", + "primitive-types 0.12.1", "scale-info", "serde", ] [[package]] name = "evm-gasometer" -version = "0.35.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.36.0-aurora#7dfbeb535e7105a7531a4e6c559f0f5d45f20014" +version = "0.37.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.1-aurora#12a268120c0f6d4b3c3f35043e7f9482e7a6fd43" dependencies = [ "environmental", "evm-core", "evm-runtime", - "primitive-types 0.11.1", + "primitive-types 0.12.1", ] [[package]] name = "evm-runtime" -version = "0.35.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.36.0-aurora#7dfbeb535e7105a7531a4e6c559f0f5d45f20014" +version = "0.37.0" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.1-aurora#12a268120c0f6d4b3c3f35043e7f9482e7a6fd43" dependencies = [ "auto_impl", "environmental", "evm-core", - "primitive-types 0.11.1", - "sha3 0.10.2", + "primitive-types 0.12.1", + "sha3", ] [[package]] @@ -1261,9 +1377,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" dependencies = [ "instant", ] @@ -1273,6 +1389,15 @@ name = "fixed-hash" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", "rand 0.8.5", @@ -1280,6 +1405,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "fnv" version = "1.0.7" @@ -1288,11 +1419,10 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ - "matches", "percent-encoding", ] @@ -1306,6 +1436,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" + [[package]] name = "funty" version = "1.1.0" @@ -1320,13 +1456,12 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1335,9 +1470,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", @@ -1345,15 +1480,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" dependencies = [ "futures-core", "futures-task", @@ -1362,15 +1497,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", @@ -1379,21 +1514,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ "futures-channel", "futures-core", @@ -1407,6 +1542,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.12.4" @@ -1418,9 +1562,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -1439,9 +1583,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if 1.0.0", "libc", @@ -1450,9 +1594,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" dependencies = [ "fallible-iterator", "indexmap", @@ -1461,9 +1605,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.25" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6" +checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1" dependencies = [ "bitflags", "libc", @@ -1481,17 +1625,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hash-db" -version = "0.15.2" +name = "h2" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" - +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util 0.7.4", + "tracing", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hash-db" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" + [[package]] name = "hash256-std-hasher" version = "0.15.2" @@ -1512,9 +1675,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] @@ -1557,6 +1720,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hmac" @@ -1574,7 +1740,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -1584,10 +1750,104 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array 0.14.5", + "generic-array 0.14.6", "hmac 0.8.1", ] +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "id-arena" version = "2.2.1" @@ -1602,31 +1862,21 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] -[[package]] -name = "impl-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" -dependencies = [ - "parity-scale-codec 2.3.1", -] - [[package]] name = "impl-codec" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec 3.1.5", + "parity-scale-codec", ] [[package]] @@ -1640,9 +1890,9 @@ dependencies = [ [[package]] name = "impl-serde" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" dependencies = [ "serde", ] @@ -1665,7 +1915,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.12.1", + "hashbrown 0.12.3", "serde", ] @@ -1678,56 +1928,41 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "integer-encoding" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" - [[package]] name = "io-lifetimes" -version = "0.4.4" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ef6787e7f0faedc040f95716bdd0e62bcfcf4ba93da053b62dea2691c13864" -dependencies = [ - "winapi", -] +checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6" [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "jobserver" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.58" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] @@ -1772,15 +2007,15 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "libgit2-sys" -version = "0.12.26+1.3.0" +version = "0.14.0+1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" +checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b" dependencies = [ "cc", "libc", @@ -1802,9 +2037,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.6.1+6.28.2" +version = "0.8.0+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc587013734dadb7cf23468e531aa120788b87243648be42e2d3a072186291" +checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" dependencies = [ "bindgen", "bzip2-sys", @@ -1812,17 +2047,18 @@ dependencies = [ "glob", "libc", "libz-sys", + "tikv-jemalloc-sys", "zstd-sys", ] [[package]] name = "libsecp256k1" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64 0.13.0", + "base64", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -1889,11 +2125,20 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "link-cplusplus" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +dependencies = [ + "cc", +] + [[package]] name = "linux-raw-sys" -version = "0.0.36" +version = "0.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a261afc61b7a5e323933b402ca6a1765183687c614789b1e4db7762ed4230bca" +checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7" [[package]] name = "lock_api" @@ -1906,9 +2151,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg", "scopeguard", @@ -1945,11 +2190,11 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84e6fe5655adc6ce00787cf7dcaf8dc4f998a0565d23eafc207a8b08ca3349a" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" dependencies = [ - "hashbrown 0.11.2", + "hashbrown 0.12.3", ] [[package]] @@ -1982,19 +2227,13 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "md-5" -version = "0.10.1" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" dependencies = [ - "digest 0.10.3", + "digest 0.10.5", ] [[package]] @@ -2015,9 +2254,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3179b85e1fd8b14447cbebadb75e45a1002f541b925f0bfec366d56a81c56d" +checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" dependencies = [ "libc", ] @@ -2045,18 +2284,18 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" dependencies = [ "libc", "log", @@ -2070,10 +2309,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + [[package]] name = "near-account-id" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "borsh", "serde", @@ -2082,7 +2327,7 @@ dependencies = [ [[package]] name = "near-cache" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "lru", ] @@ -2090,7 +2335,7 @@ dependencies = [ [[package]] name = "near-chain-configs" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "anyhow", "chrono", @@ -2100,7 +2345,7 @@ dependencies = [ "num-rational 0.3.2", "serde", "serde_json", - "sha2 0.9.9", + "sha2 0.10.6", "smart-default", "tracing", ] @@ -2108,7 +2353,7 @@ dependencies = [ [[package]] name = "near-crypto" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "arrayref", "blake2", @@ -2118,69 +2363,62 @@ dependencies = [ "curve25519-dalek", "derive_more", "ed25519-dalek", - "libc", "near-account-id", "once_cell", - "parity-secp256k1", "primitive-types 0.10.1", "rand 0.7.3", - "rand_core 0.5.1", + "secp256k1", "serde", "serde_json", "subtle", "thiserror", ] -[[package]] -name = "near-metrics" -version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" -dependencies = [ - "prometheus", - "tracing", -] - [[package]] name = "near-o11y" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "atty", "backtrace", - "clap 3.2.7", + "clap", "once_cell", "opentelemetry", - "opentelemetry-jaeger", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "prometheus", + "serde", + "strum", "thiserror", "tokio", "tracing", "tracing-appender", "tracing-opentelemetry", - "tracing-serde", "tracing-subscriber", ] [[package]] name = "near-pool" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "borsh", "near-crypto", - "near-metrics", + "near-o11y", "near-primitives", "once_cell", - "rand 0.7.3", + "rand 0.8.5", ] [[package]] name = "near-primitives" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "borsh", "byteorder", "bytesize", + "cfg-if 1.0.0", "chrono", "derive_more", "easy-ext", @@ -2192,7 +2430,7 @@ dependencies = [ "num-rational 0.3.2", "once_cell", "primitive-types 0.10.1", - "rand 0.7.3", + "rand 0.8.5", "reed-solomon-erasure", "serde", "serde_json", @@ -2204,23 +2442,24 @@ dependencies = [ [[package]] name = "near-primitives-core" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ - "base64 0.11.0", + "base64", "borsh", "bs58", "derive_more", "near-account-id", "num-rational 0.3.2", "serde", - "sha2 0.9.9", + "serde_repr", + "sha2 0.10.6", "strum", ] [[package]] name = "near-rpc-error-core" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "quote", "serde", @@ -2230,7 +2469,7 @@ dependencies = [ [[package]] name = "near-rpc-error-macro" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "near-rpc-error-core", "serde", @@ -2240,9 +2479,9 @@ dependencies = [ [[package]] name = "near-sdk" version = "3.1.0" -source = "git+https://github.com/aurora-is-near/near-sdk-rs.git?rev=7a3fa3fbff84b712050370d840297df38c925d2d#7a3fa3fbff84b712050370d840297df38c925d2d" +source = "git+https://github.com/aurora-is-near/near-sdk-rs.git?rev=a4634850023fd115053970f17e10861779d5167d#a4634850023fd115053970f17e10861779d5167d" dependencies = [ - "base64 0.13.0", + "base64", "borsh", "bs58", "near-primitives-core", @@ -2256,7 +2495,7 @@ dependencies = [ [[package]] name = "near-sdk-core" version = "3.1.0" -source = "git+https://github.com/aurora-is-near/near-sdk-rs.git?rev=7a3fa3fbff84b712050370d840297df38c925d2d#7a3fa3fbff84b712050370d840297df38c925d2d" +source = "git+https://github.com/aurora-is-near/near-sdk-rs.git?rev=a4634850023fd115053970f17e10861779d5167d#a4634850023fd115053970f17e10861779d5167d" dependencies = [ "Inflector", "proc-macro2", @@ -2267,7 +2506,7 @@ dependencies = [ [[package]] name = "near-sdk-macros" version = "3.1.0" -source = "git+https://github.com/aurora-is-near/near-sdk-rs.git?rev=7a3fa3fbff84b712050370d840297df38c925d2d#7a3fa3fbff84b712050370d840297df38c925d2d" +source = "git+https://github.com/aurora-is-near/near-sdk-rs.git?rev=a4634850023fd115053970f17e10861779d5167d#a4634850023fd115053970f17e10861779d5167d" dependencies = [ "near-sdk-core", "proc-macro2", @@ -2278,7 +2517,7 @@ dependencies = [ [[package]] name = "near-sdk-sim" version = "3.2.0" -source = "git+https://github.com/aurora-is-near/near-sdk-rs.git?rev=7a3fa3fbff84b712050370d840297df38c925d2d#7a3fa3fbff84b712050370d840297df38c925d2d" +source = "git+https://github.com/aurora-is-near/near-sdk-rs.git?rev=a4634850023fd115053970f17e10861779d5167d#a4634850023fd115053970f17e10861779d5167d" dependencies = [ "chrono", "funty 1.1.0", @@ -2296,32 +2535,36 @@ dependencies = [ [[package]] name = "near-stable-hasher" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" [[package]] name = "near-store" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ + "anyhow", "borsh", "byteorder", "bytesize", + "crossbeam", "derive_more", "elastic-array", + "enum-map", "fs2", + "itoa", "lru", "near-crypto", - "near-metrics", "near-o11y", "near-primitives", "num_cpus", "once_cell", - "rand 0.7.3", + "rand 0.8.5", "rlimit", "rocksdb", "serde", "serde_json", "strum", + "tempfile", "thiserror", "tracing", ] @@ -2329,39 +2572,41 @@ dependencies = [ [[package]] name = "near-vm-errors" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "borsh", "near-account-id", "near-rpc-error-macro", "serde", + "strum", ] [[package]] name = "near-vm-logic" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ - "base64 0.13.0", "borsh", "bs58", "byteorder", + "ed25519-dalek", "near-account-id", "near-crypto", + "near-o11y", "near-primitives", "near-primitives-core", "near-vm-errors", - "ripemd160", + "ripemd", "serde", - "sha2 0.9.9", - "sha3 0.9.1", + "sha2 0.10.6", + "sha3", "zeropool-bn", ] [[package]] name = "near-vm-runner" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "anyhow", "borsh", @@ -2377,7 +2622,6 @@ dependencies = [ "parity-wasm 0.42.2", "pwasm-utils", "serde", - "threadpool", "tracing", "wasmer-compiler-near", "wasmer-compiler-singlepass-near", @@ -2407,14 +2651,14 @@ dependencies = [ [[package]] name = "node-runtime" version = "0.0.0" -source = "git+https://github.com/birchmd/nearcore.git?rev=980bc48dc02878fea1e0dbc5812ae7de49f12dda#980bc48dc02878fea1e0dbc5812ae7de49f12dda" +source = "git+https://github.com/birchmd/nearcore.git?rev=6033903be2037d67510188450f289b2d6e033f04#6033903be2037d67510188450f289b2d6e033f04" dependencies = [ "borsh", "byteorder", "hex", "near-chain-configs", "near-crypto", - "near-metrics", + "near-o11y", "near-primitives", "near-store", "near-vm-errors", @@ -2424,10 +2668,11 @@ dependencies = [ "num-rational 0.3.2", "num-traits", "once_cell", - "rand 0.7.3", + "rand 0.8.5", "rayon", "serde", "serde_json", + "sha2 0.10.6", "thiserror", "tracing", ] @@ -2442,6 +2687,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num" version = "0.4.0" @@ -2563,29 +2818,30 @@ dependencies = [ [[package]] name = "object" -version = "0.27.1" +version = "0.28.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" dependencies = [ "crc32fast", + "hashbrown 0.11.2", "indexmap", "memchr", ] [[package]] name = "object" -version = "0.28.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.12.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "oorandom" @@ -2607,9 +2863,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.74" +version = "0.9.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" +checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" dependencies = [ "autocfg", "cc", @@ -2640,18 +2896,21 @@ dependencies = [ ] [[package]] -name = "opentelemetry-jaeger" -version = "0.16.0" +name = "opentelemetry-otlp" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c0b12cd9e3f9b35b52f6e0dac66866c519b26f424f4bbf96e3fe8bfbdc5229" +checksum = "9d1a6ca9de4c8b00aa7f1a153bd76cb263287155cec642680d79d98706f3d28a" dependencies = [ "async-trait", - "lazy_static", + "futures", + "futures-util", + "http", "opentelemetry", - "opentelemetry-semantic-conventions", + "prost", "thiserror", - "thrift", "tokio", + "tonic", + "tonic-build", ] [[package]] @@ -2664,19 +2923,16 @@ dependencies = [ ] [[package]] -name = "ordered-float" -version = "1.1.1" +name = "os_str_bytes" +version = "6.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" -dependencies = [ - "num-traits", -] +checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9" [[package]] -name = "os_str_bytes" -version = "6.1.0" +name = "overload" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "page_size" @@ -2690,68 +2946,30 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" -dependencies = [ - "arrayvec 0.7.2", - "bitvec 0.20.4", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive 2.3.1", - "serde", -] - -[[package]] -name = "parity-scale-codec" -version = "3.1.5" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9182e4a71cae089267ab03e67c99368db7cd877baf50f931e5d6d4b71e195ac0" +checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a" dependencies = [ "arrayvec 0.7.2", - "bitvec 1.0.1", + "bitvec", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive 3.1.3", + "parity-scale-codec-derive", "serde", ] -[[package]] -name = "parity-scale-codec-derive" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "parity-scale-codec-derive" version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 1.2.1", "proc-macro2", "quote", "syn", ] -[[package]] -name = "parity-secp256k1" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fca4f82fccae37e8bbdaeb949a4a218a1bbc485d11598f193d2a908042e5fc1" -dependencies = [ - "arrayvec 0.5.2", - "cc", - "cfg-if 0.1.10", - "rand 0.7.3", -] - [[package]] name = "parity-wasm" version = "0.41.0" @@ -2774,25 +2992,14 @@ dependencies = [ "parking_lot_core 0.7.2", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api 0.4.7", - "parking_lot_core 0.8.5", -] - [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "lock_api 0.4.7", - "parking_lot_core 0.9.3", + "lock_api 0.4.9", + "parking_lot_core 0.9.4", ] [[package]] @@ -2811,36 +3018,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall 0.2.13", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.13", + "redox_syscall 0.2.16", "smallvec", "windows-sys", ] [[package]] name = "paste" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" [[package]] name = "peeking_take_while" @@ -2850,42 +3043,52 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "petgraph" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +dependencies = [ + "fixedbitset", + "indexmap", +] [[package]] name = "phf" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" dependencies = [ "phf_shared", ] [[package]] name = "phf_shared" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" dependencies = [ "siphasher", ] [[package]] name = "pin-project" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.10" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", @@ -2906,15 +3109,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "plotters" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" dependencies = [ "num-traits", "plotters-backend", @@ -2925,28 +3128,28 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" [[package]] name = "plotters-svg" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" dependencies = [ "plotters-backend", ] [[package]] name = "postgres" -version = "0.19.3" +version = "0.19.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8bbcd5f6deb39585a0d9f4ef34c4a41c25b7ad26d23c75d837d78c8e7adc85f" +checksum = "960c214283ef8f0027974c03e9014517ced5db12f021a9abb66185a5751fab0a" dependencies = [ "bytes", "fallible-iterator", - "futures", + "futures-util", "log", "tokio", "tokio-postgres", @@ -2958,7 +3161,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "878c6cbf956e03af9aa8204b407b9cbf47c072164800aa918c516cd4b056c50c" dependencies = [ - "base64 0.13.0", + "base64", "byteorder", "bytes", "fallible-iterator", @@ -2966,15 +3169,15 @@ dependencies = [ "md-5", "memchr", "rand 0.8.5", - "sha2 0.10.2", + "sha2 0.10.6", "stringprep", ] [[package]] name = "postgres-types" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd6e8b7189a73169290e89bd24c771071f1012d8fe6f738f5226531f0b03d89" +checksum = "73d946ec7d256b04dfadc4e6a3292324e6f417124750fc5c0950f981b703a0f1" dependencies = [ "bytes", "fallible-iterator", @@ -2993,19 +3196,18 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" dependencies = [ - "fixed-hash", - "impl-codec 0.5.1", + "fixed-hash 0.7.0", "uint", ] [[package]] name = "primitive-types" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ - "fixed-hash", - "impl-codec 0.6.0", + "fixed-hash 0.8.0", + "impl-codec", "impl-rlp", "impl-serde", "scale-info", @@ -3023,10 +3225,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ + "once_cell", "thiserror", "toml", ] @@ -3057,39 +3260,92 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] [[package]] name = "prometheus" -version = "0.11.0" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8425533e7122f0c3cc7a37e6244b16ad3a2cc32ae7ac6276e2a75da0d9c200d" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" dependencies = [ "cfg-if 1.0.0", "fnv", "lazy_static", - "parking_lot 0.11.2", + "memchr", + "parking_lot 0.12.1", "protobuf", - "regex", "thiserror", ] +[[package]] +name = "prost" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5" +dependencies = [ + "bytes", + "heck 0.3.3", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prost", + "prost-types", + "regex", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a" +dependencies = [ + "bytes", + "prost", +] + [[package]] name = "protobuf" -version = "2.27.1" +version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf7e6d18738ecd0902d30d1ad232c9125985a3422929b16c65517b38adc14f96" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" [[package]] name = "psm" -version = "0.1.18" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871372391786ccec00d3c5d3d6608905b3d4db263639cfe075d3b60a736d115a" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" dependencies = [ "cc", ] @@ -3127,19 +3383,13 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - [[package]] name = "radium" version = "0.7.0" @@ -3167,7 +3417,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -3187,7 +3437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -3201,11 +3451,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.7", + "getrandom 0.2.8", ] [[package]] @@ -3249,9 +3499,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] @@ -3266,21 +3516,22 @@ dependencies = [ ] [[package]] -name = "regalloc" -version = "0.0.33" +name = "regalloc2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d808cff91dfca7b239d40b972ba628add94892b1d9e19a842aedc5cfae8ab1a" +checksum = "904196c12c9f55d3aea578613219f493ced8e05b3d0c6a42d11cb4142d8b4879" dependencies = [ + "fxhash", "log", - "rustc-hash", + "slice-group-by", "smallvec", ] [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -3298,9 +3549,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "region" @@ -3346,22 +3597,11 @@ dependencies = [ [[package]] name = "ripemd" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1facec54cb5e0dc08553501fa740091086d0259ad0067e0d4103448e4cb22ed3" -dependencies = [ - "digest 0.10.3", -] - -[[package]] -name = "ripemd160" -version = "0.9.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "opaque-debug", + "digest 0.10.5", ] [[package]] @@ -3376,7 +3616,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cec2b3485b07d96ddfd3134767b8a447b45ea4eb91448d0a35180ec0ffd5ed15" dependencies = [ "bytecheck", - "hashbrown 0.12.1", + "hashbrown 0.12.3", "ptr_meta", "rend", "rkyv_derive", @@ -3405,11 +3645,12 @@ dependencies = [ [[package]] name = "rlp" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999508abb0ae792aabed2460c45b89106d97fe4adac593bdaef433c2605847b5" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", + "rlp-derive", "rustc-hex", ] @@ -3426,9 +3667,9 @@ dependencies = [ [[package]] name = "rocksdb" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620f4129485ff1a7128d184bc687470c21c7951b64779ebc9cfdad3dcd920290" +checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" dependencies = [ "libc", "librocksdb-sys", @@ -3467,14 +3708,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.11", + "semver 1.0.14", ] [[package]] name = "rustix" -version = "0.31.3" +version = "0.33.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2dcfc2778a90e38f56a708bfc90572422e11d6c7ee233d053d1f782cf9df6d2" +checksum = "938a344304321a9da4973b9ff4f9f8db9caf4597dfd9dda6a60b523340a0fff0" dependencies = [ "bitflags", "errno", @@ -3486,15 +3727,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" +checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "same-file" @@ -3507,24 +3748,24 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.1.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c46be926081c9f4dd5dd9b6f1d3e3229f2360bc6502dd8836f84a93b7c75e99a" +checksum = "88d8a765117b237ef233705cc2cc4c6a27fccd46eea6ef0c8c6dae5f3ef407f8" dependencies = [ - "bitvec 1.0.1", + "bitvec", "cfg-if 1.0.0", "derive_more", - "parity-scale-codec 3.1.5", + "parity-scale-codec", "scale-info-derive", ] [[package]] name = "scale-info-derive" -version = "2.1.2" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e334bb10a245e28e5fd755cabcafd96cfcd167c99ae63a46924ca8d8703a3c" +checksum = "cdcd47b380d8c4541044e341dcd9475f55ba37ddc50c908d945fc036a8642496" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate 1.2.1", "proc-macro2", "quote", "syn", @@ -3536,12 +3777,37 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" + [[package]] name = "seahash" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "secp256k1" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff55dc09d460954e9ef2fa8a7ced735a964be9981fd50e870b2b3b0705e14964" +dependencies = [ + "rand 0.8.5", + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "0.9.0" @@ -3553,9 +3819,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d92beeab217753479be2f74e54187a6aed4c125ff0703a866c3147a02f0c6dd" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "semver-parser" @@ -3565,9 +3831,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] @@ -3584,28 +3850,18 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212e73464ebcde48d723aa02eb270ba62eff38a9b732df31f33f1b4e145f3a54" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_cbor" -version = "0.11.2" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" dependencies = [ - "half", "serde", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", @@ -3614,15 +3870,26 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" dependencies = [ - "itoa 1.0.2", + "itoa", "ryu", "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" version = "0.9.9" @@ -3638,34 +3905,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.3", + "digest 0.10.5", ] [[package]] name = "sha3" -version = "0.9.1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] - -[[package]] -name = "sha3" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a31480366ec990f395a61b7c08122d99bd40544fdb5abcfc1b06bb29994312c" -dependencies = [ - "digest 0.10.3", + "digest 0.10.5", "keccak", ] @@ -3684,11 +3939,20 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + [[package]] name = "signature" -version = "1.5.0" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" [[package]] name = "siphasher" @@ -3698,15 +3962,24 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "smallvec" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "smart-default" @@ -3721,9 +3994,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", "winapi", @@ -3774,9 +4047,9 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4faebde00e8ff94316c01800f9054fd2ba77d30d9e922541913051d1d978918b" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.0", "proc-macro2", @@ -3793,9 +4066,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.98" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", @@ -3841,7 +4114,7 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "libc", - "redox_syscall 0.2.13", + "redox_syscall 0.2.16", "remove_dir_all", "winapi", ] @@ -3856,34 +4129,47 @@ dependencies = [ ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "test-case" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "21d6cf5a7dffb3f9dceec8e6b8ca528d9bd71d36c9f074defb548ce161f598c0" dependencies = [ - "unicode-width", + "test-case-macros", +] + +[[package]] +name = "test-case-macros" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45b7bf6e19353ddd832745c8fcf77a17a93171df7151187f26623f2b75b5b26" +dependencies = [ + "cfg-if 1.0.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "textwrap" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", @@ -3900,25 +4186,14 @@ dependencies = [ ] [[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "thrift" -version = "0.15.0" +name = "tikv-jemalloc-sys" +version = "0.5.2+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b82ca8f46f95b3ce96081fe3dd89160fdea970c254bb72925255d1b62aae692e" +checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" dependencies = [ - "byteorder", - "integer-encoding", - "log", - "ordered-float", - "threadpool", + "cc", + "fs_extra", + "libc", ] [[package]] @@ -3934,13 +4209,31 @@ dependencies = [ [[package]] name = "time" -version = "0.3.11" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca" dependencies = [ - "itoa 1.0.2", + "itoa", "libc", "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b" +dependencies = [ + "time-core", ] [[package]] @@ -3979,32 +4272,57 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.19.2" +version = "1.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" dependencies = [ + "autocfg", "bytes", "libc", "memchr", "mio", "num_cpus", - "once_cell", + "parking_lot 0.12.1", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "winapi", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio-postgres" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c88a47a23c5d2dc9ecd28fb38fba5fc7e5ddc1fe64488ec145076b0c71c8ae" +checksum = "29a12c1b3e0704ae7dfc25562629798b29c72e6b1d0a681b6f29ab4ae5e7f7bf" dependencies = [ "async-trait", "byteorder", "bytes", "fallible-iterator", - "futures", + "futures-channel", + "futures-util", "log", "parking_lot 0.12.1", "percent-encoding", @@ -4014,14 +4332,14 @@ dependencies = [ "postgres-types", "socket2", "tokio", - "tokio-util", + "tokio-util 0.7.4", ] [[package]] name = "tokio-stream" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite", @@ -4030,9 +4348,23 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.3" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" dependencies = [ "bytes", "futures-core", @@ -4051,13 +4383,89 @@ dependencies = [ "serde", ] +[[package]] +name = "tonic" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a" +dependencies = [ + "async-stream", + "async-trait", + "base64", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-stream", + "tokio-util 0.6.10", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + +[[package]] +name = "tonic-build" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757" +dependencies = [ + "proc-macro2", + "prost-build", + "quote", + "syn", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util 0.7.4", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if 1.0.0", + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4070,15 +4478,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" dependencies = [ "crossbeam-channel", - "time 0.3.11", + "time 0.3.16", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", @@ -4087,14 +4495,24 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.28" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.1.3" @@ -4108,9 +4526,9 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.17.3" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93600c803bb15e2a32bd376001b8625587f268fe887669b5ac86af524637c242" +checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" dependencies = [ "once_cell", "opentelemetry", @@ -4120,25 +4538,15 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - [[package]] name = "tracing-subscriber" -version = "0.3.11" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" dependencies = [ - "ansi_term", - "lazy_static", "matchers", + "nu-ansi-term", + "once_cell", "regex", "sharded-slab", "smallvec", @@ -4158,6 +4566,12 @@ dependencies = [ "rlp", ] +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + [[package]] name = "typenum" version = "1.15.0" @@ -4166,9 +4580,9 @@ checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "uint" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f03af7ccf01dd611cc450a0d10dbc9b745770d096473e2faf0ca6e2d66d1e0" +checksum = "a45526d29728d135c2900b0d30573fe3ee79fceb12ef534c7bb30e810a91b601" dependencies = [ "byteorder", "crunchy", @@ -4184,46 +4598,45 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" -version = "0.1.20" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" -version = "2.2.2" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", ] @@ -4288,6 +4701,16 @@ dependencies = [ "syn", ] +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -4308,9 +4731,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.81" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -4318,13 +4741,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.81" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -4333,9 +4756,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.81" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4343,9 +4766,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.81" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", @@ -4356,20 +4779,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.81" +version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "wasmer-compiler-near" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c60244fe7afb343ada73aff39452852c70e295031eab762b9f8ec77a5f3425cd" +checksum = "34d09dc0ba83ddaceb9b0846ed11a6c26a449b69fa2709e0335d268f44491921" dependencies = [ "enumset", "rkyv", - "serde", - "serde_bytes", "smallvec", "target-lexicon 0.12.4", "thiserror", @@ -4380,9 +4801,9 @@ dependencies = [ [[package]] name = "wasmer-compiler-singlepass-near" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84137bc13dfb61a4bd55a47852107caadd3b2025329d6678f6108995b5e866d" +checksum = "86f34bf0625219766759851c1f92e0797787b8b10b424c0a273ee4e0328a2ff7" dependencies = [ "byteorder", "dynasm", @@ -4399,9 +4820,9 @@ dependencies = [ [[package]] name = "wasmer-engine-near" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef11b966113dee907a8f5d38c01293a966e8dc1dd54bc27dcc0f3dd4638459c" +checksum = "fa8353167be3099f3bd033cb9c8479a02d69917777cf4c2e52a09946d5582457" dependencies = [ "backtrace", "enumset", @@ -4409,8 +4830,6 @@ dependencies = [ "memmap2", "more-asserts", "rustc-demangle", - "serde", - "serde_bytes", "target-lexicon 0.12.4", "thiserror", "wasmer-compiler-near", @@ -4420,9 +4839,9 @@ dependencies = [ [[package]] name = "wasmer-engine-universal-near" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e5c98c64fa124bd62f811405ec86ab85fa619c86f68ca3ba9c658720b73f9e" +checksum = "c34fb4f6af2209a36c5e6ed407c9e057fdd2e722e762f702dbd8575896349c62" dependencies = [ "cfg-if 1.0.0", "enumset", @@ -4503,21 +4922,20 @@ dependencies = [ [[package]] name = "wasmer-types-near" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9f6d7755e259a5575b9739cd226c40730726d72a84ed5573f71b8932fed246" +checksum = "d1131dfac4d92947acef554a75b433122ca635414c23934f53434ec0efc5994d" dependencies = [ "indexmap", "rkyv", - "serde", "thiserror", ] [[package]] name = "wasmer-vm-near" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597d871efa338883fb1d415e0c7163749042a3637e43cfe7204146e93a29d88f" +checksum = "4a47f13d5c412974a38bba01a8b009e1e49bffbee45387198403b269a74d7374" dependencies = [ "backtrace", "cc", @@ -4528,7 +4946,6 @@ dependencies = [ "more-asserts", "region 3.0.0", "rkyv", - "serde", "thiserror", "wasmer-types-near", "winapi", @@ -4554,33 +4971,35 @@ checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" [[package]] name = "wasmparser" -version = "0.81.0" +version = "0.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc" +checksum = "77dc97c22bb5ce49a47b745bed8812d30206eff5ef3af31424f2c1820c0974b2" +dependencies = [ + "indexmap", +] [[package]] name = "wasmtime" -version = "0.33.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9c724da92e39a85d2231d4c2a942c8be295211441dbca581c6c3f3f45a9f00" +checksum = "dfdd1101bdfa0414a19018ec0a091951a20b695d4d04f858d49f6c4cc53cd8dd" dependencies = [ "anyhow", "backtrace", "bincode", "cfg-if 1.0.0", - "cpp_demangle", "indexmap", "lazy_static", "libc", "log", - "object 0.27.1", + "object 0.28.4", + "once_cell", "paste", "psm", "region 2.2.0", - "rustc-demangle", "serde", "target-lexicon 0.12.4", - "wasmparser 0.81.0", + "wasmparser 0.84.0", "wasmtime-cranelift", "wasmtime-environ", "wasmtime-jit", @@ -4590,9 +5009,9 @@ dependencies = [ [[package]] name = "wasmtime-cranelift" -version = "0.33.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1762765dd69245f00e5d9783b695039e449a7be0f9c5383e4c78465dd6131aeb" +checksum = "16e78edcfb0daa9a9579ac379d00e2d5a5b2a60c0d653c8c95e8412f2166acb9" dependencies = [ "anyhow", "cranelift-codegen", @@ -4603,18 +5022,18 @@ dependencies = [ "gimli", "log", "more-asserts", - "object 0.27.1", + "object 0.28.4", "target-lexicon 0.12.4", "thiserror", - "wasmparser 0.81.0", + "wasmparser 0.84.0", "wasmtime-environ", ] [[package]] name = "wasmtime-environ" -version = "0.33.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4468301d95ec71710bb6261382efe27d1296447711645e3dbabaea6e4de3504" +checksum = "4201389132ec467981980549574b33fc70d493b40f2c045c8ce5c7b54fbad97e" dependencies = [ "anyhow", "cranelift-entity", @@ -4622,27 +5041,31 @@ dependencies = [ "indexmap", "log", "more-asserts", - "object 0.27.1", + "object 0.28.4", "serde", "target-lexicon 0.12.4", "thiserror", - "wasmparser 0.81.0", + "wasmparser 0.84.0", "wasmtime-types", ] [[package]] name = "wasmtime-jit" -version = "0.33.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0ae6e581ff014b470ec35847ea3c0b4c3ace89a55df5a04c802a11f4574e7d" +checksum = "1587ca7752d00862faa540d00fd28e5ccf1ac61ba19756449193f1153cb2b127" dependencies = [ "addr2line", "anyhow", "bincode", "cfg-if 1.0.0", + "cpp_demangle", "gimli", - "object 0.27.1", + "log", + "object 0.28.4", "region 2.2.0", + "rustc-demangle", + "rustix", "serde", "target-lexicon 0.12.4", "thiserror", @@ -4651,18 +5074,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "wasmtime-jit-debug" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b27233ab6c8934b23171c64f215f902ef19d18c1712b46a0674286d1ef28d5dd" +dependencies = [ + "lazy_static", +] + [[package]] name = "wasmtime-runtime" -version = "0.33.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9c28877ae37a367cda7b52b8887589816152e95dde9b7c80cc686f52761961" +checksum = "47d3b0b8f13db47db59d616e498fe45295819d04a55f9921af29561827bdb816" dependencies = [ "anyhow", "backtrace", "cc", "cfg-if 1.0.0", "indexmap", - "lazy_static", "libc", "log", "mach", @@ -4673,26 +5104,27 @@ dependencies = [ "rustix", "thiserror", "wasmtime-environ", + "wasmtime-jit-debug", "winapi", ] [[package]] name = "wasmtime-types" -version = "0.33.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395726e8f5dd8c57cb0db445627b842343f7e29ed7489467fdf7953ed9d3cd4f" +checksum = "1630d9dca185299bec7f557a7e73b28742fe5590caf19df001422282a0a98ad1" dependencies = [ "cranelift-entity", "serde", "thiserror", - "wasmparser 0.81.0", + "wasmparser 0.84.0", ] [[package]] name = "web-sys" -version = "0.3.58" +version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", @@ -4710,6 +5142,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "which" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +dependencies = [ + "either", + "libc", + "once_cell", +] + [[package]] name = "winapi" version = "0.3.9" @@ -4743,52 +5186,60 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ + "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", + "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" [[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" +name = "windows_x86_64_gnullvm" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" [[package]] -name = "wyz" -version = "0.2.0" +name = "windows_x86_64_msvc" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" [[package]] name = "wyz" @@ -4836,9 +5287,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.3+zstd.1.5.2" +version = "2.0.1+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" +checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 56c244ec8..dee3a9cf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ opt-level = 3 resolver = "2" members = [ "engine", + "engine-test-doubles", "engine-precompiles", "engine-sdk", "engine-standalone-storage", @@ -44,5 +45,6 @@ exclude = [ "etc/tests/ft-receiver", "etc/tests/benchmark-contract", "etc/tests/self-contained-5bEgfRQ", + "etc/tests/fibonacci", "etc/xcc-router", ] diff --git a/Makefile.toml b/Makefile.toml index 7040fd40f..7e1daa22e 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -69,7 +69,7 @@ args = [ [tasks.udeps] category = "Check" env = { "CARGO_MAKE_RUST_CHANNEL" = "nightly", "CARGO_MAKE_CRATE_INSTALLATION_LOCKED" = "true" } -install_crate = { crate_name = "cargo-udeps", binary = "cargo", min_version = "0.1.30", test_arg = ["udeps", "-h"], force = false } +install_crate = { crate_name = "cargo-udeps", binary = "cargo", min_version = "0.1.34", test_arg = ["udeps", "-h"], force = true } command = "${CARGO}" args = [ "udeps", @@ -81,9 +81,7 @@ category = "Check" command = "${CARGO}" args = [ "clippy", - "--no-default-features", - "--features", - "contract", + "--all-targets", "--", "-D", "warnings", @@ -179,6 +177,15 @@ dependencies = [ "post-engine-build-env", ] +[tasks.build-engine-flow-docker] +category = "Build" +dependencies = [ + "build-engine", + "make-bin-directory", + "copy-engine-build", + "post-engine-build-env", +] + [tasks.build-test] condition = { profiles = ["mainnet", "testnet", "custom"] } env = { "RUSTFLAGS" = "${RUSTC_FLAGS_BUILD}", "CARGO_FEATURES" = "${CARGO_FEATURES_BUILD_TEST}", "WASM_FILE" = "${WASM_FILE_TEST}", "RELEASE" = "--release", "TARGET_DIR" = "release" } @@ -187,10 +194,22 @@ run_task = "build-engine-flow" [tasks.build] condition = { profiles = ["mainnet", "testnet", "localnet", "development", "custom"] } -env = { "RUSTFLAGS" = "${RUSTC_FLAGS_BUILD}", "CARGO_FEATURES" = "${CARGO_FEATURES_BUILD}", "RELEASE" = "--release", "TARGET_DIR" = "release" } +env = { "RUSTFLAGS" = "-C strip=symbols --remap-path-prefix ${HOME}=/path/to/home/ --remap-path-prefix ${PWD}=/path/to/source/", "CARGO_FEATURES" = "${CARGO_FEATURES_BUILD}", "RELEASE" = "--release", "TARGET_DIR" = "release" } category = "Build" run_task = "build-engine-flow" +[tasks.build-docker-inner] +condition = { profiles = ["mainnet", "testnet", "localnet", "development", "custom"] } +env = { "RUSTFLAGS" = "-C strip=symbols --remap-path-prefix ${HOME}=/path/to/home/ --remap-path-prefix ${PWD}=/path/to/source/", "CARGO_FEATURES" = "${CARGO_FEATURES_BUILD}", "RELEASE" = "--release", "TARGET_DIR" = "release" } +category = "Build" +run_task = "build-engine-flow-docker" + +[tasks.build-docker] +category = "Build" +script = ''' +docker run --volume $PWD:/host -w /host -it nearprotocol/contract-builder:master-b8fc60809b907543d909ee75fcc1bd7b68cbe2fd-amd64 ./scripts/docker-entrypoint.sh ${PROFILE} +''' + [tasks.test-contracts] category = "Test" script = ''' diff --git a/README.md b/README.md index f1ecd3f4b..46d05e8ce 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ documentation. ## Deployments -Network | Contract ID | Chain ID | Version -------- | ------------------- | ---------- | ------ -Mainnet | [`aurora`][Mainnet] | 1313161554 | 2.6.1 -Testnet | [`aurora`][Testnet] | 1313161555 | 2.7.0 -Local | `aurora.test.near` | 1313161556 | 2.7.0 +| Network | Contract ID | Chain ID | +|---------|---------------------|------------| +| Mainnet | [`aurora`][Mainnet] | 1313161554 | +| Testnet | [`aurora`][Testnet] | 1313161555 | +| Local | `aurora.test.near` | 1313161556 | [Mainnet]: https://explorer.near.org/accounts/aurora [Testnet]: https://explorer.testnet.near.org/accounts/aurora @@ -26,12 +26,9 @@ Local | `aurora.test.near` | 1313161556 | 2.7.0 ### Prerequisites - Node.js (v14+) -- Rust nightly (2021-03-25) with the WebAssembly toolchain - cargo-make ```sh -rustup install nightly-2021-03-25 -rustup target add wasm32-unknown-unknown --toolchain nightly-2021-03-25 cargo install --force cargo-make ``` @@ -84,12 +81,23 @@ The current available build `task`s are: - `build-test`, builds all the below using test features. Requires a `--profile` argument. - `build-contracts`, builds all the ETH contracts. +- `build-docker`, builds the `aurora--test.wasm` in the `bin` folder using docker build environment. The purpose of this task is to produce reproducible binaries. For example, the following will build the mainnet debug binary: ```sh cargo make --profile mainnet build ``` +#### Verifying binary hash + +To verify that a deployed binary matches the source code, you may want build it reproducibly and then check that their hashes match. The motivation behind that is to prevent malicious code from being deployed. + +Run these commands to produce the binary hash: +```sh +cargo make --profile build-docker +shasum -a 256 bin/aurora-.wasm +``` + #### Running unit & integration tests To run tests, there are a few cargo make tasks we can run: diff --git a/VERSION b/VERSION index 24ba9a38d..834f26295 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.7.0 +2.8.0 diff --git a/doc/eth-connector.md b/doc/eth-connector.md index d924198a5..c519c647f 100644 --- a/doc/eth-connector.md +++ b/doc/eth-connector.md @@ -1,42 +1,122 @@ # ETH connector +Aurora ETH connector is implementation for [NEP-141](https://nomicon.io/Standards/Tokens/FungibleToken/Core). + +It has two basic accounts entities: +* Aurora on NEAR (`balance_of`) +* Aurora on ETH (`balance_of_eth`) + +This means that there are two types of `total supply`: +* `total_eth_supply_on_near` +* `total_eth_supply_on_aurora` + +Eth-Connector logic can be divided into three large groups: +1. NEP-141 specific logic +2. Eth-Connector specific logic +3. Admin Controlled specific logic + +## ETH connector methods + +* new_eth_connector (call once) + > Initialize Eth Connector. Called once. + +* verify_log_entry (integration-test, view) + > Used for integrations tests only. + +#### NEP-141 specific logic + +For more details see: [NEP-141](https://nomicon.io/Standards/Tokens/FungibleToken/Core). + +* ft_total_supply (view) +* ft_total_eth_supply_on_near (view) +* ft_total_eth_supply_on_aurora (view) +* ft_balance_of (view) +* ft_balance_of_eth (view) +* ft_transfer (mutable, payable) +* ft_resolve_transfer (private, mutable) +* storage_deposit (mutable) +* storage_withdraw (mutable, payable) +* storage_balance_of (view) +* ft_metadata (view) + +* ft_transfer_call (mutable, payable) + > - Verify message data if `sender_id == receiver_id ` before `ft_on_transfer` call to avoid verification panics + > - Fetch transfer message + > - Check is transfer amount > fee + > - Check overflow for recipient `balance_of_eth_on_aurora` before process `ft_on_transfer` + > - Check overflow for `total_eth_supply_on_aurora` before process `ft_on_transfer` + > - if sender_id != receiver_id + > - `transfer_eth_on_near` from `sender_id` to `receiver_id` + > - Call `ft_on_transfer` +* ft_on_transfer (mutable) + > - Fetch transfer message + > - mint_eth_on_aurora for `recipient` + > - if `fee` exist mint_eth_on_aurora for `relayer` + +#### Eth-Connector specific logic + +* deposit (mutable) + > Deposit logic: + > - fetch proof + > - Prepare token message data for Finish Deposit + > - Invoke promise - Verify proof log entry data by Custodian + > - Invoke promise Finish Deposit with Token message data + > + > Arguments: (proof: Proof) + +* withdraw (mutable, payable) + > Withdraw from NEAR accounts. + > + > Arguments: (recipient_address: Address, amount: NEP141Wei) + +* finish_deposit (private, mutable) + > Finish deposit logic + > - Check is Verify proof log entry data success + > - If msg is set + > - Mint amount for Owner + > - Record Proof + > - Call ft_transfer_call for receiver_id + > - else + > - Mint amount for Owner + > - Mint fee for relayer + > - Record Proof + > + > Arguments: (deposit_call: FinishDepositCallArgs, [callback] verify_log_result: bool) + +#### Admin Controlled specific logic + +* get_accounts_counter (view) +* get_paused_flags (view) +* set_paused_flags (mutable, private) + +## ETH connector specific source files + +* `fungible_token.rs` +* `connector.rs` +* `admin_controlled.rs` +* `deposit_event.rs` +* `log_entry.rs` +* `proof.rs` + ## Build 1. For production set in the Makefile ``` FEATURES = contract ``` - 1.1. For **development and testing** set in the Makefile + 1.1. For **development and testing** set in the Makefile ``` FEATURES = contract,integration-test ``` 2. Build release: `$ make release` -3. Run tests: `$ cargo test` +3. Run tests: `$ cargo test` 4. Deploying process is common for Aurora itself. Please reference [README.md](../README.md) -## Initialize eth-conenctor +## Initialize eth-connector With `near-cli` run: ``` $ near call new_eth_connector '{"prover_account": "", "eth_custodian_address": ""}' --account-id ``` -## ETH connector specific methods -* new_eth_connector (call once) -* deposit (mutable) -* withdraw (mutable, payable) -* finish_deposit (private, mutable) -* ft_total_supply (view) -* ft_total_eth_supply_on_near (view) -* ft_total_eth_supply_on_aurora (view) -* ft_balance_of (view) -* ft_balance_of_eth (view) -* ft_transfer (mutable, payable) -* ft_resolve_transfer (private, mutable) -* ft_transfer_call (mutable, payable) -* ft_on_transfer (private, mutable) -* storage_deposit (mutable) -* storage_withdraw (mutable, payable) -* storage_balance_of (view) - ## Ethereum specific flow Follow by [this instruction](https://github.com/aurora-is-near/eth-connector/blob/master/README.md). diff --git a/engine-precompiles/.catalog-info.yaml b/engine-precompiles/.catalog-info.yaml new file mode 100644 index 000000000..aacebe9ac --- /dev/null +++ b/engine-precompiles/.catalog-info.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: aurora-engine-precompiles + description: |- + EVM precompiles for the Aurora engine + tags: + - precompiles + - contract + - near + links: [] + annotations: + aurora.dev/security-tier: "1" +spec: + owner: engine-team + type: contract + lifecycle: production + system: aurora-engine + interactsWith: [] +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: aurora-engine-precompiles-native + description: |- + Aurora and NEAR specific precompile additions + tags: + - precompiles + - contract + - near + links: [] + annotations: + aurora.dev/security-tier: "1" + backstage.io/source-location: url:https://github.com/aurora-is-near/aurora-engine/blob/master/engine-precompiles/src/native.rs +spec: + owner: bridge-team + type: contract + lifecycle: production + system: aurora-engine + interactsWith: [] diff --git a/engine-precompiles/Cargo.toml b/engine-precompiles/Cargo.toml index ccdc9232c..4e392d9ce 100644 --- a/engine-precompiles/Cargo.toml +++ b/engine-precompiles/Cargo.toml @@ -17,19 +17,20 @@ aurora-engine-types = { path = "../engine-types", default-features = false } aurora-engine-sdk = { path = "../engine-sdk", default-features = false } borsh = { version = "0.9.3", default-features = false } bn = { version = "0.5.11", package = "zeropool-bn", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false } libsecp256k1 = { version = "0.7.0", default-features = false, features = ["static-context", "hmac"] } num = { version = "0.4.0", default-features = false, features = ["alloc"] } ripemd = { version = "0.1.1", default-features = false } sha2 = { version = "0.10.2", default-features = false } sha3 = { version = "0.10.2", default-features = false } -ethabi = { version = "17.1", default-features = false } +ethabi = { version = "18.0", default-features = false } hex = { version = "0.4", default-features = false, features = ["alloc"] } [dev-dependencies] +aurora-engine-test-doubles = { path = "../engine-test-doubles" } serde = { version = "1", features = ["derive"] } serde_json = "1" -rand = "0.7.3" +rand = "0.8.5" [features] default = ["std"] diff --git a/engine-precompiles/src/alt_bn256.rs b/engine-precompiles/src/alt_bn256.rs index dbb99f528..1619885a0 100644 --- a/engine-precompiles/src/alt_bn256.rs +++ b/engine-precompiles/src/alt_bn256.rs @@ -2,6 +2,7 @@ use crate::prelude::types::{Address, EthGas}; use crate::prelude::{Borrowed, PhantomData, Vec}; use crate::utils; use crate::{Byzantium, EvmPrecompileResult, HardFork, Istanbul, Precompile, PrecompileOutput}; +use bn::Group; use evm::{Context, ExitError}; /// bn128 costs. @@ -151,7 +152,7 @@ impl HostFnEncode for bn::G2 { /// Reads the `x` and `y` points from an input at a given position. fn read_point(input: &[u8], pos: usize) -> Result { - use bn::{AffineG1, Fq, Group, G1}; + use bn::{AffineG1, Fq, G1}; let px = Fq::from_slice(&input[pos..(pos + consts::SCALAR_LEN)]) .map_err(|_e| ExitError::Other(Borrowed("ERR_FQ_INCORRECT")))?; @@ -167,10 +168,11 @@ fn read_point(input: &[u8], pos: usize) -> Result { }) } -pub(super) struct Bn256Add(PhantomData); +#[derive(Default)] +pub struct Bn256Add(PhantomData); impl Bn256Add { - pub(super) const ADDRESS: Address = super::make_address(0, 6); + pub const ADDRESS: Address = super::make_address(0, 6); pub fn new() -> Self { Self(Default::default()) @@ -269,10 +271,11 @@ impl Precompile for Bn256Add { } } -pub(super) struct Bn256Mul(PhantomData); +#[derive(Default)] +pub struct Bn256Mul(PhantomData); impl Bn256Mul { - pub(super) const ADDRESS: Address = super::make_address(0, 7); + pub const ADDRESS: Address = super::make_address(0, 7); pub fn new() -> Self { Self(Default::default()) @@ -374,10 +377,11 @@ impl Precompile for Bn256Mul { } } -pub(super) struct Bn256Pair(PhantomData); +#[derive(Default)] +pub struct Bn256Pair(PhantomData); impl Bn256Pair { - pub(super) const ADDRESS: Address = super::make_address(0, 8); + pub const ADDRESS: Address = super::make_address(0, 8); pub fn new() -> Self { Self(Default::default()) @@ -427,16 +431,26 @@ impl Bn256Pair { ) .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_BBX")))?; - let g1_a = bn::AffineG1::new(ax, ay) - .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_A")))? - .into(); + let g1_a = { + if ax.is_zero() && ay.is_zero() { + bn::G1::zero() + } else { + bn::AffineG1::new(ax, ay) + .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_A")))? + .into() + } + }; let g1_b = { let ba = bn::Fq2::new(bax, bay); let bb = bn::Fq2::new(bbx, bby); - bn::AffineG2::new(ba, bb) - .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_B")))? - .into() + if ba.is_zero() && bb.is_zero() { + bn::G2::zero() + } else { + bn::AffineG2::new(ba, bb) + .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_B")))? + .into() + } }; vals.push((g1_a, g1_b)) } @@ -838,5 +852,26 @@ mod tests { res, Err(ExitError::Other(Borrowed("ERR_BN128_INVALID_LEN",))) )); + + // on curve + let input = hex::decode( + "\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000", + ) + .unwrap(); + let expected = + hex::decode("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); + + let res = Bn256Pair::::new() + .run(&input, Some(EthGas::new(260_000)), &new_context(), false) + .unwrap() + .output; + assert_eq!(res, expected); } } diff --git a/engine-precompiles/src/blake2.rs b/engine-precompiles/src/blake2.rs index 5d841e668..8c6b6d7fc 100644 --- a/engine-precompiles/src/blake2.rs +++ b/engine-precompiles/src/blake2.rs @@ -128,10 +128,10 @@ fn f(mut h: [u64; 8], m: [u64; 16], t: [u64; 2], f: bool, rounds: u32) -> Vec [u8; 20] { diff --git a/engine-precompiles/src/identity.rs b/engine-precompiles/src/identity.rs index 142dcd874..f898ee137 100644 --- a/engine-precompiles/src/identity.rs +++ b/engine-precompiles/src/identity.rs @@ -21,7 +21,7 @@ mod consts { pub struct Identity; impl Identity { - pub(super) const ADDRESS: Address = super::make_address(0, 4); + pub const ADDRESS: Address = super::make_address(0, 4); } impl Precompile for Identity { diff --git a/engine-precompiles/src/lib.rs b/engine-precompiles/src/lib.rs index 78a956e05..fc6d9cc4e 100644 --- a/engine-precompiles/src/lib.rs +++ b/engine-precompiles/src/lib.rs @@ -34,17 +34,17 @@ use crate::xcc::CrossContractCall; use aurora_engine_sdk::env::Env; use aurora_engine_sdk::io::IO; use aurora_engine_sdk::promise::ReadOnlyPromiseHandler; -use aurora_engine_types::{account_id::AccountId, types::Address, vec, BTreeMap, Box}; +use aurora_engine_types::{account_id::AccountId, types::Address, vec, BTreeMap, BTreeSet, Box}; use evm::backend::Log; use evm::executor::{ self, stack::{PrecompileFailure, PrecompileHandle}, }; -use evm::{Context, ExitError, ExitSucceed}; +use evm::{Context, ExitError, ExitFatal, ExitSucceed}; use promise_result::PromiseResult; use xcc::cross_contract_call; -#[derive(Debug, Default)] +#[derive(Debug, Default, PartialEq, Eq)] pub struct PrecompileOutput { pub cost: EthGas, pub output: Vec, @@ -112,6 +112,13 @@ impl HardFork for Berlin {} pub struct Precompiles<'a, I, E, H> { pub all_precompiles: prelude::BTreeMap>, + pub paused_precompiles: prelude::BTreeSet
, +} + +impl<'a, I, E, H> Precompiles<'a, I, E, H> { + fn is_paused(&self, address: &Address) -> bool { + self.paused_precompiles.contains(address) + } } impl<'a, I: IO + Copy, E: Env, H: ReadOnlyPromiseHandler> executor::stack::PrecompileSet @@ -121,9 +128,15 @@ impl<'a, I: IO + Copy, E: Env, H: ReadOnlyPromiseHandler> executor::stack::Preco &self, handle: &mut impl PrecompileHandle, ) -> Option> { - let address = handle.code_address(); + let address = Address::new(handle.code_address()); - let result = match self.all_precompiles.get(&Address::new(address))? { + if self.is_paused(&address) { + return Some(Err(PrecompileFailure::Fatal { + exit_status: ExitFatal::Other(prelude::Cow::Borrowed("ERR_PAUSED")), + })); + } + + let result = match self.all_precompiles.get(&address)? { AllPrecompiles::ExitToNear(p) => process_precompile(p, handle), AllPrecompiles::ExitToEthereum(p) => process_precompile(p, handle), AllPrecompiles::PredecessorAccount(p) => process_precompile(p, handle), @@ -132,6 +145,7 @@ impl<'a, I: IO + Copy, E: Env, H: ReadOnlyPromiseHandler> executor::stack::Preco AllPrecompiles::CrossContractCall(p) => process_handle_based_precompile(p, handle), AllPrecompiles::Generic(p) => process_precompile(p.as_ref(), handle), }; + Some(result.and_then(|output| post_process(output, handle))) } @@ -354,6 +368,7 @@ impl<'a, I: IO + Copy, E: Env, H: ReadOnlyPromiseHandler> Precompiles<'a, I, E, Self { all_precompiles: generic_precompiles, + paused_precompiles: BTreeSet::new(), } } } @@ -460,7 +475,7 @@ mod tests { #[test] fn test_make_address() { for i in 0..u8::MAX { - assert_eq!(super::make_address(0, i as u128), u8_to_address(i)); + assert_eq!(super::make_address(0, i.into()), u8_to_address(i)); } let mut rng = rand::thread_rng(); @@ -471,6 +486,130 @@ mod tests { } } + #[test] + fn test_paused_precompiles_throws_error() { + use crate::{ + AllPrecompiles, Context, EvmPrecompileResult, ExitError, Precompile, PrecompileOutput, + Precompiles, + }; + use aurora_engine_sdk::env::Fixed; + use aurora_engine_sdk::promise::Noop; + use aurora_engine_test_doubles::io::StoragePointer; + use aurora_engine_types::types::EthGas; + use evm::executor::stack::{PrecompileFailure, PrecompileHandle, PrecompileSet}; + use evm::{ExitFatal, ExitReason, Transfer}; + + struct MockPrecompile; + + impl Precompile for MockPrecompile { + fn required_gas(_input: &[u8]) -> Result + where + Self: Sized, + { + Ok(EthGas::new(0)) + } + + fn run( + &self, + _input: &[u8], + _target_gas: Option, + _context: &Context, + _is_static: bool, + ) -> EvmPrecompileResult { + Ok(PrecompileOutput::default()) + } + } + + struct MockPrecompileHandle { + code_address: H160, + } + + impl MockPrecompileHandle { + pub fn new(code_address: H160) -> Self { + Self { code_address } + } + } + + impl PrecompileHandle for MockPrecompileHandle { + fn call( + &mut self, + _to: H160, + _transfer: Option, + _input: Vec, + _gas_limit: Option, + _is_static: bool, + _context: &Context, + ) -> (ExitReason, Vec) { + unimplemented!() + } + + fn record_cost(&mut self, _cost: u64) -> Result<(), ExitError> { + unimplemented!() + } + + fn remaining_gas(&self) -> u64 { + unimplemented!() + } + + fn log( + &mut self, + _address: H160, + _topics: Vec, + _data: Vec, + ) -> Result<(), ExitError> { + unimplemented!() + } + + fn code_address(&self) -> H160 { + self.code_address + } + + fn input(&self) -> &[u8] { + unimplemented!() + } + + fn context(&self) -> &Context { + unimplemented!() + } + + fn is_static(&self) -> bool { + unimplemented!() + } + + fn gas_limit(&self) -> Option { + unimplemented!() + } + } + + let precompile_address = Address::default(); + let precompile: AllPrecompiles = + AllPrecompiles::Generic(Box::new(MockPrecompile)); + + let precompiles: Precompiles = Precompiles { + all_precompiles: { + let mut map = prelude::BTreeMap::new(); + map.insert(precompile_address, precompile); + map + }, + paused_precompiles: { + let mut set = prelude::BTreeSet::new(); + set.insert(precompile_address); + set + }, + }; + let mut precompile_handle = MockPrecompileHandle::new(precompile_address.raw()); + + let result = precompiles + .execute(&mut precompile_handle) + .expect("result must contain error but is empty"); + let actual_failure = result.expect_err("result must contain failure but is successful"); + let expected_failure = PrecompileFailure::Fatal { + exit_status: ExitFatal::Other(prelude::Cow::Borrowed("ERR_PAUSED")), + }; + + assert_eq!(expected_failure, actual_failure); + } + fn u8_to_address(x: u8) -> Address { let mut bytes = [0u8; 20]; bytes[19] = x; diff --git a/engine-precompiles/src/modexp.rs b/engine-precompiles/src/modexp.rs index bf56d5bf8..686a664d7 100644 --- a/engine-precompiles/src/modexp.rs +++ b/engine-precompiles/src/modexp.rs @@ -6,10 +6,11 @@ use crate::{ use evm::{Context, ExitError}; use num::{BigUint, Integer}; -pub(super) struct ModExp(PhantomData); +#[derive(Default)] +pub struct ModExp(PhantomData); impl ModExp { - pub(super) const ADDRESS: Address = super::make_address(0, 5); + pub const ADDRESS: Address = super::make_address(0, 5); pub fn new() -> Self { Self(Default::default()) @@ -21,7 +22,6 @@ impl ModExp { fn calc_iter_count(exp_len: u64, base_len: u64, bytes: &[u8]) -> Result { let start = usize::try_from(base_len).map_err(utils::err_usize_conv)?; let exp_len = usize::try_from(exp_len).map_err(utils::err_usize_conv)?; - // #[allow(clippy::redundant_closure)] let exp = parse_bytes( bytes, start.saturating_add(96), @@ -146,7 +146,7 @@ impl Precompile for ModExp { let mul = Self::mul_complexity(base_len, mod_len); let iter_count = Self::calc_iter_count(exp_len, base_len, input)?; // mul * iter_count bounded by 2^189 (so no overflow) - let gas = mul * iter_count / U256::from(3); + let gas = mul * iter_count.max(U256::one()) / U256::from(3); Ok(EthGas::new(core::cmp::max(200, saturating_round(gas)))) } @@ -418,13 +418,13 @@ mod tests { #[test] fn test_modexp() { for (test, test_gas) in TESTS.iter().zip(BYZANTIUM_GAS.iter()) { - let input = hex::decode(&test.input).unwrap(); + let input = hex::decode(test.input).unwrap(); let res = ModExp::::new() .run(&input, Some(*test_gas), &new_context(), false) .unwrap() .output; - let expected = hex::decode(&test.expected).unwrap(); + let expected = hex::decode(test.expected).unwrap(); assert_eq!(res, expected, "{}", test.name); } } @@ -432,7 +432,7 @@ mod tests { #[test] fn test_byzantium_modexp_gas() { for (test, test_gas) in TESTS.iter().zip(BYZANTIUM_GAS.iter()) { - let input = hex::decode(&test.input).unwrap(); + let input = hex::decode(test.input).unwrap(); let gas = ModExp::::required_gas(&input).unwrap(); assert_eq!(gas, *test_gas, "{} gas", test.name); @@ -442,7 +442,7 @@ mod tests { #[test] fn test_berlin_modexp_gas() { for (test, test_gas) in TESTS.iter().zip(BERLIN_GAS.iter()) { - let input = hex::decode(&test.input).unwrap(); + let input = hex::decode(test.input).unwrap(); let gas = ModExp::::required_gas(&input).unwrap(); assert_eq!(gas, *test_gas, "{} gas", test.name); @@ -495,4 +495,17 @@ mod tests { let expected: Vec = Vec::new(); assert_eq!(res.output, expected) } + + #[test] + fn test_modexp_gas_revert() { + let input = "000000000000090000000000000000"; + // Gas cost comes out to 18446744073709551615 + let res = ModExp::::new().run( + &hex::decode(input).unwrap(), + Some(EthGas::new(100_000)), + &new_context(), + false, + ); + assert_eq!(Err(ExitError::OutOfGas), res); + } } diff --git a/engine-precompiles/src/native.rs b/engine-precompiles/src/native.rs index ed3c17699..91064c96b 100644 --- a/engine-precompiles/src/native.rs +++ b/engine-precompiles/src/native.rs @@ -30,8 +30,12 @@ mod costs { // TODO(#483): Determine the correct amount of gas pub(super) const EXIT_TO_ETHEREUM_GAS: EthGas = EthGas::new(0); + /// Value determined experimentally based on tests and mainnet data. Example: + /// https://explorer.mainnet.near.org/transactions/5CD7NrqWpK3H8MAAU4mYEPuuWz9AqR9uJkkZJzw5b8PM#D1b5NVRrAsJKUX2ZGs3poKViu1Rgt4RJZXtTfMgdxH4S pub(super) const FT_TRANSFER_GAS: NearGas = NearGas::new(10_000_000_000_000); + /// Value determined experimentally based on tests. + /// (No mainnet data available since this feature is not enabled) #[cfg(feature = "error_refund")] pub(super) const REFUND_ON_ERROR_GAS: NearGas = NearGas::new(5_000_000_000_000); diff --git a/engine-precompiles/src/promise_result.rs b/engine-precompiles/src/promise_result.rs index 1899f66a6..223536c65 100644 --- a/engine-precompiles/src/promise_result.rs +++ b/engine-precompiles/src/promise_result.rs @@ -16,7 +16,7 @@ pub mod costs { use crate::prelude::types::EthGas; /// This cost is always charged for calling this precompile. - pub const PROMISE_RESULT_BASE_COST: EthGas = EthGas::new(125); + pub const PROMISE_RESULT_BASE_COST: EthGas = EthGas::new(105); /// This is the cost per byte of promise result data. pub const PROMISE_RESULT_BYTE_COST: EthGas = EthGas::new(1); } diff --git a/engine-precompiles/src/secp256k1.rs b/engine-precompiles/src/secp256k1.rs index f66a06a5e..4e862a93d 100644 --- a/engine-precompiles/src/secp256k1.rs +++ b/engine-precompiles/src/secp256k1.rs @@ -56,7 +56,7 @@ fn internal_impl(hash: H256, signature: &[u8]) -> Result { pub struct ECRecover; impl ECRecover { - pub(super) const ADDRESS: Address = super::make_address(0, 1); + pub const ADDRESS: Address = super::make_address(0, 1); } impl Precompile for ECRecover { @@ -135,7 +135,7 @@ mod tests { &hex::decode("1563915e194D8CfBA1943570603F7606A3115508").unwrap(), ) .unwrap(); - assert!(ecverify(hash, &signature, signer)); + assert!(ecverify(hash, signature, signer)); } #[test] diff --git a/engine-precompiles/src/xcc.rs b/engine-precompiles/src/xcc.rs index e8e009ad2..d902a3f7b 100644 --- a/engine-precompiles/src/xcc.rs +++ b/engine-precompiles/src/xcc.rs @@ -9,7 +9,7 @@ use aurora_engine_types::{ account_id::AccountId, format, parameters::{CrossContractCallArgs, PromiseCreateArgs}, - types::{balance::ZERO_YOCTO, Address, EthGas}, + types::{balance::ZERO_YOCTO, Address, EthGas, NearGas}, vec, Cow, Vec, H160, H256, U256, }; use borsh::{BorshDeserialize, BorshSerialize}; @@ -42,7 +42,8 @@ pub mod costs { /// `NEAR Gas / EVM Gas`, we simply multiply `0.175 * 10^12 / 10^3 = 175 * 10^6`. pub const CROSS_CONTRACT_CALL_NEAR_GAS: u64 = 175_000_000; - pub const ROUTER_EXEC: NearGas = NearGas::new(7_000_000_000_000); + pub const ROUTER_EXEC_BASE: NearGas = NearGas::new(7_000_000_000_000); + pub const ROUTER_EXEC_PER_CALLBACK: NearGas = NearGas::new(12_000_000_000_000); pub const ROUTER_SCHEDULE: NearGas = NearGas::new(5_000_000_000_000); } @@ -130,6 +131,9 @@ impl HandleBasedPrecompile for CrossContractCall { CrossContractCallArgs::Eager(call) => { let call_gas = call.total_gas(); let attached_near = call.total_near(); + let callback_count = call.promise_count() - 1; + let router_exec_cost = costs::ROUTER_EXEC_BASE + + NearGas::new(callback_count * costs::ROUTER_EXEC_PER_CALLBACK.as_u64()); let promise = PromiseCreateArgs { target_account_id, method: consts::ROUTER_EXEC_NAME.into(), @@ -137,7 +141,7 @@ impl HandleBasedPrecompile for CrossContractCall { .try_to_vec() .map_err(|_| ExitError::Other(Cow::from(consts::ERR_SERIALIZE)))?, attached_balance: ZERO_YOCTO, - attached_gas: costs::ROUTER_EXEC + call_gas, + attached_gas: router_exec_cost + call_gas, }; (promise, attached_near) } diff --git a/engine-sdk/Cargo.toml b/engine-sdk/Cargo.toml index c6a127a03..11aaef8bf 100644 --- a/engine-sdk/Cargo.toml +++ b/engine-sdk/Cargo.toml @@ -22,5 +22,6 @@ sha2 = { version = "0.10.2", default-features = false } std = ["aurora-engine-types/std", "borsh/std", "sha3/std", "sha2/std"] contract = [] log = [] +all-promise-actions = [] mainnet = [] testnet = [] diff --git a/engine-sdk/src/env.rs b/engine-sdk/src/env.rs index b0d73d0ea..6140f823a 100644 --- a/engine-sdk/src/env.rs +++ b/engine-sdk/src/env.rs @@ -5,7 +5,7 @@ use aurora_engine_types::account_id::AccountId; pub const DEFAULT_PREPAID_GAS: NearGas = NearGas::new(300_000_000_000_000); /// Timestamp represented by the number of nanoseconds since the Unix Epoch. -#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct Timestamp(u64); impl Timestamp { @@ -67,7 +67,7 @@ pub trait Env { /// Fully in-memory implementation of the blockchain environment with /// fixed values for all the fields. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct Fixed { pub signer_account_id: AccountId, pub current_account_id: AccountId, diff --git a/engine-sdk/src/lib.rs b/engine-sdk/src/lib.rs index fd20909d5..2c93b7088 100644 --- a/engine-sdk/src/lib.rs +++ b/engine-sdk/src/lib.rs @@ -185,9 +185,9 @@ pub fn log(_data: &str) { #[macro_export] macro_rules! log { - ($e: expr) => { + ($($args:tt)*) => { #[cfg(feature = "log")] - $crate::log($e) + $crate::log(&aurora_engine_types::format!("{}", format_args!($($args)*))) }; } diff --git a/engine-sdk/src/near_runtime.rs b/engine-sdk/src/near_runtime.rs index a62640f75..c9dc79d4a 100644 --- a/engine-sdk/src/near_runtime.rs +++ b/engine-sdk/src/near_runtime.rs @@ -2,7 +2,9 @@ use crate::io::StorageIntermediate; use crate::prelude::NearGas; use crate::promise::PromiseId; use aurora_engine_types::account_id::AccountId; -use aurora_engine_types::parameters::{PromiseAction, PromiseBatchAction, PromiseCreateArgs}; +use aurora_engine_types::parameters::{ + NearPublicKey, PromiseAction, PromiseBatchAction, PromiseCreateArgs, +}; use aurora_engine_types::types::PromiseResult; use aurora_engine_types::H256; @@ -18,6 +20,16 @@ const CUSTODIAN_ADDRESS: &[u8] = &[ 132, 168, 43, 179, 156, 131, 152, 157, 93, 192, 126, 19, 16, 40, 25, 35, 210, 84, 77, 194, ]; +macro_rules! feature_gated { + ($feature_name:literal, $code:block) => { + if cfg!(feature = $feature_name) { + $code + } else { + unimplemented!("Not implemented without feature {}", $feature_name) + } + }; +} + /// Wrapper type for indices in NEAR's register API. pub struct RegisterIndex(u64); @@ -280,14 +292,14 @@ impl crate::promise::PromiseHandler for Runtime { } } - fn promise_create_call(&mut self, args: &PromiseCreateArgs) -> PromiseId { + unsafe fn promise_create_call(&mut self, args: &PromiseCreateArgs) -> PromiseId { let account_id = args.target_account_id.as_bytes(); let method_name = args.method.as_bytes(); let arguments = args.args.as_slice(); let amount = args.attached_balance.as_u128(); let gas = args.attached_gas.as_u64(); - let id = unsafe { + let id = { exports::promise_create( account_id.len() as _, account_id.as_ptr() as _, @@ -302,7 +314,7 @@ impl crate::promise::PromiseHandler for Runtime { PromiseId::new(id) } - fn promise_attach_callback( + unsafe fn promise_attach_callback( &mut self, base: PromiseId, callback: &PromiseCreateArgs, @@ -313,7 +325,7 @@ impl crate::promise::PromiseHandler for Runtime { let amount = callback.attached_balance.as_u128(); let gas = callback.attached_gas.as_u64(); - let id = unsafe { + let id = { exports::promise_then( base.raw(), account_id.len() as _, @@ -330,36 +342,34 @@ impl crate::promise::PromiseHandler for Runtime { PromiseId::new(id) } - fn promise_create_batch(&mut self, args: &PromiseBatchAction) -> PromiseId { + unsafe fn promise_create_batch(&mut self, args: &PromiseBatchAction) -> PromiseId { let account_id = args.target_account_id.as_bytes(); - let id = unsafe { - exports::promise_batch_create(account_id.len() as _, account_id.as_ptr() as _) - }; + let id = { exports::promise_batch_create(account_id.len() as _, account_id.as_ptr() as _) }; for action in args.actions.iter() { match action { - PromiseAction::CreateAccount => unsafe { + PromiseAction::CreateAccount => { exports::promise_batch_action_create_account(id); - }, - PromiseAction::Transfer { amount } => unsafe { + } + PromiseAction::Transfer { amount } => { let amount = amount.as_u128(); exports::promise_batch_action_transfer(id, &amount as *const u128 as _); - }, - PromiseAction::DeployConotract { code } => unsafe { + } + PromiseAction::DeployContract { code } => { let code = code.as_slice(); exports::promise_batch_action_deploy_contract( id, code.len() as _, code.as_ptr() as _, ); - }, + } PromiseAction::FunctionCall { name, gas, attached_yocto, args, - } => unsafe { + } => { let method_name = name.as_bytes(); let arguments = args.as_slice(); let amount = attached_yocto.as_u128(); @@ -372,7 +382,79 @@ impl crate::promise::PromiseHandler for Runtime { &amount as *const u128 as _, gas.as_u64(), ) - }, + } + PromiseAction::Stake { amount, public_key } => { + feature_gated!("all-promise-actions", { + let amount = amount.as_u128(); + let pk: RawPublicKey = public_key.into(); + let pk_bytes = pk.as_bytes(); + exports::promise_batch_action_stake( + id, + &amount as *const u128 as _, + pk_bytes.len() as _, + pk_bytes.as_ptr() as _, + ) + }); + } + PromiseAction::AddFullAccessKey { public_key, nonce } => { + feature_gated!("all-promise-actions", { + let pk: RawPublicKey = public_key.into(); + let pk_bytes = pk.as_bytes(); + exports::promise_batch_action_add_key_with_full_access( + id, + pk_bytes.len() as _, + pk_bytes.as_ptr() as _, + *nonce, + ) + }); + } + PromiseAction::AddFunctionCallKey { + public_key, + nonce, + allowance, + receiver_id, + function_names, + } => { + feature_gated!("all-promise-actions", { + let pk: RawPublicKey = public_key.into(); + let pk_bytes = pk.as_bytes(); + let allowance = allowance.as_u128(); + let receiver_id = receiver_id.as_bytes(); + let function_names = function_names.as_bytes(); + exports::promise_batch_action_add_key_with_function_call( + id, + pk_bytes.len() as _, + pk_bytes.as_ptr() as _, + *nonce, + &allowance as *const u128 as _, + receiver_id.len() as _, + receiver_id.as_ptr() as _, + function_names.len() as _, + function_names.as_ptr() as _, + ) + }); + } + PromiseAction::DeleteKey { public_key } => { + feature_gated!("all-promise-actions", { + let pk: RawPublicKey = public_key.into(); + let pk_bytes = pk.as_bytes(); + exports::promise_batch_action_delete_key( + id, + pk_bytes.len() as _, + pk_bytes.as_ptr() as _, + ) + }); + } + PromiseAction::DeleteAccount { beneficiary_id } => { + feature_gated!("all-promise-actions", { + let beneficiary_id = beneficiary_id.as_bytes(); + exports::promise_batch_action_delete_key( + id, + beneficiary_id.len() as _, + beneficiary_id.as_ptr() as _, + ) + }); + } } } @@ -390,6 +472,40 @@ impl crate::promise::PromiseHandler for Runtime { } } +/// Similar to NearPublicKey, except the first byte includes +/// the curve identifier. +enum RawPublicKey { + Ed25519([u8; 33]), + Secp256k1([u8; 65]), +} + +impl RawPublicKey { + fn as_bytes(&self) -> &[u8] { + match self { + Self::Ed25519(bytes) => bytes, + Self::Secp256k1(bytes) => bytes, + } + } +} + +impl<'a> From<&'a NearPublicKey> for RawPublicKey { + fn from(key: &'a NearPublicKey) -> Self { + match key { + NearPublicKey::Ed25519(bytes) => { + let mut buf = [0u8; 33]; + buf[1..33].copy_from_slice(bytes); + Self::Ed25519(buf) + } + NearPublicKey::Secp256k1(bytes) => { + let mut buf = [0u8; 65]; + buf[0] = 0x01; + buf[1..65].copy_from_slice(bytes); + Self::Secp256k1(buf) + } + } + } +} + /// Some host functions are not usable in NEAR view calls. /// This struct puts in default values for those calls instead. pub struct ViewEnv; @@ -539,19 +655,19 @@ pub(crate) mod exports { gas: u64, ); pub(crate) fn promise_batch_action_transfer(promise_index: u64, amount_ptr: u64); - fn promise_batch_action_stake( + pub(crate) fn promise_batch_action_stake( promise_index: u64, amount_ptr: u64, public_key_len: u64, public_key_ptr: u64, ); - fn promise_batch_action_add_key_with_full_access( + pub(crate) fn promise_batch_action_add_key_with_full_access( promise_index: u64, public_key_len: u64, public_key_ptr: u64, nonce: u64, ); - fn promise_batch_action_add_key_with_function_call( + pub(crate) fn promise_batch_action_add_key_with_function_call( promise_index: u64, public_key_len: u64, public_key_ptr: u64, @@ -562,12 +678,12 @@ pub(crate) mod exports { method_names_len: u64, method_names_ptr: u64, ); - fn promise_batch_action_delete_key( + pub(crate) fn promise_batch_action_delete_key( promise_index: u64, public_key_len: u64, public_key_ptr: u64, ); - fn promise_batch_action_delete_account( + pub(crate) fn promise_batch_action_delete_account( promise_index: u64, beneficiary_id_len: u64, beneficiary_id_ptr: u64, diff --git a/engine-sdk/src/promise.rs b/engine-sdk/src/promise.rs index c6f0bac73..17f5a03cb 100644 --- a/engine-sdk/src/promise.rs +++ b/engine-sdk/src/promise.rs @@ -22,16 +22,33 @@ pub trait PromiseHandler { fn promise_results_count(&self) -> u64; fn promise_result(&self, index: u64) -> Option; - fn promise_create_call(&mut self, args: &PromiseCreateArgs) -> PromiseId; - fn promise_attach_callback( + /// # Safety + /// Creating calls to other contracts using the Engine account is dangerous because + /// it has special admin privileges (especially with itself), for example minting + /// bridged tokens. Therefore, this function must be used with extreme caution to prevent + /// security vulnerabilities. In particular, it must not be possible for users to execute + /// arbitrary calls using the Engine. + unsafe fn promise_create_call(&mut self, args: &PromiseCreateArgs) -> PromiseId; + + /// # Safety + /// See note on `promise_create_call`. + unsafe fn promise_attach_callback( &mut self, base: PromiseId, callback: &PromiseCreateArgs, ) -> PromiseId; - fn promise_create_batch(&mut self, args: &PromiseBatchAction) -> PromiseId; + + /// # Safety + /// See note on `promise_create_call`. Promise batches in particular must be used very + /// carefully because they can take destructive actions such as deploying new contract + /// code or adding/removing access keys. + unsafe fn promise_create_batch(&mut self, args: &PromiseBatchAction) -> PromiseId; + fn promise_return(&mut self, promise: PromiseId); - fn promise_create_with_callback(&mut self, args: &PromiseWithCallbackArgs) -> PromiseId { + /// # Safety + /// See note on `promise_create_call`. + unsafe fn promise_create_with_callback(&mut self, args: &PromiseWithCallbackArgs) -> PromiseId { let base = self.promise_create_call(&args.base); self.promise_attach_callback(base, &args.callback) } @@ -69,11 +86,11 @@ impl PromiseHandler for Noop { None } - fn promise_create_call(&mut self, _args: &PromiseCreateArgs) -> PromiseId { + unsafe fn promise_create_call(&mut self, _args: &PromiseCreateArgs) -> PromiseId { PromiseId::new(0) } - fn promise_attach_callback( + unsafe fn promise_attach_callback( &mut self, _base: PromiseId, _callback: &PromiseCreateArgs, @@ -81,7 +98,7 @@ impl PromiseHandler for Noop { PromiseId::new(0) } - fn promise_create_batch(&mut self, _args: &PromiseBatchAction) -> PromiseId { + unsafe fn promise_create_batch(&mut self, _args: &PromiseBatchAction) -> PromiseId { PromiseId::new(0) } diff --git a/engine-standalone-storage/Cargo.toml b/engine-standalone-storage/Cargo.toml index 16aefd3e5..866a62579 100644 --- a/engine-standalone-storage/Cargo.toml +++ b/engine-standalone-storage/Cargo.toml @@ -18,9 +18,11 @@ aurora-engine = { path = "../engine", default-features = false, features = ["std aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features = ["std"] } aurora-engine-transactions = { path = "../engine-transactions", default-features = false, features = ["std"] } +aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false, features = ["std"] } borsh = { version = "0.9.3" } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false } -rocksdb = { version = "0.18.0", default-features = false } +evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false } +hex = "0.4.3" +rocksdb = { version = "0.19.0", default-features = false } postgres = "0.19.2" serde = "1.0.130" serde_json = "1.0.72" diff --git a/engine-standalone-storage/src/engine_state.rs b/engine-standalone-storage/src/engine_state.rs index 0f42b8502..2d5125253 100644 --- a/engine-standalone-storage/src/engine_state.rs +++ b/engine-standalone-storage/src/engine_state.rs @@ -14,7 +14,7 @@ pub enum EngineStorageValue<'a> { impl<'a> AsRef<[u8]> for EngineStorageValue<'a> { fn as_ref(&self) -> &[u8] { match self { - Self::Slice(slice) => *slice, + Self::Slice(slice) => slice, Self::Vec(bytes) => bytes, } } @@ -98,9 +98,11 @@ impl<'db, 'input: 'db, 'output: 'db> IO for EngineStateAccess<'db, 'input, 'outp let opt = self.construct_engine_read(key); let mut iter = self.db.iterator_opt(rocksdb::IteratorMode::End, opt); - let value = iter - .next() - .map(|(_, value)| DiffValue::try_from_bytes(&value).unwrap())?; + let value = iter.next().and_then(|maybe_elem| { + maybe_elem + .ok() + .map(|(_, value)| DiffValue::try_from_bytes(&value).unwrap()) + })?; value.take_value().map(EngineStorageValue::Vec) } diff --git a/engine-standalone-storage/src/lib.rs b/engine-standalone-storage/src/lib.rs index 99e11aa28..0f536c09b 100644 --- a/engine-standalone-storage/src/lib.rs +++ b/engine-standalone-storage/src/lib.rs @@ -82,17 +82,14 @@ impl Storage { opt.set_iterate_lower_bound(lower_bound); let mut iter = self.db.iterator_opt(mode, opt); - iter.next() - .map(|(key, value)| { - let block_height = { - let mut buf = [0u8; 8]; - buf.copy_from_slice(&key[prefix_len..]); - u64::from_be_bytes(buf) - }; - let block_hash = H256::from_slice(&value); - (block_hash, block_height) - }) - .ok_or(error::Error::NoBlockAtHeight(0)) + let (key, value) = iter.next().ok_or(error::Error::NoBlockAtHeight(0))??; + let block_height = { + let mut buf = [0u8; 8]; + buf.copy_from_slice(&key[prefix_len..]); + u64::from_be_bytes(buf) + }; + let block_hash = H256::from_slice(&value); + Ok((block_hash, block_height)) } pub fn get_block_hash_by_height(&self, block_height: u64) -> Result { @@ -254,7 +251,8 @@ impl Storage { let n = db_key_prefix.len(); let iter = self.db.prefix_iterator(&db_key_prefix); let mut result = Vec::with_capacity(100); - for (k, v) in iter { + for maybe_elem in iter { + let (k, v) = maybe_elem?; if k.len() < n || k[0..n] != db_key_prefix { break; } diff --git a/engine-standalone-storage/src/promise.rs b/engine-standalone-storage/src/promise.rs index 19ff476d9..a508305b1 100644 --- a/engine-standalone-storage/src/promise.rs +++ b/engine-standalone-storage/src/promise.rs @@ -29,11 +29,11 @@ impl<'a> PromiseHandler for NoScheduler<'a> { Some(result) } - fn promise_create_call(&mut self, _args: &PromiseCreateArgs) -> PromiseId { + unsafe fn promise_create_call(&mut self, _args: &PromiseCreateArgs) -> PromiseId { PromiseId::new(0) } - fn promise_attach_callback( + unsafe fn promise_attach_callback( &mut self, _base: PromiseId, _callback: &PromiseCreateArgs, @@ -41,7 +41,7 @@ impl<'a> PromiseHandler for NoScheduler<'a> { PromiseId::new(0) } - fn promise_create_batch(&mut self, _args: &PromiseBatchAction) -> PromiseId { + unsafe fn promise_create_batch(&mut self, _args: &PromiseBatchAction) -> PromiseId { PromiseId::new(0) } diff --git a/engine-standalone-storage/src/relayer_db/mod.rs b/engine-standalone-storage/src/relayer_db/mod.rs index b2f7b68a6..80fefca95 100644 --- a/engine-standalone-storage/src/relayer_db/mod.rs +++ b/engine-standalone-storage/src/relayer_db/mod.rs @@ -230,7 +230,7 @@ mod test { .set_block_data(block_hash, block_height, block_metadata) .unwrap(); let result = storage.with_engine_access(block_height, 0, &[], |io| { - let mut local_io = io.clone(); + let mut local_io = io; engine::set_state(&mut local_io, engine_state.clone()); connector::EthConnectorContract::create_contract( io, diff --git a/engine-standalone-storage/src/sync/mod.rs b/engine-standalone-storage/src/sync/mod.rs index 407526e2f..9142e6b86 100644 --- a/engine-standalone-storage/src/sync/mod.rs +++ b/engine-standalone-storage/src/sync/mod.rs @@ -1,3 +1,6 @@ +use aurora_engine::pausables::{ + EnginePrecompilesPauser, PausedPrecompilesManager, PrecompileFlags, +}; use aurora_engine::{connector, engine, parameters::SubmitResult, xcc}; use aurora_engine_sdk::env::{self, Env, DEFAULT_PREPAID_GAS}; use aurora_engine_types::{ @@ -222,7 +225,6 @@ fn non_submit_execute<'db>( } else { engine.receive_erc20_tokens( &env.predecessor_account_id, - &env.signer_account_id, args, &env.current_account_id, &mut handler, @@ -388,6 +390,22 @@ fn non_submit_execute<'db>( TransactionKind::Unknown => None, // Not handled in this function; is handled by the general `execute_transaction` function TransactionKind::Submit(_) => unreachable!(), + TransactionKind::PausePrecompiles(args) => { + let precompiles_to_pause = PrecompileFlags::from_bits_truncate(args.paused_mask); + + let mut pauser = EnginePrecompilesPauser::from_io(io); + pauser.pause_precompiles(precompiles_to_pause); + + None + } + TransactionKind::ResumePrecompiles(args) => { + let precompiles_to_resume = PrecompileFlags::from_bits_truncate(args.paused_mask); + + let mut pauser = EnginePrecompilesPauser::from_io(io); + pauser.resume_precompiles(precompiles_to_resume); + + None + } }; Ok(result) diff --git a/engine-standalone-storage/src/sync/types.rs b/engine-standalone-storage/src/sync/types.rs index 4d732ab50..c3eb652ca 100644 --- a/engine-standalone-storage/src/sync/types.rs +++ b/engine-standalone-storage/src/sync/types.rs @@ -1,8 +1,14 @@ +use crate::Storage; use aurora_engine::parameters; +use aurora_engine::parameters::PausePrecompilesCallArgs; use aurora_engine::xcc::AddressVersionUpdateArgs; -use aurora_engine_transactions::EthTransactionKind; +use aurora_engine_transactions::{EthTransactionKind, NormalizedEthTransaction}; use aurora_engine_types::account_id::AccountId; -use aurora_engine_types::{types, H256}; +use aurora_engine_types::types::Address; +use aurora_engine_types::{ + types::{self, Wei}, + H256, U256, +}; use borsh::{BorshDeserialize, BorshSerialize}; use std::borrow::Cow; @@ -72,6 +78,10 @@ pub enum TransactionKind { Submit(EthTransactionKind), /// Ethereum transaction triggered by a NEAR account Call(parameters::CallArgs), + /// Administrative method that makes a subset of precompiles paused + PausePrecompiles(PausePrecompilesCallArgs), + /// Administrative method that resumes previously paused subset of precompiles + ResumePrecompiles(PausePrecompilesCallArgs), /// Input here represents the EVM code used to create the new contract Deploy(Vec), /// New bridged token @@ -119,6 +129,254 @@ pub enum TransactionKind { Unknown, } +impl TransactionKind { + pub fn eth_repr( + self, + engine_account: &AccountId, + caller: &AccountId, + block_height: u64, + transaction_position: u16, + storage: &Storage, + ) -> NormalizedEthTransaction { + match self { + // In the case the submit arg fails to normalize, there is no EVM execution + Self::Submit(eth_tx_kind) => eth_tx_kind + .try_into() + .unwrap_or_else(|_| Self::no_evm_execution("submit")), + Self::Call(call_args) => { + let from = Self::get_implicit_address(caller); + let nonce = + Self::get_implicit_nonce(&from, block_height, transaction_position, storage); + let (to, data, value) = match call_args { + parameters::CallArgs::V1(args) => (args.contract, args.input, Wei::zero()), + parameters::CallArgs::V2(args) => ( + args.contract, + args.input, + Wei::new(U256::from_big_endian(&args.value)), + ), + }; + NormalizedEthTransaction { + address: from, + chain_id: None, + nonce, + gas_limit: U256::from(u64::MAX), + max_priority_fee_per_gas: U256::zero(), + max_fee_per_gas: U256::zero(), + to: Some(to), + value, + data, + access_list: Vec::new(), + } + } + Self::Deploy(data) => { + let from = Self::get_implicit_address(caller); + let nonce = + Self::get_implicit_nonce(&from, block_height, transaction_position, storage); + NormalizedEthTransaction { + address: from, + chain_id: None, + nonce, + gas_limit: U256::from(u64::MAX), + max_priority_fee_per_gas: U256::zero(), + max_fee_per_gas: U256::zero(), + to: None, + value: Wei::zero(), + data, + access_list: Vec::new(), + } + } + Self::DeployErc20(_) => { + let from = Self::get_implicit_address(caller); + let nonce = + Self::get_implicit_nonce(&from, block_height, transaction_position, storage); + let data = aurora_engine::engine::setup_deploy_erc20_input(engine_account); + NormalizedEthTransaction { + address: from, + chain_id: None, + nonce, + gas_limit: U256::from(u64::MAX), + max_priority_fee_per_gas: U256::zero(), + max_fee_per_gas: U256::zero(), + to: None, + value: Wei::zero(), + data, + access_list: Vec::new(), + } + } + Self::FtOnTransfer(args) => { + if engine_account == caller { + let recipient = aurora_engine::deposit_event::FtTransferMessageData::parse_on_transfer_message(&args.msg).map(|data| data.recipient).unwrap_or_default(); + let value = Wei::new(U256::from(args.amount.as_u128())); + // This transaction mints new ETH, so we'll say it comes from the zero address. + NormalizedEthTransaction { + address: types::Address::default(), + chain_id: None, + nonce: U256::zero(), + gas_limit: U256::from(u64::MAX), + max_priority_fee_per_gas: U256::zero(), + max_fee_per_gas: U256::zero(), + to: Some(recipient), + value, + data: Vec::new(), + access_list: Vec::new(), + } + } else { + let from = Self::get_implicit_address(engine_account); + let nonce = Self::get_implicit_nonce( + &from, + block_height, + transaction_position, + storage, + ); + let to = storage + .with_engine_access(block_height, transaction_position, &[], |io| { + aurora_engine::engine::get_erc20_from_nep141(&io, caller) + }) + .result + .ok() + .and_then(|bytes| types::Address::try_from_slice(&bytes).ok()) + .unwrap_or_default(); + let erc20_recipient = hex::decode(&args.msg.as_bytes()[0..40]) + .ok() + .and_then(|bytes| types::Address::try_from_slice(&bytes).ok()) + .unwrap_or_default(); + let data = aurora_engine::engine::setup_receive_erc20_tokens_input( + &args, + &erc20_recipient, + ); + NormalizedEthTransaction { + address: from, + chain_id: None, + nonce, + gas_limit: U256::from(u64::MAX), + max_priority_fee_per_gas: U256::zero(), + max_fee_per_gas: U256::zero(), + to: Some(to), + value: Wei::zero(), + data, + access_list: Vec::new(), + } + } + } + Self::RefundOnError(maybe_args) => { + match maybe_args { + Some(args) => match args.erc20_address { + Some(erc20_address) => { + // ERC-20 refund + let from = Self::get_implicit_address(engine_account); + let nonce = Self::get_implicit_nonce( + &from, + block_height, + transaction_position, + storage, + ); + let to = erc20_address; + let data = aurora_engine::engine::setup_refund_on_error_input( + U256::from_big_endian(&args.amount), + args.recipient_address, + ); + NormalizedEthTransaction { + address: from, + chain_id: None, + nonce, + gas_limit: U256::from(u64::MAX), + max_priority_fee_per_gas: U256::zero(), + max_fee_per_gas: U256::zero(), + to: Some(to), + value: Wei::zero(), + data, + access_list: Vec::new(), + } + } + None => { + // ETH refund + let value = Wei::new(U256::from_big_endian(&args.amount)); + let from = aurora_engine_precompiles::native::exit_to_near::ADDRESS; + let nonce = Self::get_implicit_nonce( + &from, + block_height, + transaction_position, + storage, + ); + NormalizedEthTransaction { + address: from, + chain_id: None, + nonce, + gas_limit: U256::from(u64::MAX), + max_priority_fee_per_gas: U256::zero(), + max_fee_per_gas: U256::zero(), + to: Some(args.recipient_address), + value, + data: Vec::new(), + access_list: Vec::new(), + } + } + }, + None => Self::no_evm_execution("refund_on_error"), + } + } + Self::Deposit(_) => Self::no_evm_execution("deposit"), + Self::FtTransferCall(_) => Self::no_evm_execution("ft_transfer_call"), + Self::FinishDeposit(_) => Self::no_evm_execution("finish_deposit"), + Self::ResolveTransfer(_, _) => Self::no_evm_execution("resolve_transfer"), + Self::FtTransfer(_) => Self::no_evm_execution("ft_transfer"), + TransactionKind::Withdraw(_) => Self::no_evm_execution("withdraw"), + TransactionKind::StorageDeposit(_) => Self::no_evm_execution("storage_deposit"), + TransactionKind::StorageUnregister(_) => Self::no_evm_execution("storage_unregister"), + TransactionKind::StorageWithdraw(_) => Self::no_evm_execution("storage_withdraw"), + TransactionKind::SetPausedFlags(_) => Self::no_evm_execution("set_paused_flags"), + TransactionKind::RegisterRelayer(_) => Self::no_evm_execution("register_relayer"), + TransactionKind::SetConnectorData(_) => Self::no_evm_execution("set_connector_data"), + TransactionKind::NewConnector(_) => Self::no_evm_execution("new_connector"), + TransactionKind::NewEngine(_) => Self::no_evm_execution("new_engine"), + TransactionKind::FactoryUpdate(_) => Self::no_evm_execution("factory_update"), + TransactionKind::FactoryUpdateAddressVersion(_) => { + Self::no_evm_execution("factory_update_address_version") + } + TransactionKind::FactorySetWNearAddress(_) => { + Self::no_evm_execution("factory_set_wnear_address") + } + TransactionKind::Unknown => Self::no_evm_execution("unknown"), + Self::PausePrecompiles(_) => Self::no_evm_execution("pause_precompiles"), + Self::ResumePrecompiles(_) => Self::no_evm_execution("resume_precompiles"), + } + } + + /// There are many cases where a receipt on NEAR can change the Aurora contract state, but no EVM execution actually occurs. + /// In these cases we have a sentinel Ethereum transaction from the zero address to itself with input equal to the method name. + fn no_evm_execution(method_name: &str) -> NormalizedEthTransaction { + NormalizedEthTransaction { + address: Address::from_array([0; 20]), + chain_id: None, + nonce: U256::zero(), + gas_limit: U256::zero(), + max_priority_fee_per_gas: U256::zero(), + max_fee_per_gas: U256::zero(), + to: Some(Address::from_array([0; 20])), + value: Wei::zero(), + data: method_name.as_bytes().to_vec(), + access_list: Vec::new(), + } + } + + fn get_implicit_address(caller: &AccountId) -> types::Address { + aurora_engine_sdk::types::near_account_to_evm_address(caller.as_bytes()) + } + + fn get_implicit_nonce( + from: &types::Address, + block_height: u64, + transaction_position: u16, + storage: &Storage, + ) -> U256 { + storage + .with_engine_access(block_height, transaction_position, &[], |io| { + aurora_engine::engine::get_nonce(&io, from) + }) + .result + } +} + /// This data type represents `TransactionMessage` above in the way consistent with how it is /// stored on disk (in the DB). This type implements borsh (de)serialization. The purpose of /// having a private struct for borsh, which is separate from the main `TransactionMessage` @@ -243,6 +501,8 @@ enum BorshableTransactionKind<'a> { FactoryUpdate(Cow<'a, Vec>), FactoryUpdateAddressVersion(Cow<'a, AddressVersionUpdateArgs>), FactorySetWNearAddress(types::Address), + PausePrecompiles(Cow<'a, parameters::PausePrecompilesCallArgs>), + ResumePrecompiles(Cow<'a, parameters::PausePrecompilesCallArgs>), Unknown, } @@ -282,6 +542,8 @@ impl<'a> From<&'a TransactionKind> for BorshableTransactionKind<'a> { Self::FactorySetWNearAddress(*address) } TransactionKind::Unknown => Self::Unknown, + TransactionKind::PausePrecompiles(x) => Self::PausePrecompiles(Cow::Borrowed(x)), + TransactionKind::ResumePrecompiles(x) => Self::ResumePrecompiles(Cow::Borrowed(x)), } } } @@ -333,6 +595,12 @@ impl<'a> TryFrom> for TransactionKind { Ok(Self::FactorySetWNearAddress(address)) } BorshableTransactionKind::Unknown => Ok(Self::Unknown), + BorshableTransactionKind::PausePrecompiles(x) => { + Ok(Self::PausePrecompiles(x.into_owned())) + } + BorshableTransactionKind::ResumePrecompiles(x) => { + Ok(Self::ResumePrecompiles(x.into_owned())) + } } } } diff --git a/engine-standalone-tracing/Cargo.toml b/engine-standalone-tracing/Cargo.toml index 99aaa2416..b7bfb8aa3 100644 --- a/engine-standalone-tracing/Cargo.toml +++ b/engine-standalone-tracing/Cargo.toml @@ -15,10 +15,10 @@ crate-type = ["lib"] [dependencies] aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false, features = ["std"] } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false, features = ["std", "tracing"] } -evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false, features = ["std", "tracing"] } -evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false, features = ["std", "tracing"] } +evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std"] } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } hex = { version = "0.4", default-features = false, features = ["std"] } serde = { version = "1", features = ["derive"], optional = true } diff --git a/engine-test-doubles/Cargo.toml b/engine-test-doubles/Cargo.toml new file mode 100644 index 000000000..54de5edd7 --- /dev/null +++ b/engine-test-doubles/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "aurora-engine-test-doubles" +version = "1.0.0" +authors = ["Aurora Labs "] +edition = "2021" +description = "Contains implementations of engine traits suitable for using in tests" +documentation = "" +readme = true +homepage = "https://github.com/aurora-is-near/aurora-engine" +repository = "https://github.com/aurora-is-near/aurora-engine" +license = "GPL-3.0" +publish = false +autobenches = false + +[dependencies] +aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } +aurora-engine-sdk = { path = "../engine-sdk" } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } + +[dev-dependencies] diff --git a/engine-tests/src/test_utils/standalone/mocks/storage.rs b/engine-test-doubles/src/io.rs similarity index 93% rename from engine-tests/src/test_utils/standalone/mocks/storage.rs rename to engine-test-doubles/src/io.rs index ba6c011be..adb066c41 100644 --- a/engine-tests/src/test_utils/standalone/mocks/storage.rs +++ b/engine-test-doubles/src/io.rs @@ -20,12 +20,12 @@ impl StorageIntermediate for Value { #[derive(Debug, Default)] pub struct Storage { - input: Vec, - output: Vec, - // TODO: write a real storage backend - kv_store: HashMap, Vec>, + pub input: Vec, + pub output: Vec, + pub kv_store: HashMap, Vec>, } +/// In-memory implementation of [IO]. #[derive(Debug, Clone, Copy)] pub struct StoragePointer<'a>(pub &'a RwLock); diff --git a/engine-test-doubles/src/lib.rs b/engine-test-doubles/src/lib.rs new file mode 100644 index 000000000..5c41c3f48 --- /dev/null +++ b/engine-test-doubles/src/lib.rs @@ -0,0 +1,3 @@ +pub mod io; +pub mod promise; +pub mod tracing; diff --git a/engine-tests/src/test_utils/standalone/mocks/promise.rs b/engine-test-doubles/src/promise.rs similarity index 87% rename from engine-tests/src/test_utils/standalone/mocks/promise.rs rename to engine-test-doubles/src/promise.rs index a201d1996..38462b382 100644 --- a/engine-tests/src/test_utils/standalone/mocks/promise.rs +++ b/engine-test-doubles/src/promise.rs @@ -4,6 +4,7 @@ use aurora_engine_types::parameters::{PromiseBatchAction, PromiseCreateArgs}; use aurora_engine_types::types::PromiseResult; use std::collections::HashMap; +#[derive(Debug, PartialEq, Eq)] pub enum PromiseArgs { Create(PromiseCreateArgs), #[allow(dead_code)] @@ -42,18 +43,18 @@ impl PromiseHandler for PromiseTracker { self.promise_results.get(index as usize).cloned() } - fn promise_create_call(&mut self, args: &PromiseCreateArgs) -> PromiseId { + unsafe fn promise_create_call(&mut self, args: &PromiseCreateArgs) -> PromiseId { let id = self.take_id(); self.scheduled_promises .insert(id, PromiseArgs::Create(args.clone())); PromiseId::new(id) } - fn promise_attach_callback( + unsafe fn promise_attach_callback( &mut self, base: PromiseId, - callback: &aurora_engine_types::parameters::PromiseCreateArgs, - ) -> aurora_engine_sdk::promise::PromiseId { + callback: &PromiseCreateArgs, + ) -> PromiseId { let id = self.take_id(); self.scheduled_promises.insert( id, @@ -65,7 +66,7 @@ impl PromiseHandler for PromiseTracker { PromiseId::new(id) } - fn promise_create_batch(&mut self, args: &PromiseBatchAction) -> PromiseId { + unsafe fn promise_create_batch(&mut self, args: &PromiseBatchAction) -> PromiseId { let id = self.take_id(); self.scheduled_promises .insert(id, PromiseArgs::Batch(args.clone())); diff --git a/engine-tests/src/test_utils/standalone/mocks/tracing.rs b/engine-test-doubles/src/tracing.rs similarity index 100% rename from engine-tests/src/test_utils/standalone/mocks/tracing.rs rename to engine-test-doubles/src/tracing.rs diff --git a/engine-tests/Cargo.toml b/engine-tests/Cargo.toml index b74330172..4a551162e 100644 --- a/engine-tests/Cargo.toml +++ b/engine-tests/Cargo.toml @@ -16,6 +16,7 @@ autobenches = false [dev-dependencies] aurora-engine = { path = "../engine", default-features = false, features = ["std", "tracing"] } +aurora-engine-test-doubles = { path = "../engine-test-doubles", default-features = false } aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features = ["std"] } aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false, features = ["std"] } @@ -24,28 +25,29 @@ engine-standalone-storage = { path = "../engine-standalone-storage" } engine-standalone-tracing = { path = "../engine-standalone-tracing" } borsh = { version = "0.9.3", default-features = false } sha3 = { version = "0.10.2", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false, features = ["std", "tracing"] } -evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false, features = ["std", "tracing"] } -evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false, features = ["std", "tracing"] } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } rlp = { version = "0.5.0", default-features = false } base64 = "0.13.0" -bstr = "0.2" +bstr = "1.0.1" byte-slice-cast = { version = "1.0", default-features = false } -ethabi = "17.1" +ethabi = "18.0" serde = { version = "1", features = ["derive"] } serde_json = "1" hex = { version = "0.4.3", default-features = false } -near-sdk = { git = "https://github.com/aurora-is-near/near-sdk-rs.git", rev = "7a3fa3fbff84b712050370d840297df38c925d2d" } -near-sdk-sim = { git = "https://github.com/aurora-is-near/near-sdk-rs.git", rev = "7a3fa3fbff84b712050370d840297df38c925d2d" } -near-crypto = { git = "https://github.com/birchmd/nearcore.git", rev = "980bc48dc02878fea1e0dbc5812ae7de49f12dda" } -near-vm-runner = { git = "https://github.com/birchmd/nearcore.git", rev = "980bc48dc02878fea1e0dbc5812ae7de49f12dda", default-features = false, features = [ "wasmer2_vm", "protocol_feature_alt_bn128" ] } -near-vm-logic = { git = "https://github.com/birchmd/nearcore.git", rev = "980bc48dc02878fea1e0dbc5812ae7de49f12dda", default-features = false, features = [ "protocol_feature_alt_bn128" ] } -near-primitives-core = { git = "https://github.com/birchmd/nearcore.git", rev = "980bc48dc02878fea1e0dbc5812ae7de49f12dda", features = [ "protocol_feature_alt_bn128" ] } -near-primitives = { git = "https://github.com/birchmd/nearcore.git", rev = "980bc48dc02878fea1e0dbc5812ae7de49f12dda", default-features = false, features = [ "nightly_protocol" ] } +near-sdk = { git = "https://github.com/aurora-is-near/near-sdk-rs.git", rev = "a4634850023fd115053970f17e10861779d5167d" } +near-sdk-sim = { git = "https://github.com/aurora-is-near/near-sdk-rs.git", rev = "a4634850023fd115053970f17e10861779d5167d" } +near-crypto = { git = "https://github.com/birchmd/nearcore.git", rev = "6033903be2037d67510188450f289b2d6e033f04" } +near-vm-errors = { git = "https://github.com/birchmd/nearcore.git", rev = "6033903be2037d67510188450f289b2d6e033f04" } +near-vm-runner = { git = "https://github.com/birchmd/nearcore.git", rev = "6033903be2037d67510188450f289b2d6e033f04", default-features = false, features = [ "wasmer2_vm" ] } +near-vm-logic = { git = "https://github.com/birchmd/nearcore.git", rev = "6033903be2037d67510188450f289b2d6e033f04" } +near-primitives-core = { git = "https://github.com/birchmd/nearcore.git", rev = "6033903be2037d67510188450f289b2d6e033f04" } +near-primitives = { git = "https://github.com/birchmd/nearcore.git", rev = "6033903be2037d67510188450f289b2d6e033f04", default-features = false, features = [ "nightly_protocol" ] } libsecp256k1 = { version = "0.7.0", default-features = false } rand = "0.8.5" -criterion = "0.3.4" -git2 = "0.13" +criterion = "0.4.0" +git2 = "0.15" tempfile = "3.2.0" walrus = "0.19" diff --git a/engine-tests/src/benches/eth_standard_precompiles.rs b/engine-tests/src/benches/eth_standard_precompiles.rs index 778f41724..12f043e4d 100644 --- a/engine-tests/src/benches/eth_standard_precompiles.rs +++ b/engine-tests/src/benches/eth_standard_precompiles.rs @@ -29,7 +29,7 @@ pub(crate) fn eth_standard_precompiles_benchmark(c: &mut Criterion) { )); let test_names = PrecompilesContract::all_method_names(); - let bench_ids: Vec<_> = test_names.iter().map(BenchmarkId::from_parameter).collect(); + let bench_ids = test_names.iter().map(BenchmarkId::from_parameter); // create testing transactions let transactions: Vec<_> = test_names diff --git a/engine-tests/src/benches/nft_pagination.rs b/engine-tests/src/benches/nft_pagination.rs index e928501fb..e769dda18 100644 --- a/engine-tests/src/benches/nft_pagination.rs +++ b/engine-tests/src/benches/nft_pagination.rs @@ -28,7 +28,7 @@ pub(crate) fn measure_gas_usage( )); // mint NFTs - let data: String = std::iter::repeat('0').take(data_size).collect(); + let data = "0".repeat(data_size); for i in 0..total_tokens { let result = runner .submit_with_signer(&mut source_account, |nonce| { diff --git a/engine-tests/src/test_utils/exit_precompile.rs b/engine-tests/src/test_utils/exit_precompile.rs index 177f8822f..6f440d289 100644 --- a/engine-tests/src/test_utils/exit_precompile.rs +++ b/engine-tests/src/test_utils/exit_precompile.rs @@ -2,6 +2,7 @@ use crate::prelude::{ parameters::SubmitResult, transactions::legacy::TransactionLegacy, Address, Wei, U256, }; use crate::test_utils::{self, solidity, AuroraRunner, Signer}; +use near_vm_errors::VMError; pub(crate) struct TesterConstructor(pub solidity::ContractConstructor); @@ -68,7 +69,7 @@ impl Tester { method: &str, value: Wei, params: &[ethabi::Token], - ) -> Result { + ) -> Result { let data = self .contract .abi @@ -86,7 +87,10 @@ impl Tester { data, }; - let result = runner.submit_transaction(&signer.secret_key, tx).unwrap(); + runner.submit_transaction(&signer.secret_key, tx) + } + + fn submit_result_to_success_or_revert(result: SubmitResult) -> Result { match result.status { aurora_engine::parameters::TransactionStatus::Succeed(_) => Ok(result), aurora_engine::parameters::TransactionStatus::Revert(bytes) => Err(Revert(bytes)), @@ -124,7 +128,7 @@ impl Tester { runner: &mut AuroraRunner, signer: &mut Signer, flag: bool, - ) -> Result { + ) -> Result { self.call_function( runner, signer, @@ -140,12 +144,15 @@ impl Tester { signer: &mut Signer, flag: bool, ) -> Result { - self.call_function( - runner, - signer, - "withdrawAndFail", - Wei::zero(), - &[ethabi::Token::Bool(flag)], + Self::submit_result_to_success_or_revert( + self.call_function( + runner, + signer, + "withdrawAndFail", + Wei::zero(), + &[ethabi::Token::Bool(flag)], + ) + .unwrap(), ) } @@ -155,12 +162,15 @@ impl Tester { signer: &mut Signer, flag: bool, ) -> Result { - self.call_function( - runner, - signer, - "tryWithdrawAndAvoidFail", - Wei::zero(), - &[ethabi::Token::Bool(flag)], + Self::submit_result_to_success_or_revert( + self.call_function( + runner, + signer, + "tryWithdrawAndAvoidFail", + Wei::zero(), + &[ethabi::Token::Bool(flag)], + ) + .unwrap(), ) } @@ -170,12 +180,15 @@ impl Tester { signer: &mut Signer, flag: bool, ) -> Result { - self.call_function( - runner, - signer, - "tryWithdrawAndAvoidFailAndSucceed", - Wei::zero(), - &[ethabi::Token::Bool(flag)], + Self::submit_result_to_success_or_revert( + self.call_function( + runner, + signer, + "tryWithdrawAndAvoidFailAndSucceed", + Wei::zero(), + &[ethabi::Token::Bool(flag)], + ) + .unwrap(), ) } @@ -186,7 +199,7 @@ impl Tester { is_to_near: bool, amount: Wei, ) -> Result { - if is_to_near { + Self::submit_result_to_success_or_revert(if is_to_near { self.call_function( runner, signer, @@ -194,6 +207,7 @@ impl Tester { amount, &[ethabi::Token::Bytes(DEST_ACCOUNT.as_bytes().to_vec())], ) + .unwrap() } else { self.call_function( runner, @@ -202,7 +216,8 @@ impl Tester { amount, &[ethabi::Token::Address(DEST_ADDRESS.raw())], ) - } + .unwrap() + }) } } diff --git a/engine-tests/src/test_utils/mod.rs b/engine-tests/src/test_utils/mod.rs index 6ed7188a4..881124cf3 100644 --- a/engine-tests/src/test_utils/mod.rs +++ b/engine-tests/src/test_utils/mod.rs @@ -33,6 +33,9 @@ pub fn origin() -> String { pub(crate) const SUBMIT: &str = "submit"; pub(crate) const CALL: &str = "call"; pub(crate) const DEPLOY_ERC20: &str = "deploy_erc20_token"; +pub(crate) const PAUSE_PRECOMPILES: &str = "pause_precompiles"; +pub(crate) const PAUSED_PRECOMPILES: &str = "paused_precompiles"; +pub(crate) const RESUME_PRECOMPILES: &str = "resume_precompiles"; pub(crate) mod erc20; pub(crate) mod exit_precompile; @@ -149,7 +152,7 @@ impl<'a> OneShotAuroraRunner<'a> { impl AuroraRunner { pub fn one_shot(&self) -> OneShotAuroraRunner { OneShotAuroraRunner { - base: &self, + base: self, ext: self.ext.clone(), context: self.context.clone(), } @@ -223,7 +226,11 @@ impl AuroraRunner { if let Some(standalone_runner) = &mut self.standalone_runner { if maybe_error.is_none() - && (method_name == SUBMIT || method_name == CALL || method_name == DEPLOY_ERC20) + && (method_name == SUBMIT + || method_name == CALL + || method_name == DEPLOY_ERC20 + || method_name == PAUSE_PRECOMPILES + || method_name == RESUME_PRECOMPILES) { standalone_runner .submit_raw(method_name, &self.context, &self.promise_results) @@ -302,7 +309,7 @@ impl AuroraRunner { let ft_value = { let mut current_ft: FungibleToken = trie .get(&ft_key) - .map(|bytes| FungibleToken::try_from_slice(&bytes).unwrap()) + .map(|bytes| FungibleToken::try_from_slice(bytes).unwrap()) .unwrap_or_default(); current_ft.total_eth_supply_on_near = current_ft.total_eth_supply_on_near + NEP141Wei::new(init_balance.raw().as_u128()); @@ -319,7 +326,7 @@ impl AuroraRunner { let aurora_balance_value = { let mut current_balance: u128 = trie .get(&aurora_balance_key) - .map(|bytes| u128::try_from_slice(&bytes).unwrap()) + .map(|bytes| u128::try_from_slice(bytes).unwrap()) .unwrap_or_default(); current_balance += init_balance.raw().as_u128(); current_balance @@ -582,7 +589,7 @@ impl Default for AuroraRunner { /// Wrapper around `ProfileData` to still include the wasm gas usage /// (which was removed in https://github.com/near/nearcore/pull/4438). -#[derive(Default, Clone)] +#[derive(Debug, Default, Clone)] pub(crate) struct ExecutionProfile { pub host_breakdown: ProfileData, wasm_gas: u64, @@ -804,8 +811,8 @@ pub(crate) fn validate_address_balance_and_nonce( } pub(crate) fn address_from_hex(address: &str) -> Address { - let bytes = if address.starts_with("0x") { - hex::decode(&address[2..]).unwrap() + let bytes = if let Some(address) = address.strip_prefix("0x") { + hex::decode(address).unwrap() } else { hex::decode(address).unwrap() }; @@ -831,7 +838,7 @@ pub fn unwrap_success(result: SubmitResult) -> Vec { pub fn unwrap_success_slice(result: &SubmitResult) -> &[u8] { match &result.status { - TransactionStatus::Succeed(ret) => &ret, + TransactionStatus::Succeed(ret) => ret, other => panic!("Unexpected status: {:?}", other), } } diff --git a/engine-tests/src/test_utils/rust.rs b/engine-tests/src/test_utils/rust.rs index ce10882df..1e0a0c85c 100644 --- a/engine-tests/src/test_utils/rust.rs +++ b/engine-tests/src/test_utils/rust.rs @@ -5,7 +5,7 @@ pub fn compile>(source_path: P) { let output = Command::new("cargo") .current_dir(source_path) .env("RUSTFLAGS", "-C link-arg=-s") - .args(&["build", "--target", "wasm32-unknown-unknown", "--release"]) + .args(["build", "--target", "wasm32-unknown-unknown", "--release"]) .output() .unwrap(); diff --git a/engine-tests/src/test_utils/self_destruct.rs b/engine-tests/src/test_utils/self_destruct.rs index 751ff0751..7268dcc68 100644 --- a/engine-tests/src/test_utils/self_destruct.rs +++ b/engine-tests/src/test_utils/self_destruct.rs @@ -173,7 +173,7 @@ impl SelfDestruct { .unwrap(); let input = CallArgs::V2(FunctionCallArgsV2 { - contract: self.contract.address.into(), + contract: self.contract.address, value: WeiU256::default(), input: data.to_vec(), }) diff --git a/engine-tests/src/test_utils/solidity.rs b/engine-tests/src/test_utils/solidity.rs index 4ec333134..4123273dc 100644 --- a/engine-tests/src/test_utils/solidity.rs +++ b/engine-tests/src/test_utils/solidity.rs @@ -173,7 +173,7 @@ where let output_mount_arg = format!("{}:/output", output_path.to_str().unwrap()); let contract_arg = format!("/contracts/{}", contract_file.as_ref().to_str().unwrap()); let output = Command::new("/usr/bin/env") - .args(&[ + .args([ "docker", "run", "-v", diff --git a/engine-tests/src/test_utils/standalone/mocks/mod.rs b/engine-tests/src/test_utils/standalone/mocks/mod.rs index 017412a70..990ae733f 100644 --- a/engine-tests/src/test_utils/standalone/mocks/mod.rs +++ b/engine-tests/src/test_utils/standalone/mocks/mod.rs @@ -12,9 +12,6 @@ use engine_standalone_storage::{BlockMetadata, Storage}; use near_sdk_sim::DEFAULT_GAS; pub mod block; -pub mod promise; -pub mod storage; -pub mod tracing; pub const ETH_CUSTODIAN_ADDRESS: Address = aurora_engine_precompiles::make_address(0xd045f7e1, 0x9b2488924b97f9c145b5e51d0d895a65); @@ -127,7 +124,7 @@ pub fn mint_evm_account( .unwrap(); let transfer_args = NEP141FtOnTransferArgs { - sender_id: aurora_account_id.clone(), + sender_id: aurora_account_id, amount: Balance::new(balance.raw().as_u128()), msg: format!( "aurora:{}{}", @@ -135,9 +132,7 @@ pub fn mint_evm_account( hex::encode(address.as_bytes()) ), }; - connector - .ft_on_transfer(&mut engine, &transfer_args) - .unwrap(); + connector.ft_on_transfer(&engine, &transfer_args).unwrap(); engine.apply(std::iter::once(state_change), std::iter::empty(), false); } diff --git a/engine-tests/src/test_utils/standalone/mod.rs b/engine-tests/src/test_utils/standalone/mod.rs index 85e9baeac..43e30b2ea 100644 --- a/engine-tests/src/test_utils/standalone/mod.rs +++ b/engine-tests/src/test_utils/standalone/mod.rs @@ -1,5 +1,7 @@ use aurora_engine::engine; -use aurora_engine::parameters::{CallArgs, DeployErc20TokenArgs, SubmitResult, TransactionStatus}; +use aurora_engine::parameters::{ + CallArgs, DeployErc20TokenArgs, PausePrecompilesCallArgs, SubmitResult, TransactionStatus, +}; use aurora_engine_sdk::env::{self, Env}; use aurora_engine_transactions::legacy::{LegacyEthSignedTransaction, TransactionLegacy}; use aurora_engine_types::types::{Address, NearGas, PromiseResult, Wei}; @@ -43,7 +45,7 @@ impl StandaloneRunner { .unwrap(); env.block_height += 1; let transaction_hash = H256::zero(); - let tx_msg = Self::template_tx_msg(storage, &env, 0, transaction_hash, &[]); + let tx_msg = Self::template_tx_msg(storage, env, 0, transaction_hash, &[]); let result = storage.with_engine_access(env.block_height, 0, &[], |io| { mocks::init_evm(io, env, chain_id); }); @@ -77,7 +79,7 @@ impl StandaloneRunner { }; env.block_height += 1; - let tx_msg = Self::template_tx_msg(storage, &env, 0, transaction_hash, &[]); + let tx_msg = Self::template_tx_msg(storage, env, 0, transaction_hash, &[]); let result = storage.with_engine_access(env.block_height, 0, &[], |io| { mocks::mint_evm_account(address, balance, nonce, code, io, env) @@ -140,7 +142,7 @@ impl StandaloneRunner { env.block_height += 1; Self::internal_submit_transaction( - &transaction_bytes, + transaction_bytes, 0, storage, env, @@ -163,17 +165,18 @@ impl StandaloneRunner { let transaction_bytes = rlp::encode(signed_tx).to_vec(); let transaction_hash = aurora_engine_sdk::keccak(&transaction_bytes); - let mut tx_msg = Self::template_tx_msg(storage, &env, 0, transaction_hash, &[]); + let mut tx_msg = Self::template_tx_msg(storage, env, 0, transaction_hash, &[]); tx_msg.position = transaction_position; tx_msg.transaction = TransactionKind::Submit(transaction_bytes.as_slice().try_into().unwrap()); let outcome = sync::execute_transaction_message(storage, tx_msg).unwrap(); match outcome.maybe_result.as_ref().unwrap().as_ref().unwrap() { - sync::TransactionExecutionResult::Submit(result) => match result.as_ref() { - Err(e) => return Err(e.clone()), - Ok(_) => (), - }, + sync::TransactionExecutionResult::Submit(result) => { + if let Err(e) = result.as_ref() { + return Err(e.clone()); + } + } _ => unreachable!(), }; @@ -238,6 +241,44 @@ impl StandaloneRunner { 0, Vec::new(), )) + } else if method_name == test_utils::RESUME_PRECOMPILES { + let input = &ctx.input[..]; + let call_args = PausePrecompilesCallArgs::try_from_slice(input) + .expect("Unable to parse input as PausePrecompilesCallArgs"); + + let transaction_hash = aurora_engine_sdk::keccak(&ctx.input); + let mut tx_msg = + Self::template_tx_msg(storage, &env, 0, transaction_hash, promise_results); + tx_msg.transaction = TransactionKind::ResumePrecompiles(call_args); + + let outcome = sync::execute_transaction_message(storage, tx_msg).unwrap(); + self.cumulative_diff.append(outcome.diff.clone()); + storage::commit(storage, &outcome); + + Ok(SubmitResult::new( + TransactionStatus::Succeed(Vec::new()), + 0, + Vec::new(), + )) + } else if method_name == test_utils::PAUSE_PRECOMPILES { + let input = &ctx.input[..]; + let call_args = PausePrecompilesCallArgs::try_from_slice(input) + .expect("Unable to parse input as PausePrecompilesCallArgs"); + + let transaction_hash = aurora_engine_sdk::keccak(&ctx.input); + let mut tx_msg = + Self::template_tx_msg(storage, &env, 0, transaction_hash, promise_results); + tx_msg.transaction = TransactionKind::PausePrecompiles(call_args); + + let outcome = sync::execute_transaction_message(storage, tx_msg).unwrap(); + self.cumulative_diff.append(outcome.diff.clone()); + storage::commit(storage, &outcome); + + Ok(SubmitResult::new( + TransactionStatus::Succeed(Vec::new()), + 0, + Vec::new(), + )) } else { panic!("Unsupported standalone method {}", method_name); } @@ -319,7 +360,7 @@ impl StandaloneRunner { cumulative_diff: &mut Diff, promise_results: &[PromiseResult], ) -> Result { - let transaction_hash = aurora_engine_sdk::keccak(&transaction_bytes); + let transaction_hash = aurora_engine_sdk::keccak(transaction_bytes); let mut tx_msg = Self::template_tx_msg( storage, env, diff --git a/engine-tests/src/test_utils/uniswap.rs b/engine-tests/src/test_utils/uniswap.rs index cacb15285..275df297e 100644 --- a/engine-tests/src/test_utils/uniswap.rs +++ b/engine-tests/src/test_utils/uniswap.rs @@ -399,7 +399,7 @@ fn download_uniswap_artifacts() { DOWNLOAD_ONCE.call_once(|| { let output = Command::new("/usr/bin/env") .current_dir(&uniswap_root_path()) - .args(&["yarn", "install"]) + .args(["yarn", "install"]) .output() .unwrap(); diff --git a/engine-tests/src/tests/account_id_precompiles.rs b/engine-tests/src/tests/account_id_precompiles.rs index 2b64efb24..cc456ed3d 100644 --- a/engine-tests/src/tests/account_id_precompiles.rs +++ b/engine-tests/src/tests/account_id_precompiles.rs @@ -72,6 +72,6 @@ fn test_account_id_precompiles() { fn unwrap_ethabi_string(result: &SubmitResult) -> String { let bytes = test_utils::unwrap_success_slice(result); - let mut tokens = ethabi::decode(&[ethabi::ParamType::String], &bytes).unwrap(); + let mut tokens = ethabi::decode(&[ethabi::ParamType::String], bytes).unwrap(); tokens.pop().unwrap().into_string().unwrap() } diff --git a/engine-tests/src/tests/contract_call.rs b/engine-tests/src/tests/contract_call.rs index 83c219f10..b9c6143ae 100644 --- a/engine-tests/src/tests/contract_call.rs +++ b/engine-tests/src/tests/contract_call.rs @@ -6,7 +6,7 @@ use crate::test_utils::exit_precompile::{Tester, TesterConstructor, DEST_ACCOUNT fn setup_test() -> (AuroraRunner, Signer, Address, Tester) { let mut runner = AuroraRunner::new(); - let token = runner.deploy_erc20_token(&"tt.testnet".to_string()); + let token = runner.deploy_erc20_token("tt.testnet"); let mut signer = test_utils::Signer::random(); runner.create_address( test_utils::address_from_secret_key(&signer.secret_key), @@ -20,17 +20,12 @@ fn setup_test() -> (AuroraRunner, Signer, Address, Tester) { let tester: Tester = runner .deploy_contract( &signer.secret_key, - |ctr| ctr.deploy(nonce, token.into()), + |ctr| ctr.deploy(nonce, token), tester_ctr, ) .into(); - runner.mint( - token, - tester.contract.address.into(), - 1_000_000_000, - origin(), - ); + runner.mint(token, tester.contract.address, 1_000_000_000, origin()); (runner, signer, token, tester) } diff --git a/engine-tests/src/tests/ecrecover.rs b/engine-tests/src/tests/ecrecover.rs index bdc4353d3..9378e165f 100644 --- a/engine-tests/src/tests/ecrecover.rs +++ b/engine-tests/src/tests/ecrecover.rs @@ -85,9 +85,9 @@ fn check_wasm_ecrecover( fn construct_input(hash: &[u8], sig: &[u8]) -> Vec { let mut buf = [0u8; 128]; - (&mut buf[0..32]).copy_from_slice(hash); + (buf[0..32]).copy_from_slice(hash); buf[63] = sig[64]; - (&mut buf[64..128]).copy_from_slice(&sig[0..64]); + (buf[64..128]).copy_from_slice(&sig[0..64]); buf.to_vec() } diff --git a/engine-tests/src/tests/erc20.rs b/engine-tests/src/tests/erc20.rs index b5de18747..a1a11af3e 100644 --- a/engine-tests/src/tests/erc20.rs +++ b/engine-tests/src/tests/erc20.rs @@ -110,7 +110,7 @@ fn profile_erc20_get_balance() { // at least 70% of the cost is spent on wasm computation (as opposed to host functions) let wasm_fraction = (100 * profile.wasm_gas()) / profile.all_gas(); assert!( - 20 <= wasm_fraction && wasm_fraction <= 30, + (20..=30).contains(&wasm_fraction), "{}% is not between 20% and 30%", wasm_fraction ); diff --git a/engine-tests/src/tests/erc20_connector.rs b/engine-tests/src/tests/erc20_connector.rs index 2e438b15c..3cccf9f31 100644 --- a/engine-tests/src/tests/erc20_connector.rs +++ b/engine-tests/src/tests/erc20_connector.rs @@ -109,7 +109,7 @@ impl test_utils::AuroraRunner { self.make_call("submit", origin, rlp::encode(&input).to_vec()) } - pub fn deploy_erc20_token(&mut self, nep141: &String) -> Address { + pub fn deploy_erc20_token(&mut self, nep141: &str) -> Address { let result = self.make_call("deploy_erc20_token", origin(), nep141.try_to_vec().unwrap()); result.check_ok(); @@ -125,10 +125,10 @@ impl test_utils::AuroraRunner { let mut rng = rand::thread_rng(); let source_account = SecretKey::random(&mut rng); let source_address = test_utils::address_from_secret_key(&source_account); - self.create_address(source_address, INITIAL_BALANCE.into(), INITIAL_NONCE.into()); + self.create_address(source_address, INITIAL_BALANCE, INITIAL_NONCE.into()); EthereumAddress { secret_key: source_account, - address: source_address.into(), + address: source_address, } } @@ -151,7 +151,7 @@ impl test_utils::AuroraRunner { "mint(address,uint256)", &[ Token::Address(target.raw()), - Token::Uint(U256::from(amount).into()), + Token::Uint(U256::from(amount)), ], ); let result = self.evm_call(token, input, origin); @@ -184,7 +184,7 @@ impl test_utils::AuroraRunner { ], ); - let input = create_eth_transaction(Some(token.into()), Wei::zero(), input, None, &sender); + let input = create_eth_transaction(Some(token), Wei::zero(), input, None, &sender); let result = self.evm_submit(input, origin); // create_eth_transaction() result.check_ok(); @@ -231,13 +231,13 @@ impl test_utils::AuroraRunner { #[test] fn test_deploy_erc20_token() { let mut runner = AuroraRunner::new(); - runner.deploy_erc20_token(&"tt.testnet".to_string()); + runner.deploy_erc20_token("tt.testnet"); } #[test] fn test_mint() { let mut runner = AuroraRunner::new(); - let token = runner.deploy_erc20_token(&"tt.testnet".to_string()); + let token = runner.deploy_erc20_token("tt.testnet"); let address = runner.create_account().address; let balance = runner.balance_of(token, address, origin()); assert_eq!(balance, U256::from(0)); @@ -250,7 +250,7 @@ fn test_mint() { #[test] fn test_mint_not_admin() { let mut runner = AuroraRunner::new(); - let token = runner.deploy_erc20_token(&"tt.testnet".to_string()); + let token = runner.deploy_erc20_token("tt.testnet"); let address = runner.create_account().address; let balance = runner.balance_of(token, address, origin()); assert_eq!(balance, U256::from(0)); @@ -294,7 +294,7 @@ fn test_ft_on_transfer_fail() { let res = runner.ft_on_transfer(nep141, alice.clone(), alice, amount, recipient.encode()); // Transaction should fail so it must return everything - assert_eq!(res, format!("\"{}\"", amount.to_string())); + assert_eq!(res, format!("\"{}\"", amount)); } #[ignore] @@ -310,7 +310,7 @@ fn test_relayer_charge_fee() { let token = runner.deploy_erc20_token(&nep141); let recipient = runner.create_account().address; - let recipient_balance = runner.get_balance(recipient.into()); + let recipient_balance = runner.get_balance(recipient); assert_eq!(recipient_balance, INITIAL_BALANCE); let relayer = create_ethereum_address(); @@ -332,7 +332,7 @@ fn test_relayer_charge_fee() { recipient.encode() + &hex::encode(fee_encoded), ); - let recipient_balance_end = runner.get_balance(recipient.into()); + let recipient_balance_end = runner.get_balance(recipient); assert_eq!( recipient_balance_end, Wei::new_u64(INITIAL_BALANCE.raw().as_u64() - fee) @@ -347,7 +347,7 @@ fn test_relayer_charge_fee() { #[test] fn test_transfer_erc20_token() { let mut runner = AuroraRunner::new(); - let token = runner.deploy_erc20_token(&"tt.testnet".to_string()); + let token = runner.deploy_erc20_token("tt.testnet"); let peer0 = runner.create_account(); let peer1 = runner.create_account(); diff --git a/engine-tests/src/tests/eth_connector.rs b/engine-tests/src/tests/eth_connector.rs index 9b1a2a4d8..03f7d51bc 100644 --- a/engine-tests/src/tests/eth_connector.rs +++ b/engine-tests/src/tests/eth_connector.rs @@ -18,16 +18,16 @@ use near_sdk_sim::transaction::ExecutionStatus; use near_sdk_sim::{to_yocto, ExecutionResult, UserAccount, DEFAULT_GAS, STORAGE_AMOUNT}; use serde_json::json; -const CONTRACT_ACC: &'static str = "eth_connector.root"; -const PROOF_DATA_NEAR: &'static str = r#"{"log_index":0,"log_entry_data":[248,251,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,54,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,101,116,104,95,114,101,99,105,112,105,101,110,116,46,114,111,111,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"receipt_index":0,"receipt_data":[249,2,6,1,130,107,17,185,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,253,248,251,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,54,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,101,116,104,95,114,101,99,105,112,105,101,110,116,46,114,111,111,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"header_data":[249,2,10,160,177,33,112,26,26,176,12,12,163,2,249,133,245,12,51,201,55,50,148,156,122,67,27,26,101,178,36,153,54,100,53,137,160,29,204,77,232,222,199,93,122,171,133,181,103,182,204,212,26,211,18,69,27,148,138,116,19,240,161,66,253,64,212,147,71,148,124,28,230,160,8,239,64,193,62,78,177,68,166,204,116,240,224,174,172,126,160,197,65,5,202,188,134,5,164,246,19,133,35,57,28,114,241,186,81,123,163,166,161,24,32,157,168,170,13,108,58,61,46,160,6,199,163,13,91,119,225,39,168,255,213,10,107,252,143,246,138,241,108,139,59,35,187,185,162,223,53,108,222,73,181,109,160,27,154,49,63,26,170,15,177,97,255,6,204,84,221,234,197,159,172,114,47,148,126,32,199,241,127,101,120,182,51,52,100,185,1,0,0,0,8,0,0,0,0,0,0,0,32,0,0,0,0,0,2,0,8,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,8,32,0,32,0,0,128,0,2,0,0,0,1,0,32,0,0,0,2,0,0,0,0,32,0,0,0,0,0,4,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,128,64,0,0,0,0,1,32,0,0,0,0,0,0,96,32,0,64,0,0,0,128,1,0,0,0,0,1,0,0,0,8,0,0,0,18,32,0,0,64,145,1,8,0,4,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,33,16,0,128,0,0,0,0,0,0,128,0,2,0,0,0,0,0,0,0,0,0,0,2,0,80,0,0,0,0,0,0,0,0,1,128,0,8,0,0,0,0,4,0,0,0,128,2,0,32,0,128,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,16,0,8,0,0,0,0,0,0,0,0,0,0,128,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,25,1,227,23,131,157,85,14,131,122,18,0,131,75,91,132,132,96,174,58,224,140,115,112,105,100,101,114,49,48,1,2,8,230,160,188,212,199,183,154,22,223,85,103,215,24,122,240,235,79,129,44,93,184,88,161,218,79,5,44,226,106,100,50,40,163,97,136,155,158,202,3,149,91,200,78],"proof":[[248,113,160,46,156,31,85,241,226,241,13,5,56,73,146,176,67,195,109,6,189,172,104,44,103,44,88,32,15,181,152,136,29,121,252,160,191,48,87,174,71,151,208,114,164,150,51,200,171,90,90,106,46,200,79,77,222,145,95,89,141,137,138,149,67,73,8,87,128,128,128,128,128,128,160,175,9,219,77,174,13,247,133,55,172,92,185,202,7,160,10,204,112,44,133,36,96,30,234,235,134,30,209,205,166,212,255,128,128,128,128,128,128,128,128],[249,2,13,48,185,2,9,249,2,6,1,130,107,17,185,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,253,248,251,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,54,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,101,116,104,95,114,101,99,105,112,105,101,110,116,46,114,111,111,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]}"#; -const PROOF_DATA_ETH: &'static str = r#"{"log_index":0,"log_entry_data":[249,1,27,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,101,116,104,95,99,111,110,110,101,99,116,111,114,46,114,111,111,116,58,56,57,49,66,50,55,52,57,50,51,56,66,50,55,102,70,53,56,101,57,53,49,48,56,56,101,53,53,98,48,52,100,101,55,49,68,99,51,55,52,0,0,0,0,0],"receipt_index":0,"receipt_data":[249,2,40,1,130,121,129,185,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,1,30,249,1,27,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,101,116,104,95,99,111,110,110,101,99,116,111,114,46,114,111,111,116,58,56,57,49,66,50,55,52,57,50,51,56,66,50,55,102,70,53,56,101,57,53,49,48,56,56,101,53,53,98,48,52,100,101,55,49,68,99,51,55,52,0,0,0,0,0],"header_data":[249,2,23,160,227,118,223,171,207,47,75,187,79,185,74,198,88,140,54,97,161,196,35,70,121,178,154,141,172,91,193,252,86,64,228,227,160,29,204,77,232,222,199,93,122,171,133,181,103,182,204,212,26,211,18,69,27,148,138,116,19,240,161,66,253,64,212,147,71,148,109,150,79,199,61,172,73,162,195,49,105,169,235,252,47,207,92,249,136,136,160,232,74,213,122,210,55,65,43,78,225,85,247,174,212,229,211,176,186,250,113,21,129,16,181,52,172,217,167,148,242,153,45,160,15,198,229,127,6,235,198,161,226,121,173,106,62,0,90,25,158,11,242,44,178,3,137,22,245,126,227,91,74,156,24,115,160,65,253,74,43,97,155,196,93,59,43,202,12,155,49,115,95,124,247,230,15,1,171,150,10,56,115,247,86,81,8,39,11,185,1,0,128,32,9,2,0,0,0,0,0,0,32,16,128,32,0,0,128,2,0,0,64,51,0,0,0,129,0,32,66,32,0,14,0,144,0,0,0,2,13,34,0,128,64,200,128,4,32,16,0,64,0,0,34,0,32,0,40,0,8,0,0,32,176,0,196,1,0,0,10,1,16,8,16,0,0,72,48,0,0,36,0,17,4,128,10,68,0,16,0,1,32,0,128,0,32,0,12,64,162,8,98,2,0,32,0,0,16,136,1,16,40,0,0,0,0,4,0,0,44,32,0,0,192,49,0,8,12,64,96,129,0,2,0,0,128,0,12,64,10,8,1,132,0,32,0,1,4,33,0,4,128,140,128,0,2,66,0,0,192,0,2,16,2,0,0,0,32,16,0,0,64,0,242,4,0,0,0,0,0,0,4,128,0,32,0,14,194,0,16,10,64,32,0,0,0,2,16,96,16,129,0,16,32,32,128,128,32,0,2,68,0,32,1,8,64,16,32,2,5,2,68,0,32,0,2,16,1,0,0,16,2,0,0,16,2,0,0,0,128,0,16,0,36,128,32,0,4,64,16,0,40,16,0,17,0,16,132,25,207,98,158,131,157,85,88,131,122,17,225,131,121,11,191,132,96,174,60,127,153,216,131,1,10,1,132,103,101,116,104,134,103,111,49,46,49,54,135,119,105,110,100,111,119,115,160,33,15,129,167,71,37,0,207,110,217,101,107,71,110,48,237,4,83,174,75,131,188,213,179,154,115,243,94,107,52,238,144,136,84,114,37,115,236,166,252,105],"proof":[[248,177,160,211,36,253,39,157,18,180,1,3,139,140,168,65,238,106,111,239,53,121,48,235,96,8,115,106,93,174,165,66,207,49,216,160,172,74,129,163,113,84,7,35,23,12,83,10,253,21,57,198,143,128,73,112,84,222,23,146,164,219,89,23,138,197,111,237,160,52,220,245,245,91,231,95,169,113,225,49,168,40,77,59,232,33,210,4,93,203,94,247,212,15,42,146,32,70,206,193,54,160,6,140,29,61,156,224,194,173,129,74,84,92,11,129,184,212,37,31,23,140,226,87,230,72,30,52,97,66,185,236,139,228,128,128,128,128,160,190,114,105,101,139,216,178,42,238,75,109,119,227,138,206,144,183,82,34,173,26,173,188,231,152,171,56,163,2,179,13,190,128,128,128,128,128,128,128,128],[249,2,47,48,185,2,43,249,2,40,1,130,121,129,185,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,1,30,249,1,27,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,101,116,104,95,99,111,110,110,101,99,116,111,114,46,114,111,111,116,58,56,57,49,66,50,55,52,57,50,51,56,66,50,55,102,70,53,56,101,57,53,49,48,56,56,101,53,53,98,48,52,100,101,55,49,68,99,51,55,52,0,0,0,0,0]]}"#; -const DEPOSITED_RECIPIENT: &'static str = "eth_recipient.root"; -const PROVER_ACCOUNT: &'static str = "eth_connector.root"; -const CUSTODIAN_ADDRESS: &'static str = "096DE9C2B8A5B8c22cEe3289B101f6960d68E51E"; +const CONTRACT_ACC: &str = "eth_connector.root"; +const PROOF_DATA_NEAR: &str = r#"{"log_index":0,"log_entry_data":[248,251,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,54,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,101,116,104,95,114,101,99,105,112,105,101,110,116,46,114,111,111,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"receipt_index":0,"receipt_data":[249,2,6,1,130,107,17,185,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,253,248,251,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,54,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,101,116,104,95,114,101,99,105,112,105,101,110,116,46,114,111,111,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"header_data":[249,2,10,160,177,33,112,26,26,176,12,12,163,2,249,133,245,12,51,201,55,50,148,156,122,67,27,26,101,178,36,153,54,100,53,137,160,29,204,77,232,222,199,93,122,171,133,181,103,182,204,212,26,211,18,69,27,148,138,116,19,240,161,66,253,64,212,147,71,148,124,28,230,160,8,239,64,193,62,78,177,68,166,204,116,240,224,174,172,126,160,197,65,5,202,188,134,5,164,246,19,133,35,57,28,114,241,186,81,123,163,166,161,24,32,157,168,170,13,108,58,61,46,160,6,199,163,13,91,119,225,39,168,255,213,10,107,252,143,246,138,241,108,139,59,35,187,185,162,223,53,108,222,73,181,109,160,27,154,49,63,26,170,15,177,97,255,6,204,84,221,234,197,159,172,114,47,148,126,32,199,241,127,101,120,182,51,52,100,185,1,0,0,0,8,0,0,0,0,0,0,0,32,0,0,0,0,0,2,0,8,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,8,32,0,32,0,0,128,0,2,0,0,0,1,0,32,0,0,0,2,0,0,0,0,32,0,0,0,0,0,4,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,128,64,0,0,0,0,1,32,0,0,0,0,0,0,96,32,0,64,0,0,0,128,1,0,0,0,0,1,0,0,0,8,0,0,0,18,32,0,0,64,145,1,8,0,4,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,33,16,0,128,0,0,0,0,0,0,128,0,2,0,0,0,0,0,0,0,0,0,0,2,0,80,0,0,0,0,0,0,0,0,1,128,0,8,0,0,0,0,4,0,0,0,128,2,0,32,0,128,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,16,0,8,0,0,0,0,0,0,0,0,0,0,128,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,25,1,227,23,131,157,85,14,131,122,18,0,131,75,91,132,132,96,174,58,224,140,115,112,105,100,101,114,49,48,1,2,8,230,160,188,212,199,183,154,22,223,85,103,215,24,122,240,235,79,129,44,93,184,88,161,218,79,5,44,226,106,100,50,40,163,97,136,155,158,202,3,149,91,200,78],"proof":[[248,113,160,46,156,31,85,241,226,241,13,5,56,73,146,176,67,195,109,6,189,172,104,44,103,44,88,32,15,181,152,136,29,121,252,160,191,48,87,174,71,151,208,114,164,150,51,200,171,90,90,106,46,200,79,77,222,145,95,89,141,137,138,149,67,73,8,87,128,128,128,128,128,128,160,175,9,219,77,174,13,247,133,55,172,92,185,202,7,160,10,204,112,44,133,36,96,30,234,235,134,30,209,205,166,212,255,128,128,128,128,128,128,128,128],[249,2,13,48,185,2,9,249,2,6,1,130,107,17,185,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,253,248,251,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,54,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,101,116,104,95,114,101,99,105,112,105,101,110,116,46,114,111,111,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]}"#; +const PROOF_DATA_ETH: &str = r#"{"log_index":0,"log_entry_data":[249,1,27,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,101,116,104,95,99,111,110,110,101,99,116,111,114,46,114,111,111,116,58,56,57,49,66,50,55,52,57,50,51,56,66,50,55,102,70,53,56,101,57,53,49,48,56,56,101,53,53,98,48,52,100,101,55,49,68,99,51,55,52,0,0,0,0,0],"receipt_index":0,"receipt_data":[249,2,40,1,130,121,129,185,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,1,30,249,1,27,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,101,116,104,95,99,111,110,110,101,99,116,111,114,46,114,111,111,116,58,56,57,49,66,50,55,52,57,50,51,56,66,50,55,102,70,53,56,101,57,53,49,48,56,56,101,53,53,98,48,52,100,101,55,49,68,99,51,55,52,0,0,0,0,0],"header_data":[249,2,23,160,227,118,223,171,207,47,75,187,79,185,74,198,88,140,54,97,161,196,35,70,121,178,154,141,172,91,193,252,86,64,228,227,160,29,204,77,232,222,199,93,122,171,133,181,103,182,204,212,26,211,18,69,27,148,138,116,19,240,161,66,253,64,212,147,71,148,109,150,79,199,61,172,73,162,195,49,105,169,235,252,47,207,92,249,136,136,160,232,74,213,122,210,55,65,43,78,225,85,247,174,212,229,211,176,186,250,113,21,129,16,181,52,172,217,167,148,242,153,45,160,15,198,229,127,6,235,198,161,226,121,173,106,62,0,90,25,158,11,242,44,178,3,137,22,245,126,227,91,74,156,24,115,160,65,253,74,43,97,155,196,93,59,43,202,12,155,49,115,95,124,247,230,15,1,171,150,10,56,115,247,86,81,8,39,11,185,1,0,128,32,9,2,0,0,0,0,0,0,32,16,128,32,0,0,128,2,0,0,64,51,0,0,0,129,0,32,66,32,0,14,0,144,0,0,0,2,13,34,0,128,64,200,128,4,32,16,0,64,0,0,34,0,32,0,40,0,8,0,0,32,176,0,196,1,0,0,10,1,16,8,16,0,0,72,48,0,0,36,0,17,4,128,10,68,0,16,0,1,32,0,128,0,32,0,12,64,162,8,98,2,0,32,0,0,16,136,1,16,40,0,0,0,0,4,0,0,44,32,0,0,192,49,0,8,12,64,96,129,0,2,0,0,128,0,12,64,10,8,1,132,0,32,0,1,4,33,0,4,128,140,128,0,2,66,0,0,192,0,2,16,2,0,0,0,32,16,0,0,64,0,242,4,0,0,0,0,0,0,4,128,0,32,0,14,194,0,16,10,64,32,0,0,0,2,16,96,16,129,0,16,32,32,128,128,32,0,2,68,0,32,1,8,64,16,32,2,5,2,68,0,32,0,2,16,1,0,0,16,2,0,0,16,2,0,0,0,128,0,16,0,36,128,32,0,4,64,16,0,40,16,0,17,0,16,132,25,207,98,158,131,157,85,88,131,122,17,225,131,121,11,191,132,96,174,60,127,153,216,131,1,10,1,132,103,101,116,104,134,103,111,49,46,49,54,135,119,105,110,100,111,119,115,160,33,15,129,167,71,37,0,207,110,217,101,107,71,110,48,237,4,83,174,75,131,188,213,179,154,115,243,94,107,52,238,144,136,84,114,37,115,236,166,252,105],"proof":[[248,177,160,211,36,253,39,157,18,180,1,3,139,140,168,65,238,106,111,239,53,121,48,235,96,8,115,106,93,174,165,66,207,49,216,160,172,74,129,163,113,84,7,35,23,12,83,10,253,21,57,198,143,128,73,112,84,222,23,146,164,219,89,23,138,197,111,237,160,52,220,245,245,91,231,95,169,113,225,49,168,40,77,59,232,33,210,4,93,203,94,247,212,15,42,146,32,70,206,193,54,160,6,140,29,61,156,224,194,173,129,74,84,92,11,129,184,212,37,31,23,140,226,87,230,72,30,52,97,66,185,236,139,228,128,128,128,128,160,190,114,105,101,139,216,178,42,238,75,109,119,227,138,206,144,183,82,34,173,26,173,188,231,152,171,56,163,2,179,13,190,128,128,128,128,128,128,128,128],[249,2,47,48,185,2,43,249,2,40,1,130,121,129,185,1,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,1,30,249,1,27,148,9,109,233,194,184,165,184,194,44,238,50,137,177,1,246,150,13,104,229,30,248,66,160,209,66,67,156,39,142,37,218,217,165,7,102,241,83,208,227,210,215,191,43,209,111,194,120,28,75,212,148,178,177,90,157,160,0,0,0,0,0,0,0,0,0,0,0,0,121,24,63,219,216,14,45,138,234,26,202,162,246,123,251,138,54,212,10,141,184,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59,101,116,104,95,99,111,110,110,101,99,116,111,114,46,114,111,111,116,58,56,57,49,66,50,55,52,57,50,51,56,66,50,55,102,70,53,56,101,57,53,49,48,56,56,101,53,53,98,48,52,100,101,55,49,68,99,51,55,52,0,0,0,0,0]]}"#; +const DEPOSITED_RECIPIENT: &str = "eth_recipient.root"; +const PROVER_ACCOUNT: &str = "eth_connector.root"; +const CUSTODIAN_ADDRESS: &str = "096DE9C2B8A5B8c22cEe3289B101f6960d68E51E"; const DEPOSITED_AMOUNT: u128 = 800400; const DEPOSITED_FEE: u128 = 400; -const RECIPIENT_ETH_ADDRESS: &'static str = "891b2749238b27ff58e951088e55b04de71dc374"; -const EVM_CUSTODIAN_ADDRESS: &'static str = "096DE9C2B8A5B8c22cEe3289B101f6960d68E51E"; +const RECIPIENT_ETH_ADDRESS: &str = "891b2749238b27ff58e951088e55b04de71dc374"; +const EVM_CUSTODIAN_ADDRESS: &str = "096DE9C2B8A5B8c22cEe3289B101f6960d68E51E"; const DEPOSITED_EVM_AMOUNT: u128 = 10200; const DEPOSITED_EVM_FEE: u128 = 200; @@ -85,7 +85,7 @@ fn init_contract( contract_name.parse().unwrap(), "new_eth_connector", &InitCallArgs { - prover_account: str_to_account_id(PROVER_ACCOUNT.into()), + prover_account: str_to_account_id(PROVER_ACCOUNT), eth_custodian_address: custodian_address.into(), metadata: FungibleTokenMetadata::default(), } @@ -154,7 +154,7 @@ fn assert_proof_was_not_used(account: &UserAccount, contract: &str, proof: &str) } #[allow(dead_code)] -fn print_logs(logs: &Vec) { +fn print_logs(logs: &[String]) { for l in logs { println!("[log] {}", l); } @@ -322,7 +322,7 @@ fn test_withdraw_eth_from_near() { assert!(data[0].is_some()); match data[1].clone().unwrap().outcome().status { ExecutionStatus::SuccessValue(ref v) => { - let d: WithdrawResult = WithdrawResult::try_from_slice(&v).unwrap(); + let d: WithdrawResult = WithdrawResult::try_from_slice(v).unwrap(); assert_eq!(d.amount, withdraw_amount); assert_eq!(d.recipient_id, recipient_addr); let custodian_addr = validate_eth_address(CUSTODIAN_ADDRESS); @@ -597,7 +597,7 @@ fn test_deposit_with_0x_prefix() { use aurora_engine::deposit_event::TokenMessageData; let (master_account, contract) = init(CUSTODIAN_ADDRESS); - let eth_custodian_address: Address = Address::decode(&CUSTODIAN_ADDRESS.to_string()).unwrap(); + let eth_custodian_address: Address = Address::decode(CUSTODIAN_ADDRESS).unwrap(); let recipient_address = Address::from_array([10u8; 20]); let deposit_amount = 17; let recipient_address_encoded = recipient_address.encode(); @@ -660,6 +660,194 @@ fn test_deposit_with_0x_prefix() { assert_eq!(address_balance, deposit_amount); } +fn generate_dummy_proof(message: String, deposit_amount: u128, log_index: u64) -> Proof { + use aurora_engine::deposit_event::TokenMessageData; + + let eth_custodian_address: Address = Address::decode(CUSTODIAN_ADDRESS).unwrap(); + + let fee: Fee = Fee::new(NEP141Wei::new(0)); + let token_message_data = + TokenMessageData::parse_event_message_and_prepare_token_message_data(&message, fee) + .unwrap(); + + let deposit_event = aurora_engine::deposit_event::DepositedEvent { + eth_custodian_address, + sender: Address::zero(), + token_message_data, + amount: NEP141Wei::new(deposit_amount), + fee, + }; + + let event_schema = ethabi::Event { + name: aurora_engine::deposit_event::DEPOSITED_EVENT.into(), + inputs: aurora_engine::deposit_event::DepositedEvent::event_params(), + anonymous: false, + }; + let log_entry = aurora_engine::log_entry::LogEntry { + address: eth_custodian_address.raw(), + topics: vec![ + event_schema.signature(), + // the sender is not important + crate::prelude::H256::zero(), + ], + data: ethabi::encode(&[ + ethabi::Token::String(message), + ethabi::Token::Uint(U256::from(deposit_event.amount.as_u128())), + ethabi::Token::Uint(U256::from(deposit_event.fee.as_u128())), + ]), + }; + + Proof { + log_index, + // Only this field matters for the purpose of this test + log_entry_data: rlp::encode(&log_entry).to_vec(), + receipt_index: 1, + receipt_data: Vec::new(), + header_data: Vec::new(), + proof: Vec::new(), + } +} + +#[test] +fn test_deposit_eth_to_near_account() { + let (master_account, contract) = init(CUSTODIAN_ADDRESS); + + let deposit_amount = 17; + + let user_account_id = "some_user.root"; + let _user_account = master_account.create_user( + user_account_id.parse().unwrap(), + to_yocto("100"), // initial balance + ); + let proof = generate_dummy_proof(user_account_id.to_string(), deposit_amount, 1); + + let res = master_account.call( + contract.account_id(), + "deposit", + &proof.try_to_vec().unwrap(), + DEFAULT_GAS, + 0, + ); + let promises = res.promise_results(); + for p in promises.iter() { + assert!(p.is_some()); + let p = p.as_ref().unwrap(); + p.assert_success() + } + res.assert_success(); + + let aurora_balance = get_eth_on_near_balance(&master_account, CONTRACT_ACC, CONTRACT_ACC); + assert_eq!(aurora_balance, 0); + let user_account_balance = + get_eth_on_near_balance(&master_account, user_account_id, CONTRACT_ACC); + assert_eq!(user_account_balance, deposit_amount); +} + +#[test] +fn test_deposit_eth_with_empty_custom_connector_account() { + // In this, test we make an ETH deposit using the message format for targeting + // an Aurora address, but use a different NEAR account than the Aurora Engine. + // The result is that the ETH is correctly minted to the Engine, but then an + // error occurs when it tries to transfer those funds because the listed NEAR + // account does not implement `ft_on_transfer`. + let (master_account, contract) = init(CUSTODIAN_ADDRESS); + + let deposit_amount = 17; + + let user_account_id = "some_user.root"; + let _user_account = master_account.create_user( + user_account_id.parse().unwrap(), + to_yocto("100"), // initial balance + ); + + let recipient_address = Address::from_array([10u8; 20]); + let recipient_address_encoded = recipient_address.encode(); + let message = [user_account_id, ":", "0x", &recipient_address_encoded].concat(); + let proof = generate_dummy_proof(message, deposit_amount, 1); + let res = master_account.call( + contract.account_id(), + "deposit", + &proof.try_to_vec().unwrap(), + DEFAULT_GAS, + 0, + ); + let promises = res.promise_results(); + res.assert_success(); + + let promise = &promises[promises.len() - 5]; + assert_execution_status_failure( + promise.as_ref().unwrap().outcome().clone().status, + format!( + r#"CompilationError(CodeDoesNotExist {{ account_id: AccountId("{}") }}"#, + user_account_id + ) + .as_str(), + "Expected failure in `ft_on_transfer` call, but deposit succeeded", + ); + + let user_account_balance = + get_eth_on_near_balance(&master_account, user_account_id, CONTRACT_ACC); + assert_eq!(user_account_balance, 0); + let aurora_balance = get_eth_on_near_balance(&master_account, CONTRACT_ACC, CONTRACT_ACC); + assert_eq!(aurora_balance, deposit_amount); + let address_balance = get_eth_balance(&master_account, recipient_address, CONTRACT_ACC); + assert_eq!(address_balance, 0); +} + +#[test] +fn test_deposit_eth_with_custom_connector_account() { + // In this test, we make an ETH deposit using the message format for targeting + // an Aurora address, but use a different NEAR account than the Aurora Engine. + // Additionally, the target account implements `ft_on_transfer` so that it can + // receive the ETH and perform some action with it. This is safe because the ETH is + // minted in the Engine first, then transferred to the target account using + // `ft_transfer_call`. + let (master_account, contract) = init(CUSTODIAN_ADDRESS); + + let deposit_amount = 17; + + let user_account_id = "some_user.root"; + let _user_account = master_account.deploy( + &dummy_ft_receiver_bytes(), + user_account_id.parse().unwrap(), + to_yocto("100"), // initial balance + ); + + let recipient_address = Address::from_array([10u8; 20]); + let recipient_address_encoded = recipient_address.encode(); + let message = [user_account_id, ":", "0x", &recipient_address_encoded].concat(); + let proof = generate_dummy_proof(message, deposit_amount, 1); + let res = master_account.call( + contract.account_id(), + "deposit", + &proof.try_to_vec().unwrap(), + DEFAULT_GAS, + 0, + ); + let promises = res.promise_results(); + for p in promises.iter() { + assert!(p.is_some()); + let p = p.as_ref().unwrap(); + if p.executor_id().as_str() == user_account_id { + // The `ft_on_transfer` implementation in the user's account generates this log. + assert_eq!( + p.logs().first().map(|s| s.as_str()), + Some("in 17 tokens from @eth_connector.root ft_on_transfer, msg = some_user.root:00000000000000000000000000000000000000000000000000000000000000000a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"), + ); + } + p.assert_success() + } + res.assert_success(); + + let user_account_balance = + get_eth_on_near_balance(&master_account, user_account_id, CONTRACT_ACC); + assert_eq!(user_account_balance, deposit_amount); + let aurora_balance = get_eth_on_near_balance(&master_account, CONTRACT_ACC, CONTRACT_ACC); + assert_eq!(aurora_balance, 0); + let address_balance = get_eth_balance(&master_account, recipient_address, CONTRACT_ACC); + assert_eq!(address_balance, 0); +} + #[test] fn test_deposit_with_same_proof() { let (_master_account, contract) = init(CUSTODIAN_ADDRESS); @@ -849,22 +1037,20 @@ fn call_set_paused_flags( contract: &str, paused_mask: PausedMask, ) -> ExecutionResult { - let res = account.call( + account.call( contract.parse().unwrap(), "set_paused_flags", &paused_mask.try_to_vec().unwrap(), DEFAULT_GAS, 0, - ); - res + ) } fn create_user_account(master_account: &UserAccount) -> UserAccount { - let user_account = master_account.create_user( + master_account.create_user( "eth_recipient.root".parse().unwrap(), to_yocto("100"), // initial balance - ); - user_account + ) } #[test] diff --git a/engine-tests/src/tests/mod.rs b/engine-tests/src/tests/mod.rs index 720c72019..30f18d30e 100644 --- a/engine-tests/src/tests/mod.rs +++ b/engine-tests/src/tests/mod.rs @@ -11,6 +11,7 @@ mod ghsa_3p69_m8gg_fwmf; mod meta_parsing; mod multisender; mod one_inch; +mod pausable_precompiles; mod prepaid_gas_precompile; mod promise_results_precompile; mod random; diff --git a/engine-tests/src/tests/one_inch.rs b/engine-tests/src/tests/one_inch.rs index 4e603eadb..63581b3c7 100644 --- a/engine-tests/src/tests/one_inch.rs +++ b/engine-tests/src/tests/one_inch.rs @@ -39,7 +39,7 @@ fn test_1inch_liquidity_protocol() { let (result, profile, pool) = helper.create_pool(&pool_factory, token_a.0.address, token_b.0.address); assert!(result.gas_used >= 4_500_000); // more than 4.5M EVM gas used - assert_gas_bound(profile.all_gas(), 21); + assert_gas_bound(profile.all_gas(), 20); // Approve giving ERC-20 tokens to the pool helper.approve_erc20_tokens(&token_a, pool.address()); @@ -105,7 +105,7 @@ fn test_1_inch_limit_order_deploy() { // at least 45% of which is from wasm execution let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); assert!( - 50 <= wasm_fraction && wasm_fraction <= 60, + (50..=60).contains(&wasm_fraction), "{}% is not between 50% and 60%", wasm_fraction ); diff --git a/engine-tests/src/tests/pausable_precompiles.rs b/engine-tests/src/tests/pausable_precompiles.rs new file mode 100644 index 000000000..745a83f9c --- /dev/null +++ b/engine-tests/src/tests/pausable_precompiles.rs @@ -0,0 +1,155 @@ +use crate::prelude::{Address, U256}; +use crate::test_utils::exit_precompile::{Tester, TesterConstructor}; +use crate::test_utils::{ + self, origin, AuroraRunner, Signer, PAUSED_PRECOMPILES, PAUSE_PRECOMPILES, RESUME_PRECOMPILES, +}; +use aurora_engine::parameters::{PausePrecompilesCallArgs, TransactionStatus}; +use aurora_engine_types::types::Wei; +use borsh::BorshSerialize; +use near_vm_errors::{FunctionCallError, HostError}; +use near_vm_runner::VMError; + +const EXIT_TO_ETHEREUM_FLAG: u32 = 0b10; +const CALLED_ACCOUNT_ID: &str = "aurora"; + +#[test] +fn test_paused_precompile_is_shown_when_viewing() { + let mut runner = test_utils::deploy_evm(); + + let call_args = PausePrecompilesCallArgs { + paused_mask: EXIT_TO_ETHEREUM_FLAG, + }; + + let mut input: Vec = Vec::new(); + call_args.serialize(&mut input).unwrap(); + + let _ = runner.call(PAUSE_PRECOMPILES, CALLED_ACCOUNT_ID, input.clone()); + let (outcome, error) = runner.call(PAUSED_PRECOMPILES, CALLED_ACCOUNT_ID, Vec::new()); + + assert!(error.is_none(), "{:?}", error); + + let output: Vec = outcome + .as_ref() + .unwrap() + .return_data + .clone() + .as_value() + .unwrap(); + + let actual_paused_precompiles = u32::from_le_bytes(output.as_slice().try_into().unwrap()); + let expected_paused_precompiles = EXIT_TO_ETHEREUM_FLAG; + + assert_eq!(expected_paused_precompiles, actual_paused_precompiles); +} + +#[test] +fn test_executing_paused_precompile_throws_error() { + let (mut runner, mut signer, _, tester) = setup_test(); + + let call_args = PausePrecompilesCallArgs { + paused_mask: EXIT_TO_ETHEREUM_FLAG, + }; + + let mut input: Vec = Vec::new(); + call_args.serialize(&mut input).unwrap(); + + let _ = runner.call(PAUSE_PRECOMPILES, CALLED_ACCOUNT_ID, input.clone()); + let is_to_near = false; + let result = tester.withdraw(&mut runner, &mut signer, is_to_near); + + assert!(result.is_err(), "{:?}", result); + + let error = result.unwrap_err(); + match &error { + VMError::FunctionCallError(fn_error) => match fn_error { + FunctionCallError::HostError(err) => match err { + HostError::GuestPanic { panic_msg } => assert_eq!(panic_msg, "ERR_PAUSED"), + other => panic!("Unexpected host error {:?}", other), + }, + other => panic!("Unexpected function call error {:?}", other), + }, + other => panic!("Unexpected VM error {:?}", other), + }; +} + +#[test] +fn test_executing_paused_and_then_resumed_precompile_succeeds() { + let (mut runner, mut signer, _, tester) = setup_test(); + + let call_args = PausePrecompilesCallArgs { + paused_mask: EXIT_TO_ETHEREUM_FLAG, + }; + + let mut input: Vec = Vec::new(); + call_args.serialize(&mut input).unwrap(); + + let _ = runner.call(PAUSE_PRECOMPILES, CALLED_ACCOUNT_ID, input.clone()); + let _ = runner.call(RESUME_PRECOMPILES, CALLED_ACCOUNT_ID, input); + let is_to_near = false; + let result = tester + .withdraw(&mut runner, &mut signer, is_to_near) + .unwrap(); + + let number = match result.status { + TransactionStatus::Succeed(number) => U256::from(number.as_slice()), + _ => panic!("Unexpected status {:?}", result), + }; + + assert_eq!(number, U256::zero()); +} + +#[test] +fn test_resuming_precompile_does_not_throw_error() { + let mut runner = test_utils::deploy_evm(); + + let call_args = PausePrecompilesCallArgs { paused_mask: 0b1 }; + + let mut input: Vec = Vec::new(); + call_args.serialize(&mut input).unwrap(); + + let (_, error) = runner.call(RESUME_PRECOMPILES, CALLED_ACCOUNT_ID, input); + + assert!(error.is_none(), "{:?}", error); +} + +#[test] +fn test_pausing_precompile_does_not_throw_error() { + let mut runner = test_utils::deploy_evm(); + + let call_args = PausePrecompilesCallArgs { paused_mask: 0b1 }; + + let mut input: Vec = Vec::new(); + call_args.serialize(&mut input).unwrap(); + + let (_, error) = runner.call(PAUSE_PRECOMPILES, CALLED_ACCOUNT_ID, input); + + assert!(error.is_none(), "{:?}", error); +} + +fn setup_test() -> (AuroraRunner, Signer, Address, Tester) { + const INITIAL_NONCE: u64 = 0; + + let mut runner = test_utils::deploy_evm(); + let token = runner.deploy_erc20_token("tt.testnet"); + let mut signer = Signer::random(); + runner.create_address( + test_utils::address_from_secret_key(&signer.secret_key), + Wei::from_eth(1.into()).unwrap(), + INITIAL_NONCE.into(), + ); + + let tester_ctr = TesterConstructor::load(); + let nonce = signer.use_nonce(); + + let tester: Tester = runner + .deploy_contract( + &signer.secret_key, + |ctr| ctr.deploy(nonce, token), + tester_ctr, + ) + .into(); + + runner.mint(token, tester.contract.address, 1_000_000_000, origin()); + + (runner, signer, token, tester) +} diff --git a/engine-tests/src/tests/promise_results_precompile.rs b/engine-tests/src/tests/promise_results_precompile.rs index f85afbcbe..b5788867b 100644 --- a/engine-tests/src/tests/promise_results_precompile.rs +++ b/engine-tests/src/tests/promise_results_precompile.rs @@ -33,7 +33,7 @@ fn test_promise_results_precompile() { runner.promise_results = promise_results.clone(); let result = runner - .submit_transaction(&signer.secret_key, transaction.clone()) + .submit_transaction(&signer.secret_key, transaction) .unwrap(); let standalone_result = standalone diff --git a/engine-tests/src/tests/repro.rs b/engine-tests/src/tests/repro.rs index d8d628b8a..fc4be898f 100644 --- a/engine-tests/src/tests/repro.rs +++ b/engine-tests/src/tests/repro.rs @@ -27,7 +27,7 @@ fn repro_GdASJ3KESs() { block_timestamp: 1645717564644206730, input_path: "src/tests/res/input_GdASJ3KESs.hex", evm_gas_used: 706713, - near_gas_used: 132, + near_gas_used: 131, }); } @@ -52,7 +52,7 @@ fn repro_8ru7VEA() { block_timestamp: 1648829935343349589, input_path: "src/tests/res/input_8ru7VEA.hex", evm_gas_used: 1732181, - near_gas_used: 240, + near_gas_used: 239, }); } @@ -72,7 +72,7 @@ fn repro_FRcorNv() { block_timestamp: 1650960438774745116, input_path: "src/tests/res/input_FRcorNv.hex", evm_gas_used: 1239721, - near_gas_used: 196, + near_gas_used: 194, }); } @@ -89,7 +89,7 @@ fn repro_5bEgfRQ() { block_timestamp: 1651073772931594646, input_path: "src/tests/res/input_5bEgfRQ.hex", evm_gas_used: 6_414_105, - near_gas_used: 695, + near_gas_used: 701, }); } @@ -107,11 +107,30 @@ fn repro_D98vwmi() { block_timestamp: 1651753443421003245, input_path: "src/tests/res/input_D98vwmi.hex", evm_gas_used: 1_035_348, - near_gas_used: 198, + near_gas_used: 195, }); } -fn repro_common<'a>(context: ReproContext<'a>) { +/// This test reproduces a transaction from testnet: +/// https://explorer.testnet.near.org/transactions/Emufid2pv2UpxrZae4NyowF2N2ZHvYEPq16LsQc7Uoc6 +/// It hit the gas limit at the time of its execution (engine v2.7.0). +/// The transaction is some kind of multi-step token swap. The user says it should be similar +/// to this transaction on Polygon: +/// https://mumbai.polygonscan.com/tx/0xd9ab182692c74a873f0c444854ed1045edbb32a252b561677042276143a024b7 +#[allow(non_snake_case)] +#[test] +fn repro_Emufid2() { + repro_common(ReproContext { + snapshot_path: "src/tests/res/aurora_state_Emufid2.json", + block_index: 99197180, + block_timestamp: 1662118048636713538, + input_path: "src/tests/res/input_Emufid2.hex", + evm_gas_used: 1_156_364, + near_gas_used: 330, + }); +} + +fn repro_common(context: ReproContext) { let ReproContext { snapshot_path, block_index, diff --git a/engine-tests/src/tests/res/CallTooDeep.sol b/engine-tests/src/tests/res/CallTooDeep.sol new file mode 100644 index 000000000..416c08169 --- /dev/null +++ b/engine-tests/src/tests/res/CallTooDeep.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0; + +interface ICallTooDeep { + function test() external; +} + +contract CallTooDeep { + function test() external { + ICallTooDeep(address(this)).test(); + } +} diff --git a/engine-tests/src/tests/res/aurora_state_Emufid2.json b/engine-tests/src/tests/res/aurora_state_Emufid2.json new file mode 100644 index 000000000..5d445b2a7 --- /dev/null +++ b/engine-tests/src/tests/res/aurora_state_Emufid2.json @@ -0,0 +1,556 @@ +{ + "id": "1", + "jsonrpc": "2.0", + "result": { + "block_hash": "GFm9DHxH46VFRrJ4nz5K93vQyZ3hZPNiV7myS2xJL4iS", + "block_height": 99197179, + "proof": [], + "values": [ + { + "key": "BwBTVEFURQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5FQVMGAAAAYXVyb3JhAAAAAAAAAAAAAAAA" + }, + { + "key": "BwEIohKKF0n0FEsN/ObdMF573LHv8Q==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwES4RoP3Sh2Lur7zng1ukN6GSVCww==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwEzwfD9LYjCn/e9+pwZpHXXnLmTyw==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwF1lEzuYMKXasxmD3VzaJCh3xpiQg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwGDz8mAMQpgjYhcf/vsznYgoV5row==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF4=" + }, + { + "key": "BwGzIZ1VKG1hyqRjpvnnTkHugTxvHg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwG7YyZJhdwHBWt9Alu8TULUn8bBpg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwHCMFMViItOEVFSZVvL6PptDjVgxA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwHO0wGqlC9yDUadiBuPrx1IdGybfQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwHbUOWoZ4HHQDWl+4LNNsVEA+lpNg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALs=" + }, + { + "key": "BwHgwCG9gEDVTmHxB8hqDX7rfCv4sw==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM=" + }, + { + "key": "BwHidktZ1Z81M6wwyDnRjKKpuXoPKA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwHjC5Q5M8SiTrTfBVJR+ZKm3g1q0Q==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwHpXZ7l7J29EQeNilR0tEJ54pIvhQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwH7UPpdjx8B02RTHBJm7g7nu4MC+g==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE=" + }, + { + "key": "BwJrGVnnAwPjNNfLV3IixilrwTL67Q==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZdlnJoBrou8=" + }, + { + "key": "BwLbUOWoZ4HHQDWl+4LNNsVEA+lpNg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQK71YSrR4=" + }, + { + "key": "BwMIohKKF0n0FEsN/ObdMF573LHv8Q==", + "proof": [], + "value": "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" + }, + { + "key": "BwMS4RoP3Sh2Lur7zng1ukN6GSVCww==", + "proof": [], + "value": "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" + }, + { + "key": "BwMzwfD9LYjCn/e9+pwZpHXXnLmTyw==", + "proof": [], + "value": "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G81g5RuBUmAgYASCAVJgGWAkggFSf0NyZWF0ZTI6IEZhaWxlZCBvbiBkZXBsb3kAAAAAAAAAYESCAVJgZAFiAAfBVluUk1BQUFBWW4KAVGIAKomQYgA0iFZbkGAAUmAgYAAgkGAfAWAgkASBAZKCYgAqrVdgAIVVYgAq+FZbgmAfEGIAKshXgFFg/xkWg4ABF4VVYgAq+FZbgoABYAEBhVWCFWIAKvhXkYIBW4KBERViACr4V4JRglWRYCABkZBgAQGQYgAq21ZbUGIAKwaSkVBiACsYVltQkFZbYRpRgGIAN86DOQGQVltbgIIRFWIAKwZXYACBVWABAWIAKxlWW4A1YAFgAWCgGwOBFoEUYgArR1dgAID9W5GQUFZbYABgIIKEAxIVYgArX1dgAID9W2IAK2qCYgArL1Zbk5JQUFBWW2AAYCCChAMSFWIAK4RXYACA/VtQNZGQUFZbY05Ie3Fg4BtgAFJgQWAEUmAkYAD9W2BAUWBggQFn//////////+BEYKCEBcVYgArx1diACvHYgAri1ZbYEBSkFZbYEBRYB+CAWAfGRaBAWf//////////4ERgoIQFxViACv5V2IAK/liACuLVltgQFKRkFBWW4AVFYEUYgAlbFdgAID9W2AAgmAfgwESYgAsIldgAID9W4E1Z///////////gREVYgAsP1diACw/YgAri1ZbYgAsVGAfggFgHxkWYCABYgArzVZbgYFShGAgg4YBAREVYgAsaldgAID9W4FgIIUBYCCDATdgAJGBAWAgAZGQkVKTklBQUFZbYABgIICDhQMSFWIALJtXYACA/VuCNWf//////////4CCERViACy0V2AAgP1bgYUBkVBgYICDiAMSFWIALMtXYACA/VtiACzVYgAroVZbgzWBUoSEATWDgREVYgAs61dgAID9W4QBYB+BAYkTYgAs/VdgAID9W4A1hIERFWIALRJXYgAtEmIAK4tWW2IALSKHgmAFGwFiACvNVluBgVKQhAKCAYcBkIeBAZCLgxEVYgAtP1dgAID9W5KIAZJbgoQQFWIALaRXhYSNAxIVYgAtXldgAICB/VtiAC1oYgAroVZbhDWBUomFATViAC17gWIALAFWW4GLAVJgQIWBATViAC2QgWIALAFWW5CCAVKCUpKFAZKQiAGQYgAtRFZbgImGAVJQUFBQYECEATWU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IFZbkVBhFGFgIIQBYRMgVluQUJJQkpBQVltgAYGBHJCCFoBhFH5XYH+CFpFQW2AgghCBFBVhEM5XY05Ie3Fg4BtgAFJgImAEUmAkYAD9W2NOSHtxYOAbYABSYBFgBFJgJGAA/VtgAIKCEBVhFMdXYRTHYRSfVltQA5BWW2AAghmCERVhFN9XYRTfYRSfVltQAZBWW2AggIJSgYEBUn9Pd25hYmxlOiBjYWxsZXIgaXMgbm90IHRoZSBvd25lcmBAggFSYGABkFZbYCCAglJgJZCCAVJ/RVJDMjA6IGRlY3JlYXNlZCBhbGxvd2FuY2UgYmVsb3dgQIIBUmQgemVyb2DYG2BgggFSYIABkFb+omRpcGZzWCISIDWltY0oJzg3PL/b5L9m8ur+wpaBhh15acZVbdO4N/Z0ZHNvbGNDAAgKADN1bnN5bnRoZXNpemVXaXRoU3dhcChieXRlczMyLGFkZHJlc3MsdWludDI1NixhZGRyZXNzLChhZGRyZXNzLGFkZHJlc3MsdWludDI1NixhZGRyZXNzLGFkZHJlc3MsdWludDI1NixhZGRyZXNzLGFkZHJlc3MsYWRkcmVzcyx1aW50MjU2LHVpbnQyNTYsYWRkcmVzcyx1aW50MjU2KSwoYWRkcmVzcyxhZGRyZXNzLHVpbnQyNTYpKWVtZXJnZW5jeVVuc3ludGhlc2l6ZShieXRlczMyLGFkZHJlc3MsdWludDgsYnl0ZXMzMixieXRlczMydW5zeW50aGVzaXplKGJ5dGVzMzIsYWRkcmVzcyx1aW50MjU2LGFkZHJlc3MpbWludFN5bnRoZXRpY1Rva2VuKGJ5dGVzMzIsYWRkcmVzcyx1aW50MjU2LGFkZHJlc3MpomRpcGZzWCISIJ3CXIwz05iOe+qdT2juTZO3tfIvw7pQ+sXIz4lwyDtnZHNvbGNDAAgKADM=" + }, + { + "key": "BwN1lEzuYMKXasxmD3VzaJCh3xpiQg==", + "proof": [], + "value": "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" + }, + { + "key": "BwODz8mAMQpgjYhcf/vsznYgoV5row==", + "proof": [], + "value": "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" + }, + { + "key": "BwOzIZ1VKG1hyqRjpvnnTkHugTxvHg==", + "proof": [], + "value": "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" + }, + { + "key": "BwO7YyZJhdwHBWt9Alu8TULUn8bBpg==", + "proof": [], + "value": "YAQ2EBVhAA1XYVfKVltgADVgHFJ0AQAAAAAAAAAAAAAAAAAAAAAAAAAAYCBSb3////////////////////9gQFJ//////////////////////4AAAAAAAAAAAAAAAAAAAABgYFJ0ASoF8f////////////////2r9BwAYIBSf////////////////tX6DgAAAAAAAAAAAAAAAAAAAAAAYKBSYAAVYQJEV1thAUBSYApUYQFgUmAIVGEBgFJhAWBRQhAVYQIxV2AHVGEBwFJgCVRhAeBSYQHAUWEBgFERFWEBildhAcBRYQGAUWEBwFGAghAVYQD7V2AAgP1bgIIDkFCQUEJhAeBRgIIQFWEBFFdgAID9W4CCA5BQkFCAggKCFYKEgwQUF2EBL1dgAID9W4CQUJBQkFBhAWBRYQHgUYCCEBVhAUtXYACA/VuAggOQUJBQgIBhAV1XYACA/VuCBJBQkFCBgYMBEBVhAXJXYACA/VuAggGQUJBQYABSYABRYQFAUVZQYQIsVlthAcBRYQHAUWEBgFGAghAVYQGjV2AAgP1bgIIDkFCQUEJhAeBRgIIQFWEBvFdgAID9W4CCA5BQkFCAggKCFYKEgwQUF2EB11dgAID9W4CQUJBQkFBhAWBRYQHgUYCCEBVhAfNXYACA/VuAggOQUJBQgIBhAgVXYACA/VuCBJBQkFCAghAVYQIYV2AAgP1bgIIDkFCQUGAAUmAAUWEBQFFWUFthAkJWW2EBgFFgAFJgAFFhAUBRVlBbAFtj9EbB0GAAURQVYQJ5VzQVYQJdV2AAgP1bYAZYAWEAqVZbYQFAUmEBQFFgAFJgIGAA81AAW2AAFWEDq1dbYQFAUmEBYGcN4Lazp2QAAIFSZw3gtrOnZAAAgWAgAVJnDeC2s6dkAACBYEABUmcN4Lazp2QAAIFgYAFSZw3gtrOnZAAAgWCAAVJQYQIAYABgBYGDUgFbYQFgYQIAUWAFgRBhAuxXYACA/VtgIAIBUWECAFFgBYEQYQMCV2AAgP1bYAFgwFJgIGDAIAFUgIICghWChIMEFBdhAyJXYACA/VuAkFCQUJBQZw3gtrOnZAAAgIBhAz1XYACA/VuCBJBQkFBhAWBhAgBRYAWBEGEDV1dgAID9W2AgAgFSW4FRYAEBgINSgRQVYQLYV1tQUGCgYQIgUltgAGECIFERFRVhA4hXYQOkVltgIGECIFEDYQFgAVFgIGECIFEDYQIgUmEDdlZbYQFAUVYAW2AAFWEE7VdbYQHgUmEBQFJhAWBSYQGAUmEBoFJhAcBSYQIAZw3gtrOnZAAAgVJnDeC2s6dkAACBYCABUmcN4Lazp2QAAIFgQAFSZw3gtrOnZAAAgWBgAVJnDeC2s6dkAACBYIABUlBhAqBgAGAFgYNSAVthAgBhAqBRYAWBEGEEMldgAID9W2AgAgFRYQFAYQKgUWAFgRBhBEtXYACA/VtgIAIBUYCCAoIVgoSDBBQXYQRkV2AAgP1bgJBQkFCQUGcN4Lazp2QAAICAYQR/V2AAgP1bggSQUJBQYQIAYQKgUWAFgRBhBJlXYACA/VtgIAIBUluBUWABAYCDUoEUFWEEHldbUFBgoGECwFJbYABhAsBRERUVYQTKV2EE5lZbYCBhAsBRA2ECAAFRYCBhAsBRA2ECwFJhBLhWW2EB4FFWAFtgABVhB+NXW2ECAFJhAUBSYQFgUmEBgFJhAaBSYQHAUmEB4FJgAGECIFJhAmBgAGAFgYNSAVtgIGECYFECYQFAAVFhAkBSYQIggFFhAkBRgYGDARAVYQVLV2AAgP1bgIIBkFCQUIFSUFuBUWABAYCDUoEUFWEFI1dbUFBhAiBRFRVhBYFXYABgAFJgAFFhAgBRVlBbYABhAqBSYQIgUWECwFJhAeBRYAWAggKCFYKEgwQUF2EFqVdgAID9W4CQUJBQkFBhAuBSYQMAYABg/4GDUgFbYQLAUWEDIFJhA2BgAGAFgYNSAVtgIGEDYFECYQFAAVFhA0BSYQMgUWECwFGAggKCFYKEgwQUF2EGAFdgAID9W4CQUJBQkFBhA0BRYAWAggKCFYKEgwQUF2EGIVdgAID9W4CQUJBQkFCAgGEGM1dgAID9W4IEkFCQUGEDIFJbgVFgAQGAg1KBFBVhBdRXW1BQYQLAUWECoFJhAuBRYQIgUYCCAoIVgoSDBBQXYQZ0V2AAgP1bgJBQkFCQUGEDIFFgBYCCAoIVgoSDBBQXYQaVV2AAgP1bgJBQkFCQUIGBgwEQFWEGq1dgAID9W4CCAZBQkFBhAsBRgIICghWChIMEFBdhBspXYACA/VuAkFCQUJBQYQLgUWABgIIQFWEG5FdgAID9W4CCA5BQkFBhAsBRgIICghWChIMEFBdhBwNXYACA/VuAkFCQUJBQYAZhAyBRgIICghWChIMEFBdhByRXYACA/VuAkFCQUJBQgYGDARAVYQc6V2AAgP1bgIIBkFCQUICAYQdMV2AAgP1bggSQUJBQYQLAUmECoFFhAsBRERVhB5NXYAFhAsBRYQKgUYCCEBVhB3tXYACA/VuAggOQUJBQERUVYQeOV2EHz1ZbYQe+VltgAWECoFFhAsBRgIIQFWEHqldgAID9W4CCA5BQkFARFRVhB71XYQfPVltbW4FRYAEBgINSgRQVYQXAV1tQUGECwFFgAFJgAFFhAgBRVlAAW2AAFWEJiVdbYQIAUmEBQFJhAWBSYQGAUmEBoFJhAcBSYQHgUmEBQGEFYFJbYQVgUVFgIGEFYFEBYQVgUmEFYGEFYFEQFWEIMVdhCA9WW2EFgGEBQGEDwFJbYQPAUVFgIGEDwFEBYQPAUmEDwGEDwFEQFWEIXldhCDxWW2ED4GEBQIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhBGBRYQRAUWEEIFFhBABRYQPgUWAGWAFhA7NWW2EEwFJhBOBSYQUAUmEFIFJhBUBSYQOgYQPAUlthA8BRUmAgYQPAUQNhA8BSYQFAYQPAURAVFWEI7ldhCMtWW2EEwIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAeBRYQYgUmEGIFFhBgBRYQXgUWEFwFFhBaBRYQWAUWAGWAFhBPVWW2EGgFJhBUBhBWBSW2EFYFFSYCBhBWBRA2EFYFJhAUBhBWBREBUVYQl3V2EJVFZbYQaAUWAAUmAAUWECAFFWUABbY7t7i4BgAFEUFWELqFc0FWEJoldgAID9W2EBQGEDYFJbYQNgUVFgIGEDYFEBYQNgUmEDYGEDYFEQFWEJzFdhCapWW2EDgGEBQFFhAWBRYQGAUWEBoFFhAcBRYQHgUWECAFFhAiBRYQJAUWAGWAFhAoFWW2ECgFJhAqBSYQLAUmEC4FJhAwBSYQJAUmECIFJhAgBSYQHgUmEBwFJhAaBSYQGAUmEBYFJhAUBSYQKAgFGCUoBgIAFRgmAgAVKAYEABUYJgQAFSgGBgAVGCYGABUoBggAFRgmCAAVJQUGEBQGEDIFJbYQMgUVFgIGEDIFEBYQMgUmEDIGEDIFEQFWEKj1dhCm1WW2AGWAFhAKlWW2EDQFJhAwBhAyBSW2EDIFFSYCBhAyBRA2EDIFJhAUBhAyBREBUVYQrHV2EKpFZbYQNAUWEEIFJhBCBRYQQAUWED4FFhA8BRYQOgUWEDgFFgBlgBYQT1VlthBIBSYQNAYQNgUlthA2BRUmAgYQNgUQNhA2BSYQFAYQNgURAVFWELH1dhCvxWW2EEgFFhAUBSYCBhBSBgBGMYFg3dYQTAUmEE3GAGVFr6YQtIV2AAgP1bYB89EWELVVdgAID9W2AAUGEFIFFhBKBSYQFAUWcN4Lazp2QAAICCAoIVgoSDBBQXYQuBV2AAgP1bgJBQkFCQUGEEoFGAgGELl1dgAID9W4IEkFCQUGAAUmAgYADzUABbY37eicVgAFEUFWEPclc0FWELwVdgAID9W2CkNWACgRBhC9FXYACA/VtQYQFAYAGAYMBSYCBgwCBUglJgAYFgwFJgIGDAIAFUgmAgAVJgAoFgwFJgIGDAIAFUgmBAAVJgA4FgwFJgIGDAIAFUgmBgAVJgBIFgwFJgIGDAIAFUgmCAAVJQUGEBQFFhAWBRYQGAUWEBoFFhAcBRYQHgUWAGWAFhAKlWW2ECIFJhAeBSYQHAUmEBoFJhAYBSYQFgUmEBQFJhAiBRYQHgUmEBQFFhAWBRYQGAUWEBoFFhAcBRYQHgUWECAFFhAiBRYQJAUWECgGEBQIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAeBRYQMgUmEDIFFhAwBRYQLgUWECwFFhAqBRYQKAUWAGWAFhB+tWW2EDgFJhAkBSYQIgUmECAFJhAeBSYQHAUmEBoFJhAYBSYQFgUmEBQFJhA4BRYQJAUmEDoGAAYAWBg1IBW2CkNRVhDYdXYQFAYQOgUWAFgRBhDUtXYACA/VtgIAIBgFFgBGEDoFFgBYEQYQ1kV2AAgP1bYCACATWBgYMBEBVhDXhXYACA/VuAggGQUJBQgVJQYQ3RVlthAUBhA6BRYAWBEGENm1dgAID9W2AgAgGAUWAEYQOgUWAFgRBhDbRXYACA/VtgIAIBNYCCEBVhDcZXYACA/VuAggOQUJBQgVJQW1uBUWABAYCDUoEUFWENL1dbUFBhAUBhA+BSW2ED4FFRYCBhA+BRAWED4FJhA+BhA+BREBVhDg5XYQ3sVlthBABhAUCAUYJSgGAgAVGCYCABUoBgQAFRgmBAAVKAYGABUYJgYAFSgGCAAVGCYIABUlBQYQHgUWEEoFJhBKBRYQSAUWEEYFFhBEBRYQQgUWEEAFFgBlgBYQfrVlthBQBSYQPAYQPgUlthA+BRUmAgYQPgUQNhA+BSYQFAYQPgURAVFWEOmldhDndWW2EFAFFhA8BSYCBhBaBgBGMYFg3dYQVAUmEFXGAGVFr6YQ7DV2AAgP1bYB89EWEO0FdgAID9W2AAUGEFoFFhBSBSYABhBcBSYKQ1FWEPDldhA8BRYQJAUYCCEBVhDv5XYACA/VuAggOQUJBQYQXAUmEPL1ZbYQJAUWEDwFGAghAVYQ8jV2AAgP1bgIIDkFCQUGEFwFJbYQXAUWEFIFGAggKCFYKEgwQUF2EPS1dgAID9W4CQUJBQkFBhAkBRgIBhD2FXYACA/VuCBJBQkFBgAFJgIGAA81AAW2OEc4SZYABRFBVhGpZXYv///1QVYQ+PV2AAgP1bYAFi////VTQVYQ+hV2AAgP1bYBBUFWEPrldgAID9W2CgNmEBQDdgAlRgBYCCAoIVgoSDBBQXYQ/OV2AAgP1bgJBQkFCQUGAQgIBhD+JXYACA/VuCBJBQkFBhAeBSYANUYQIAUmEBQFFhAWBRYQGAUWEBoFFhAcBRYQHgUWECAFFhAiBRYAZYAWEAqVZbYQJgUmECIFJhAgBSYQHgUmEBwFJhAaBSYQGAUmEBYFJhAUBSYQJgUWECIFJgIGEDAGAEYxgWDd1hAqBSYQK8YAZUWvphEGlXYACA/VtgHz0RYRB2V2AAgP1bYABQYQMAUWECgFJgAGEDIFJhA0BgAYBgwFJgIGDAIFSCUmABgWDAUmAgYMAgAVSCYCABUmACgWDAUmAgYMAgAVSCYEABUmADgWDAUmAgYMAgAVSCYGABUmAEgWDAUmAgYMAgAVSCYIABUlBQYABhAoBRERVhEa1XYQFAYQPgUlthA+BRUWAgYQPgUQFhA+BSYQPgYQPgURAVYREYV2EQ9lZbYQQAYQNAgFGCUoBgIAFRgmAgAVKAYEABUYJgQAFSgGBgAVGCYGABUoBggAFRgmCAAVJQUGECIFFhBKBSYQSgUWEEgFFhBGBRYQRAUWEEIFFhBABRYAZYAWEH61ZbYQUAUmEDwGED4FJbYQPgUVJgIGED4FEDYQPgUmEBQGED4FEQFRVhEaRXYRGBVlthBQBRYQMgUlthBSBhA0CAUYJSgGAgAVGCYCABUoBgQAFRgmBAAVKAYGABUYJgYAFSgGCAAVGCYIABUlBQYQXAYABgBYGDUgFbYARhBcBRYAWBEGESAFdgAID9W2AgAgE1YQXgUmECgFEVFWESJFdgAGEF4FERYRIjV2AAgP1bW2EFwFFgBYEQYRI1V2AAgP1bYABgwFJgIGDAIAFUYQYAUmAAYQXgUREVYRRmV2ACYQXAURQVYRKdV2AgYQagYCRjcKCCMWEGIFIwYQZAUmEGPGEGAFFa+mEShFdgAID9W2AfPRFhEpFXYACA/VtgAFBhBqBRYQXgUltgAGAEYQcgUn8juHLdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGEHQFJhByBgBIBgIIRhB4ABAYJgIIUBYABgBFrxUFCAUYIBkVBQM2AggmEHgAEBUmAggQGQUDBgIIJhB4ABAVJgIIEBkFBgBGEFwFFgBYEQYRMfV2AAgP1bYCACATVgIIJhB4ABAVJgIIEBkFCAYQeAUmEHgJBQgFFgIAGAYQhAgoRgAGAEWvFhE1dXYACA/VtQUGAgYQkgYQhAUWEIYGAAYQYAUVrxYRN2V2AAgP1bYCA9gIIRFWETh1eAYROJVluBW5BQkFBhCQBSYQkAgFFgIAGAYQbAgoRgAGAEWvFhE65XYACA/VtQUGAAYQbAUREVYRQBV2EGwIBgIAFRYACCUYBgIJATFWET11dgAID9W4CRkBIVYRPlV2AAgP1bgGAgA2EBAAqCBJBQkFCQUBUVYRQAV2AAgP1bW2ACYQXAURQVYRRlV2AgYQngYCRjcKCCMWEJYFIwYQmAUmEJfGEGAFFa+mEUNFdgAID9W2AfPRFhFEFXYACA/VtgAFBhCeBRYQXgUYCCEBVhFFlXYACA/VuAggOQUJBQYQXgUltbYQNAYQXAUWAFgRBhFHpXYACA/VtgIAIBUWEF4FGBgYMBEBVhFJJXYACA/VuAggGQUJBQYQUgYQXAUWAFgRBhFK1XYACA/VtgIAIBUluBUWABAYCDUoEUFWER7VdbUFBhAUBhCiBSW2EKIFFRYCBhCiBRAWEKIFJhCiBhCiBREBVhFO9XYRTNVlthCkBhBSCAUYJSgGAgAVGCYCABUoBgQAFRgmBAAVKAYGABUYJgYAFSgGCAAVGCYIABUlBQYQIgUWEK4FJhCuBRYQrAUWEKoFFhCoBRYQpgUWEKQFFgBlgBYQfrVlthC0BSYQoAYQogUlthCiBRUmAgYQogUQNhCiBSYQFAYQogURAVFWEVe1dhFVhWW2ELQFFhCgBSYQMgUWEKAFERYRWVV2AAgP1bYQoAUWELYFJgAGECgFERFWEYq1dhC4BgAGAFgYNSAVthCgBRYQNAYQuAUWAFgRBhFc1XYACA/VtgIAIBUYCCAoIVgoSDBBQXYRXmV2AAgP1bgJBQkFCQUGEDIFGAgGEV/FdgAID9W4IEkFCQUGELoFJgAGELwFJhBSBhC4BRYAWBEGEWIFdgAID9W2AgAgFRYQugUREVYRZpV2ELoFFhBSBhC4BRYAWBEGEWR1dgAID9W2AgAgFRgIIQFWEWWVdgAID9W4CCA5BQkFBhC8BSYRafVlthBSBhC4BRYAWBEGEWfVdgAID9W2AgAgFRYQugUYCCEBVhFpNXYACA/VuAggOQUJBQYQvAUlthAeBRYQvAUYCCAoIVgoSDBBQXYRa7V2AAgP1bgJBQkFCQUGQCVAvkAICAYRbTV2AAgP1bggSQUJBQYQFAYQuAUWAFgRBhFu1XYACA/VtgIAIBUmEFIGELgFFgBYEQYRcGV2AAgP1bYCACAVFhAUBhC4BRYAWBEGEXH1dgAID9W2AgAgFRYQIAUYCCAoIVgoSDBBQXYRc8V2AAgP1bgJBQkFCQUGQCVAvkAICAYRdUV2AAgP1bggSQUJBQgIIQFWEXZ1dgAID9W4CCA5BQkFBhC4BRYAWBEGEXf1dgAID9W2ABYMBSYCBgwCABVWEFIGELgFFgBYEQYRefV2AAgP1bYCACAYBRYQFAYQuAUWAFgRBhF7lXYACA/VtgIAIBUYCCEBVhF8tXYACA/VuAggOQUJBQgVJQW4FRYAEBgINSgRQVYRW1V1tQUGEBQGEL4FJbYQvgUVFgIGEL4FEBYQvgUmELgGEL4FEQFWEYEldhF/BWW2EMAGEFIIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAiBRYQygUmEMoFFhDIBRYQxgUWEMQFFhDCBRYQwAUWAGWAFhB+tWW2ENAFJhC2BhC+BSW2EL4FFSYCBhC+BRA2EL4FJhAUBhC+BREBUVYRieV2EYe1ZbYQ0AUWELYFJhGOdWW2ABYMBSYCBgwCBhBSCAUYJVgGAgAVFgAYMBVYBgQAFRYAKDAVWAYGABUWADgwFVgGCAAVFgBIMBVVBQW2AAYQ0gUmECgFEVFWEZBFdhCgBRYQ0gUmEZWVZbYQKAUWELYFFhAyBRgIIQFWEZHVdgAID9W4CCA5BQkFCAggKCFYKEgwQUF2EZOFdgAID9W4CQUJBQkFBhAyBRgIBhGU5XYACA/VuCBJBQkFBhDSBSW2MIw3mgYQ1AUmAgYQ1gUmAUYQ2AUn9TbGlwcGFnZSBzY3Jld2VkIHlvdQAAAAAAAAAAAAAAAGENoFJhDYBQYKQ1YQ0gURAVYRmrV2BkYQ1c/VtgIGEOgGBEY0DBDxlhDeBSM2EOAFJhDSBRYQ4gUmEN/GAAYAZUWvFhGdtXYACA/VtgHz0RYRnoV2AAgP1bYABQYQ6AUGAENWEOoFJgJDVhDsBSYEQ1YQ7gUmBkNWEPAFJghDVhDyBSYQFAUWEPQFJhAWBRYQ9gUmEBgFFhD4BSYQGgUWEPoFJhAcBRYQ/AUmEKAFFhD+BSYQKAUWENIFGBgYMBEBVhGllXYACA/VuAggGQUJBQYRAAUjN/OLexooeFTZ4YBfiLZgOGWe4y4dE2L8yrpEkj0xWe1JNhAYBhDqCiYABi////VQBbYAAVYR9BV1thAkBSYQFAUmEBYFJhAYBSYQGgUmEBwFJhAeBSYQIAUmECIFJhAWBRYQFAURhhGtRXYACA/VtgAGEBYFESFWEa5VdgAID9W2AFYQFgURJhGvVXYACA/VtgAGEBQFESFWEbBldgAID9W2AFYQFAURJhGxZXYACA/VthAUBRYQFgUWEBgFFhAaBRYQHAUWEB4FFhAgBRYQIgUWECQFFhAmBRYAZYAWEAqVZbYQKgUmECYFJhAkBSYQIgUmECAFJhAeBSYQHAUmEBoFJhAYBSYQFgUmEBQFJhAqBRYQJgUmEBQGEC4FJbYQLgUVFgIGEC4FEBYQLgUmEC4GEC4FEQFWEbpVdhG4NWW2EDAGEBoIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAmBRYQOgUmEDoFFhA4BRYQNgUWEDQFFhAyBRYQMAUWAGWAFhBPVWW2EEAFJhAsBhAuBSW2EC4FFSYCBhAuBRA2EC4FJhAUBhAuBREBUVYRwxV2EcDlZbYQQAUWECwFJhAsBRYQQgUmAAYQRAUmECYFFgBYCCAoIVgoSDBBQXYRxhV2AAgP1bgJBQkFCQUGEEYFJgAGEEgFJhBKBgAGAFgYNSAVthAUBRYQSgURQVYRyZV2EBgFFhBIBSYRzPVlthAWBRYQSgURgVYRzJV2EBoGEEoFFgBYEQYRy7V2AAgP1bYCACAVFhBIBSYRzOVlthHUtWW1thBECAUWEEgFGBgYMBEBVhHOdXYACA/VuAggGQUJBQgVJQYQQgUWECwFGAggKCFYKEgwQUF2EdDVdgAID9W4CQUJBQkFBhBIBRYAWAggKCFYKEgwQUF2EdLldgAID9W4CQUJBQkFCAgGEdQFdgAID9W4IEkFCQUGEEIFJbgVFgAQGAg1KBFBVhHH5XW1BQYQQgUWECwFGAggKCFYKEgwQUF2EdeVdgAID9W4CQUJBQkFBhBGBRYAWAggKCFYKEgwQUF2EdmldgAID9W4CQUJBQkFCAgGEdrFdgAID9W4IEkFCQUGEEIFJhBEBRYQLAUWEEYFGAgGEdzVdgAID9W4IEkFCQUIGBgwEQFWEd4ldgAID9W4CCAZBQkFBhBMBSYABhBOBSYQLAUWEFAFJhBSBgAGD/gYNSAVthBQBRYQTgUmEFAFFhBQBRgIICghWChIMEFBdhHitXYACA/VuAkFCQUJBQYQQgUYGBgwEQFWEeRVdgAID9W4CCAZBQkFBgAmEFAFGAggKCFYKEgwQUF2EeZldgAID9W4CQUJBQkFBhBMBRgYGDARAVYR6AV2AAgP1bgIIBkFCQUGECwFGAghAVYR6YV2AAgP1bgIIDkFCQUICAYR6qV2AAgP1bggSQUJBQYQUAUmEE4FFhBQBRERVhHvFXYAFhBQBRYQTgUYCCEBVhHtlXYACA/VuAggOQUJBQERUVYR7sV2EfLVZbYR8cVltgAWEE4FFhBQBRgIIQFWEfCFdgAID9W4CCA5BQkFARFRVhHxtXYR8tVltbW4FRYAEBgINSgRQVYR4HV1tQUGEFAFFgAFJgAFFhAkBRVlAAW2NeDUQ/YABRFBVhIt1XNBVhH1pXYACA/VtgYFFgBDWAYEBRkBMVYR9wV2AAgP1bgJGQEhVhH35XYACA/VtQYGBRYCQ1gGBAUZATFWEflVdgAID9W4CRkBIVYR+jV2AAgP1bUGEBQGcN4Lazp2QAAIFSZw3gtrOnZAAAgWAgAVJnDeC2s6dkAACBYEABUmcN4Lazp2QAAIFgYAFSZw3gtrOnZAAAgWCAAVJQYQHgYQFAUWEBYFFhAYBRYQGgUWEBwFFhAeBRYQIAUWECIFFhAkBRYQJgUWAGWAFhAoFWW2ECoFJhAsBSYQLgUmEDAFJhAyBSYQJgUmECQFJhAiBSYQIAUmEB4FJhAcBSYQGgUmEBgFJhAWBSYQFAUmECoIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAeBgBDVgBYEQYSCfV2AAgP1bYCACAVFgRDVhAUBgBDVgBYEQYSC6V2AAgP1bYCACAVGAggKCFYKEgwQUF2Eg01dgAID9W4CQUJBQkFBnDeC2s6dkAACAgGEg7ldgAID9W4IEkFCQUIGBgwEQFWEhA1dgAID9W4CCAZBQkFBhA0BSYQFAYQOAUlthA4BRUWAgYQOAUQFhA4BSYQOAYQOAURAVYSE4V2EhFlZbYAQ1YQOgUmAkNWEDwFJhA0BRYQPgUmEEAGEB4IBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhBIBRYQRgUWEEQFFhBCBRYQQAUWED4FFhA8BRYQOgUWAGWAFhGp5WW2EE4FJhA2BhA4BSW2EDgFFSYCBhA4BRA2EDgFJhAUBhA4BREBUVYSHaV2Eht1ZbYQTgUWEDYFJhAeBgJDVgBYEQYSH1V2AAgP1bYCACAVFhA2BRgIIQFWEiC1dgAID9W4CCA5BQkFBgAYCCEBVhIiFXYACA/VuAggOQUJBQZw3gtrOnZAAAgIICghWChIMEFBdhIkVXYACA/VuAkFCQUJBQYQFAYCQ1YAWBEGEiX1dgAID9W2AgAgFRgIBhIm9XYACA/VuCBJBQkFBhBQBSYAJUYQUAUYCCAoIVgoSDBBQXYSKUV2AAgP1bgJBQkFCQUGQCVAvkAICAYSKsV2AAgP1bggSQUJBQYQUgUmEFAFFhBSBRgIIQFWEiy1dgAID9W4CCA5BQkFBgAFJgIGAA81AAW2MHIR73YABRFBVhJfBXNBVhIvZXYACA/VtgYFFgBDWAYEBRkBMVYSMMV2AAgP1bgJGQEhVhIxpXYACA/VtQYGBRYCQ1gGBAUZATFWEjMVdgAID9W4CRkBIVYSM/V2AAgP1bUGEBQGEBQFFhAWBRYQGAUWEBoFFhAcBRYAZYAWECgVZbYQIAUmECIFJhAkBSYQJgUmECgFJhAcBSYQGgUmEBgFJhAWBSYQFAUmECAIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAqBgAYFSYAGBYCABUmABgWBAAVJgAYFgYAFSYAGBYIABUlBhAUBgBDVgBYEQYSPwV2AAgP1bYCACAVFgRDVhAqBgBDVgBYEQYSQLV2AAgP1bYCACAVGAggKCFYKEgwQUF2EkJFdgAID9W4CQUJBQkFCBgYMBEBVhJDpXYACA/VuAggGQUJBQYQNAUmEBQGEDgFJbYQOAUVFgIGEDgFEBYQOAUmEDgGEDgFEQFWEkb1dhJE1WW2AENWEDoFJgJDVhA8BSYQNAUWED4FJhBABhAUCAUYJSgGAgAVGCYCABUoBgQAFRgmBAAVKAYGABUYJgYAFSgGCAAVGCYIABUlBQYQSAUWEEYFFhBEBRYQQgUWEEAFFhA+BRYQPAUWEDoFFgBlgBYRqeVlthBOBSYQNgYQOAUlthA4BRUmAgYQOAUQNhA4BSYQFAYQOAURAVFWElEVdhJO5WW2EE4FFhA2BSYQFAYCQ1YAWBEGElLFdgAID9W2AgAgFRYQNgUYCCEBVhJUJXYACA/VuAggOQUJBQYAGAghAVYSVYV2AAgP1bgIIDkFCQUGECoGAkNWAFgRBhJXJXYACA/VtgIAIBUYCAYSWCV2AAgP1bggSQUJBQYQUAUmACVGEFAFGAggKCFYKEgwQUF2Elp1dgAID9W4CQUJBQkFBkAlQL5ACAgGElv1dgAID9W4IEkFCQUGEFIFJhBQBRYQUgUYCCEBVhJd5XYACA/VuAggOQUJBQYABSYCBgAPNQAFtjPfAhJGAAURQVYS/WV2L///9UFWEmDVdgAID9W2ABYv///1U0FWEmH1dgAID9W2BgUWAENYBgQFGQExVhJjVXYACA/VuAkZASFWEmQ1dgAID9W1BgYFFgJDWAYEBRkBMVYSZaV2AAgP1bgJGQEhVhJmhXYACA/VtQYBBUFWEmdldgAID9W2EBQGcN4Lazp2QAAIFSZw3gtrOnZAAAgWAgAVJnDeC2s6dkAACBYEABUmcN4Lazp2QAAIFgYAFSZw3gtrOnZAAAgWCAAVJQYQHgYAGAYMBSYCBgwCBUglJgAYFgwFJgIGDAIAFUgmAgAVJgAoFgwFJgIGDAIAFUgmBAAVJgA4FgwFJgIGDAIAFUgmBgAVJgBIFgwFJgIGDAIAFUgmCAAVJQUGECgGEBQGEDIFJbYQMgUVFgIGEDIFEBYQMgUmEDIGEDIFEQFWEnRVdhJyNWW2EDQGEB4IBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhA8BRYQOgUWEDgFFhA2BRYQNAUWAGWAFhA7NWW2EEIFJhBEBSYQRgUmEEgFJhBKBSYQMAYQMgUlthAyBRUmAgYQMgUQNhAyBSYQFAYQMgURAVFWEn1VdhJ7JWW2EEIIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBgRDVhBMBSYAQ1YAWBEGEoHVdgAID9W2AAYMBSYCBgwCABVGEE4FJgAmAENRQVYSh4V2AgYQWAYCRjcKCCMWEFAFIwYQUgUmEFHGEE4FFa+mEoX1dgAID9W2AfPRFhKGxXYACA/VtgAFBhBYBRYQTAUltgAGAEYQYAUn8juHLdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGEGIFJhBgBgBIBgIIRhBmABAYJgIIUBYABgBFrxUFCAUYIBkVBQM2AggmEGYAEBUmAggQGQUDBgIIJhBmABAVJgIIEBkFBgRDVgIIJhBmABAVJgIIEBkFCAYQZgUmEGYJBQgFFgIAGAYQcggoRgAGAEWvFhKR1XYACA/VtQUGAgYQgAYQcgUWEHQGAAYQTgUVrxYSk8V2AAgP1bYCA9gIIRFWEpTVeAYSlPVluBW5BQkFBhB+BSYQfggFFgIAGAYQWggoRgAGAEWvFhKXRXYACA/VtQUGAAYQWgUREVYSnHV2EFoIBgIAFRYACCUYBgIJATFWEpnVdgAID9W4CRkBIVYSmrV2AAgP1bgGAgA2EBAAqCBJBQkFCQUBUVYSnGV2AAgP1bW2ACYAQ1FBVhKipXYCBhCMBgJGNwoIIxYQhAUjBhCGBSYQhcYQTgUVr6YSn5V2AAgP1bYB89EWEqBldgAID9W2AAUGEIwFFhBMBRgIIQFWEqHldgAID9W4CCA5BQkFBhBMBSW2ECgGAENWAFgRBhKj1XYACA/VtgIAIBUWEEwFFhAUBgBDVgBYEQYSpZV2AAgP1bYCACAVGAggKCFYKEgwQUF2EqcldgAID9W4CQUJBQkFBnDeC2s6dkAACAgGEqjVdgAID9W4IEkFCQUIGBgwEQFWEqoldgAID9W4CCAZBQkFBhCOBSYQFAYQkgUlthCSBRUWAgYQkgUQFhCSBSYQkgYQkgURAVYSrXV2EqtVZbYAQ1YQlAUmAkNWEJYFJhCOBRYQmAUmEJoGECgIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhCiBRYQoAUWEJ4FFhCcBRYQmgUWEJgFFhCWBRYQlAUWAGWAFhGp5WW2EKgFJhCQBhCSBSW2EJIFFSYCBhCSBRA2EJIFJhAUBhCSBREBUVYSt5V2ErVlZbYQqAUWEJAFJhAoBgJDVgBYEQYSuUV2AAgP1bYCACAVFhCQBRgIIQFWErqldgAID9W4CCA5BQkFBgAYCCEBVhK8BXYACA/VuAggOQUJBQYQqgUmEKoFFgAlSAggKCFYKEgwQUF2Er5ldgAID9W4CQUJBQkFBkAlQL5ACAgGEr/ldgAID9W4IEkFCQUGEKwFJhCqBRYQrAUYCCEBVhLB1XYACA/VuAggOQUJBQZw3gtrOnZAAAgIICghWChIMEFBdhLEFXYACA/VuAkFCQUJBQYQFAYCQ1YAWBEGEsW1dgAID9W2AgAgFRgIBhLGtXYACA/VuCBJBQkFBhCqBSYwjDeaBhCuBSYCBhCwBSYC5hCyBSf0V4Y2hhbmdlIHJlc3VsdGVkIGluIGZld2VyIGNvaW5zYQtAUn8gdGhhbiBleHBlY3RlZAAAAAAAAAAAAAAAAAAAAAAAAGELYFJhCyBQYGQ1YQqgURAVYSzsV2CEYQr8/VthCsBRYANUgIICghWChIMEFBdhLQdXYACA/VuAkFCQUJBQZAJUC+QAgIBhLR9XYACA/VuCBJBQkFBhC6BSYQugUWcN4Lazp2QAAICCAoIVgoSDBBQXYS1KV2AAgP1bgJBQkFCQUGEBQGAkNWAFgRBhLWRXYACA/VtgIAIBUYCAYS10V2AAgP1bggSQUJBQYQugUmEB4GAENWAFgRBhLZFXYACA/VtgIAIBUWEEwFGBgYMBEBVhLalXYACA/VuAggGQUJBQYAQ1YAWBEGEtwFdgAID9W2ABYMBSYCBgwCABVWEB4GAkNWAFgRBhLd9XYACA/VtgIAIBUWEKoFGAghAVYS31V2AAgP1bgIIDkFCQUGELoFGAghAVYS4NV2AAgP1bgIIDkFCQUGAkNWAFgRBhLiRXYACA/VtgAWDAUmAgYMAgAVVgAGAEYQvAUn+pBZy7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGEL4FJhC8BgBIBgIIRhDCABAYJgIIUBYABgBFrxUFCAUYIBkVBQM2AggmEMIAEBUmAggQGQUGEKoFFgIIJhDCABAVJgIIEBkFCAYQwgUmEMIJBQgFFgIAGAYQzAgoRgAGAEWvFhLsZXYACA/VtQUGAgYQ2AYQzAUWEM4GAAYCQ1YAWBEGEu5ldgAID9W2AAYMBSYCBgwCABVFrxYS79V2AAgP1bYCA9gIIRFWEvDleAYS8QVluBW5BQkFBhDWBSYQ1ggFFgIAGAYQWggoRgAGAEWvFhLzVXYACA/VtQUGAAYQWgUREVYS+IV2EFoIBgIAFRYACCUYBgIJATFWEvXldgAID9W4CRkBIVYS9sV2AAgP1bgGAgA2EBAAqCBJBQkFCQUBUVYS+HV2AAgP1bW2AENWENwFJgRDVhDeBSYCQ1YQ4AUmEKoFFhDiBSM3+LPpbyuIn6dxxTyYG0Da8AX2P2N/GGn3BwUtFaPdlxQGCAYQ3AomAAYv///1UAW2Pjv/XOYABRFBVhM95XYv///1QVYS/zV2AAgP1bYAFi////VTQVYTAFV2AAgP1bYCBhAcBgBGMYFg3dYQFgUmEBfGAGVFr6YTAmV2AAgP1bYB89EWEwM1dgAID9W2AAUGEBwFFhAUBSYKA2YQHgN2CgNmECgDdhAyBgAGAFgYNSAVthAyBRYAWBEGEwaVdgAID9W2ABYMBSYCBgwCABVGAENYCCAoIVgoSDBBQXYTCMV2AAgP1bgJBQkFCQUGEBQFGAgGEwoldgAID9W4IEkFCQUGEDQFJjCMN5oGEDYFJgIGEDgFJgMGEDoFJ/V2l0aGRyYXdhbCByZXN1bHRlZCBpbiBmZXdlciBjb2lhA8BSf25zIHRoYW4gZXhwZWN0ZWQAAAAAAAAAAAAAAAAAAAAAYQPgUmEDoFBgJGEDIFFgBYEQYTEiV2AAgP1bYCACATVhA0BREBVhMThXYIRhA3z9W2EDIFFgBYEQYTFJV2AAgP1bYAFgwFJgIGDAIAGAVGEDQFGAghAVYTFnV2AAgP1bgIIDkFCQUIFVUGEDQFFhAeBhAyBRYAWBEGExiVdgAID9W2AgAgFSYABgBGEEgFJ/qQWcuwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABhBKBSYQSAYASAYCCEYQTgAQGCYCCFAWAAYARa8VBQgFGCAZFQUDNgIIJhBOABAVJgIIEBkFBhA0BRYCCCYQTgAQFSYCCBAZBQgGEE4FJhBOCQUIBRYCABgGEFgIKEYABgBFrxYTIkV2AAgP1bUFBgIGEGQGEFgFFhBaBgAGEDIFFgBYEQYTJFV2AAgP1bYABgwFJgIGDAIAFUWvFhMlxXYACA/VtgID2AghEVYTJtV4BhMm9WW4FbkFCQUGEGIFJhBiCAUWAgAYBhBCCChGAAYARa8WEylFdgAID9W1BQYABhBCBRERVhMudXYQQggGAgAVFgAIJRgGAgkBMVYTK9V2AAgP1bgJGQEhVhMstXYACA/VuAYCADYQEACoIEkFCQUJBQFRVhMuZXYACA/VtbW4FRYAEBgINSgRQVYTBYV1tQUGAgYQcgYERjecxnkGEGgFIzYQagUmAENWEGwFJhBpxgAGAGVFrxYTMpV2AAgP1bYB89EWEzNldgAID9W2AAUGEHIFBhAeBRYQdAUmECAFFhB2BSYQIgUWEHgFJhAkBRYQegUmECYFFhB8BSYQKAUWEH4FJhAqBRYQgAUmECwFFhCCBSYQLgUWEIQFJhAwBRYQhgUmEBQFFgBDWAghAVYTOhV2AAgP1bgIIDkFCQUGEIgFIzf0GthrkxtiHzCjxQsKgbpdaAceR/UjmcBijWxEKUw/IHYQFgYQdAomAAYv///1UAW2O7S116YABRFBVhPdlXYv///1QVYTP7V2AAgP1bYAFi////VTQVYTQNV2AAgP1bYBBUFWE0GldgAID9W2AgYQHAYARjGBYN3WEBYFJhAXxgBlRa+mE0O1dgAID9W2AfPRFhNEhXYACA/VtgAFBhAcBRYQFAUmAAYQFAURhhNGNXYACA/VtgAlRgBYCCAoIVgoSDBBQXYTR8V2AAgP1bgJBQkFCQUGAQgIBhNJBXYACA/VuCBJBQkFBhAeBSYANUYQIAUmEBQFFhAWBRYQGAUWEBoFFhAcBRYQHgUWECAFFhAiBRYAZYAWEAqVZbYQJgUmECIFJhAgBSYQHgUmEBwFJhAaBSYQGAUmEBYFJhAUBSYQJgUWECIFJhAoBgAYBgwFJgIGDAIFSCUmABgWDAUmAgYMAgAVSCYCABUmACgWDAUmAgYMAgAVSCYEABUmADgWDAUmAgYMAgAVSCYGABUmAEgWDAUmAgYMAgAVSCYIABUlBQYQMgYQKAgFGCUoBgIAFRgmAgAVKAYEABUYJgQAFSgGBgAVGCYGABUoBggAFRgmCAAVJQUGEBQGED4FJbYQPgUVFgIGED4FEBYQPgUmED4GED4FEQFWE1r1dhNY1WW2EEAGECgIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAiBRYQSgUmEEoFFhBIBRYQRgUWEEQFFhBCBRYQQAUWAGWAFhB+tWW2EFAFJhA8BhA+BSW2ED4FFSYCBhA+BRA2ED4FJhAUBhA+BREBUVYTY7V2E2GFZbYQUAUWEDwFJhBSBgAGAFgYNSAVthAyBhBSBRYAWBEGE2Y1dgAID9W2AgAgGAUWAEYQUgUWAFgRBhNnxXYACA/VtgIAIBNYCCEBVhNo5XYACA/VuAggOQUJBQgVJQW4FRYAEBgINSgRQVYTZPV1tQUGEBQGEFYFJbYQVgUVFgIGEFYFEBYQVgUmEFYGEFYFEQFWE21VdhNrNWW2EFgGEDIIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAiBRYQYgUmEGIFFhBgBRYQXgUWEFwFFhBaBRYQWAUWAGWAFhB+tWW2EGgFJhBUBhBWBSW2EFYFFSYCBhBWBRA2EFYFJhAUBhBWBREBUVYTdhV2E3PlZbYQaAUWEFQFJgoDZhBqA3YQdAYABgBYGDUgFbYQVAUWECgGEHQFFgBYEQYTeUV2AAgP1bYCACAVGAggKCFYKEgwQUF2E3rVdgAID9W4CQUJBQkFBhA8BRgIBhN8NXYACA/VuCBJBQkFBhB2BSYABhB4BSYQMgYQdAUWAFgRBhN+dXYACA/VtgIAIBUWEHYFERFWE4MFdhB2BRYQMgYQdAUWAFgRBhOA5XYACA/VtgIAIBUYCCEBVhOCBXYACA/VuAggOQUJBQYQeAUmE4ZlZbYQMgYQdAUWAFgRBhOERXYACA/VtgIAIBUWEHYFGAghAVYThaV2AAgP1bgIIDkFCQUGEHgFJbYQHgUWEHgFGAggKCFYKEgwQUF2E4gldgAID9W4CQUJBQkFBkAlQL5ACAgGE4mldgAID9W4IEkFCQUGEGoGEHQFFgBYEQYTi0V2AAgP1bYCACAVJhAyBhB0BRYAWBEGE4zVdgAID9W2AgAgFRYQagYQdAUWAFgRBhOOZXYACA/VtgIAIBUWECAFGAggKCFYKEgwQUF2E5A1dgAID9W4CQUJBQkFBkAlQL5ACAgGE5G1dgAID9W4IEkFCQUICCEBVhOS5XYACA/VuAggOQUJBQYQdAUWAFgRBhOUZXYACA/VtgAWDAUmAgYMAgAVVhAyBhB0BRYAWBEGE5ZldgAID9W2AgAgGAUWEGoGEHQFFgBYEQYTmAV2AAgP1bYCACAVGAghAVYTmSV2AAgP1bgIIDkFCQUIFSUFuBUWABAYCDUoEUFWE3fFdbUFBhAUBhB8BSW2EHwFFRYCBhB8BRAWEHwFJhB8BhB8BREBVhOdlXYTm3VlthB+BhAyCAUYJSgGAgAVGCYCABUoBgQAFRgmBAAVKAYGABUYJgYAFSgGCAAVGCYIABUlBQYQIgUWEIgFJhCIBRYQhgUWEIQFFhCCBRYQgAUWEH4FFgBlgBYQfrVlthCOBSYQegYQfAUlthB8BRUmAgYQfAUQNhB8BSYQFAYQfAURAVFWE6ZVdhOkJWW2EI4FFhB6BSYQPAUWEHoFGAghAVYTqCV2AAgP1bgIIDkFCQUGEBQFGAggKCFYKEgwQUF2E6oVdgAID9W4CQUJBQkFBhA8BRgIBhOrdXYACA/VuCBJBQkFBhCQBSYABhCQBRGGE60VdgAID9W2EJAIBRYAGBgYMBEBVhOudXYACA/VuAggGQUJBQgVJQYwjDeaBhCSBSYCBhCUBSYBRhCWBSf1NsaXBwYWdlIHNjcmV3ZWQgeW91AAAAAAAAAAAAAAAAYQmAUmEJYFBgpDVhCQBRERVhO0NXYGRhCTz9W2AgYQpgYERjecxnkGEJwFIzYQngUmEJAFFhCgBSYQncYABgBlRa8WE7c1dgAID9W2AfPRFhO4BXYACA/VtgAFBhCmBQYQqAYABgBYGDUgFbYABgBGEKgFFgBYEQYTuoV2AAgP1bYCACATUYFWE9IVdgAGAEYQsAUn+pBZy7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGELIFJhCwBgBIBgIIRhC2ABAYJgIIUBYABgBFrxUFCAUYIBkVBQM2AggmELYAEBUmAggQGQUGAEYQqAUWAFgRBhPCVXYACA/VtgIAIBNWAggmELYAEBUmAggQGQUIBhC2BSYQtgkFCAUWAgAYBhDACChGAAYARa8WE8XVdgAID9W1BQYCBhDMBhDABRYQwgYABhCoBRYAWBEGE8fldgAID9W2AAYMBSYCBgwCABVFrxYTyVV2AAgP1bYCA9gIIRFWE8pleAYTyoVluBW5BQkFBhDKBSYQyggFFgIAGAYQqggoRgAGAEWvFhPM1XYACA/VtQUGAAYQqgUREVYT0gV2EKoIBgIAFRYACCUYBgIJATFWE89ldgAID9W4CRkBIVYT0EV2AAgP1bgGAgA2EBAAqCBJBQkFCQUBUVYT0fV2AAgP1bW1tbgVFgAQGAg1KBFBVhO5NXW1BQYAQ1YQ0AUmAkNWENIFJgRDVhDUBSYGQ1YQ1gUmCENWENgFJhBqBRYQ2gUmEGwFFhDcBSYQbgUWEN4FJhBwBRYQ4AUmEHIFFhDiBSYQVAUWEOQFJhAUBRYQkAUYCCEBVhPZxXYACA/VuAggOQUJBQYQ5gUjN/xgT3sR5AfoGyyNDUArYqUkQ4jD7/PedpSjK/QYo/Ng9hAYBhDQCiYABi////VQBbYAAVYUESV1thAkBSYQFAUmEBYFJhAYBSYQGgUmEBwFJhAeBSYQIAUmECIFJgAGEBYFESFWE+FldgAID9W2AFYQFgURJhPiZXYACA/VthAiBRYQJgUmAAYQKAUmEBQFFgBYCCAoIVgoSDBBQXYT5OV2AAgP1bgJBQkFCQUGECoFJgAGECwFJhAuBgAGAFgYNSAVthAWBRYQLgURgVYT6bV2EBgGEC4FFgBYEQYT6NV2AAgP1bYCACAVFhAsBSYT6gVlthPxxWW2ECgIBRYQLAUYGBgwEQFWE+uFdgAID9W4CCAZBQkFCBUlBhAmBRYQIgUYCCAoIVgoSDBBQXYT7eV2AAgP1bgJBQkFCQUGECwFFgBYCCAoIVgoSDBBQXYT7/V2AAgP1bgJBQkFCQUICAYT8RV2AAgP1bggSQUJBQYQJgUluBUWABAYCDUoEUFWE+a1dbUFBhAmBRYQIgUYCCAoIVgoSDBBQXYT9KV2AAgP1bgJBQkFCQUGECoFFgBYCCAoIVgoSDBBQXYT9rV2AAgP1bgJBQkFCQUICAYT99V2AAgP1bggSQUJBQYQJgUmECgFFhAiBRYQKgUYCAYT+eV2AAgP1bggSQUJBQgYGDARAVYT+zV2AAgP1bgIIBkFCQUGEDAFJgAGEDIFJhAiBRYQNAUmEDYGAAYP+Bg1IBW2EDQFFhAyBSYQNAUWEDQFGAggKCFYKEgwQUF2E//FdgAID9W4CQUJBQkFBhAmBRgYGDARAVYUAWV2AAgP1bgIIBkFCQUGACYQNAUYCCAoIVgoSDBBQXYUA3V2AAgP1bgJBQkFCQUGEDAFGBgYMBEBVhQFFXYACA/VuAggGQUJBQYQIgUYCCEBVhQGlXYACA/VuAggOQUJBQgIBhQHtXYACA/VuCBJBQkFBhA0BSYQMgUWEDQFERFWFAwldgAWEDQFFhAyBRgIIQFWFAqldgAID9W4CCA5BQkFARFRVhQL1XYUD+VlthQO1WW2ABYQMgUWEDQFGAghAVYUDZV2AAgP1bgIIDkFCQUBEVFWFA7FdhQP5WW1tbgVFgAQGAg1KBFBVhP9hXW1BQYQNAUWAAUmAAUWECQFFWUABbYAAVYUhjV1thAYBSYQFAUmEBYFJhAUBRYQFgUWEBgFFhAaBRYAZYAWEAqVZbYQHgUmEBoFJhAYBSYQFgUmEBQFJhAeBRYQGgUmACVGAFgIICghWChIMEFBdhQXRXYACA/VuAkFCQUJBQYBCAgGFBiFdgAID9W4IEkFCQUGECAFJhAiBgAYFSYAGBYCABUmABgWBAAVJgAYFgYAFSYAGBYIABUlBgIGEDQGAEYxgWDd1hAuBSYQL8YAZUWvphQddXYACA/VtgHz0RYUHkV2AAgP1bYABQYQNAUWECwFJhA2BhAUBhBABSW2EEAFFRYCBhBABRAWEEAFJhBABhBABREBVhQhxXYUH6VltgBlgBYQKBVlthBCBSYQRAUmEEYFJhBIBSYQSgUmED4GEEAFJbYQQAUVJgIGEEAFEDYQQAUmEBQGEEAFEQFRVhQmRXYUJBVlthBCCAUYJSgGAgAVGCYCABUoBgQAFRgmBAAVKAYGABUYJgYAFSgGCAAVGCYIABUlBQYQFAYQTgUlthBOBRUWAgYQTgUQFhBOBSYQTgYQTgURAVYUK/V2FCnVZbYQUAYQNggFGCUoBgIAFRgmAgAVKAYEABUYJgQAFSgGBgAVGCYGABUoBggAFRgmCAAVJQUGEBoFFhBaBSYQWgUWEFgFFhBWBRYQVAUWEFIFFhBQBRYAZYAWEE9VZbYQYAUmEEwGEE4FJbYQTgUVJgIGEE4FEDYQTgUmEBQGEE4FEQFRVhQ0tXYUMoVlthBgBRYQTAUmEEwFFhAUBRYQTAUYCCAoIVgoSDBBQXYUNzV2AAgP1bgJBQkFCQUGECwFGAgGFDiVdgAID9W4IEkFCQUICCEBVhQ5xXYACA/VuAggOQUJBQYQYgUmEGQGEDYIBRglKAYCABUYJgIAFSgGBAAVGCYEABUoBgYAFRgmBgAVKAYIABUYJggAFSUFBhAUBhBwBSW2EHAFFRYCBhBwBRAWEHAFJhBwBhBwBREBVhRAVXYUPjVlthAaBRYQcgUmEBYFFhB0BSYQdgYQNggFGCUoBgIAFRgmAgAVKAYEABUYJgQAFSgGBgAVGCYGABUoBggAFRgmCAAVJQUGEGIFFhCABSYQgAUWEH4FFhB8BRYQegUWEHgFFhB2BRYQdAUWEHIFFgBlgBYT3hVlthCGBSYQbgYQcAUlthBwBRUmAgYQcAUQNhBwBSYQFAYQcAURAVFWFEqVdhRIZWW2EIYFFhBuBSYQNgYQFgUWAFgRBhRMVXYACA/VtgIAIBUWEG4FGAghAVYUTbV2AAgP1bgIIDkFCQUGECIGEBYFFgBYEQYUT2V2AAgP1bYCACAVGAgGFFBldgAID9W4IEkFCQUGEIgFJhCKBgAGAFgYNSAVtgAGEIwFJhAWBRYQigURQVYUWeV2EDYGEIoFFgBYEQYUVEV2AAgP1bYCACAVFhBiBRgIICghWChIMEFBdhRWFXYACA/VuAkFCQUJBQYQTAUYCAYUV3V2AAgP1bggSQUJBQYQbgUYCCEBVhRY5XYACA/VuAggOQUJBQYQjAUmFGHVZbYQNgYQigUWAFgRBhRbJXYACA/VtgIAIBUWEDYGEIoFFgBYEQYUXLV2AAgP1bYCACAVFhBiBRgIICghWChIMEFBdhRehXYACA/VuAkFCQUJBQYQTAUYCAYUX+V2AAgP1bggSQUJBQgIIQFWFGEVdgAID9W4CCA5BQkFBhCMBSW2EGQGEIoFFgBYEQYUYxV2AAgP1bYCACAYBRYQIAUWEIwFGAggKCFYKEgwQUF2FGU1dgAID9W4CQUJBQkFBkAlQL5ACAgGFGa1dgAID9W4IEkFCQUICCEBVhRn5XYACA/VuAggOQUJBQgVJQW4FRYAEBgINSgRQVYUUcV1tQUGEGQGEBYFFgBYEQYUavV2AAgP1bYCACAVFhAUBhCQBSW2EJAFFRYCBhCQBRAWEJAFJhCQBhCQBREBVhRt5XYUa8VlthAaBRYQkgUmEBYFFhCUBSYQlgYQZAgFGCUoBgIAFRgmAgAVKAYEABUYJgQAFSgGBgAVGCYGABUoBggAFRgmCAAVJQUGEGIFFhCgBSYQoAUWEJ4FFhCcBRYQmgUWEJgFFhCWBRYQlAUWEJIFFgBlgBYT3hVlthCmBSYQjgYQkAUlthCQBRUmAgYQkAUQNhCQBSYQFAYQkAURAVFWFHgldhR19WW2EKYFGAghAVYUeTV2AAgP1bgIIDkFCQUGEI4FJhCOBRYAGAghAVYUexV2AAgP1bgIIDkFCQUGECIGEBYFFgBYEQYUfMV2AAgP1bYCACAVGAgGFH3FdgAID9W4IEkFCQUGEI4FJhCoCAgIBhCOBRgVJQUGAggQGQUICAYQiAUWEI4FGAghAVYUgRV2AAgP1bgIIDkFCQUIFSUFBgQJBQkFBgwFJgwFFhCsBSW2AAYQrAUREVFWFIP1dhSFtWW2AgYQrAUQNhCoABUWAgYQrAUQNhCsBSYUgtVlthAYBRVlAAW2PMKyfXYABRFBVhSNdXNBVhSHxXYACA/VtgYFFgJDWAYEBRkBMVYUiSV2AAgP1bgJGQEhVhSKBXYACA/VtQYAQ1YQFAUmAkNWEBYFJhAWBRYQFAUWAGWAFhQRpWW2EBwFJhAeBSYQHAUWAAUmAgYADzUABbYxpNAdJgAFEUFWFMQldi////VBVhSPRXYACA/VtgAWL///9VNBVhSQZXYACA/VtgYFFgJDWAYEBRkBMVYUkcV2AAgP1bgJGQEhVhSSpXYACA/VtQYBBUFWFJOFdgAID9W2AAYQFAUmAAYQFgUmEBQFFhAWBRYAQ1YQGgUmAkNWEBwFJhAcBRYQGgUWAGWAFhQRpWW2ECIFJhAkBSYQFgUmEBQFJhAiCAUWEBQFJgIIEBUWEBYFJQYwjDeaBhAmBSYCBhAoBSYBhhAqBSf05vdCBlbm91Z2ggY29pbnMgcmVtb3ZlZAAAAAAAAAAAYQLAUmECoFBgRDVhAUBREBVhSeBXYGRhAnz9W2AkNWAFgRBhSfBXYACA/VtgAWDAUmAgYMAgAYBUYQFAUWEBYFFgA1SAggKCFYKEgwQUF2FKHFdgAID9W4CQUJBQkFBkAlQL5ACAgGFKNFdgAID9W4IEkFCQUIGBgwEQFWFKSVdgAID9W4CCAZBQkFCAghAVYUpdV2AAgP1bgIIDkFCQUIFVUGAgYQOgYERjecxnkGEDAFIzYQMgUmAENWEDQFJhAxxgAGAGVFrxYUqWV2AAgP1bYB89EWFKo1dgAID9W2AAUGEDoFBgAGAEYQQgUn+pBZy7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGEEQFJhBCBgBIBgIIRhBIABAYJgIIUBYABgBFrxUFCAUYIBkVBQM2AggmEEgAEBUmAggQGQUGEBQFFgIIJhBIABAVJgIIEBkFCAYQSAUmEEgJBQgFFgIAGAYQUggoRgAGAEWvFhS0BXYACA/VtQUGAgYQXgYQUgUWEFQGAAYCQ1YAWBEGFLYFdgAID9W2AAYMBSYCBgwCABVFrxYUt3V2AAgP1bYCA9gIIRFWFLiFeAYUuKVluBW5BQkFBhBcBSYQXAgFFgIAGAYQPAgoRgAGAEWvFhS69XYACA/VtQUGAAYQPAUREVYUwCV2EDwIBgIAFRYACCUYBgIJATFWFL2FdgAID9W4CRkBIVYUvmV2AAgP1bgGAgA2EBAAqCBJBQkFCQUBUVYUwBV2AAgP1bW2AENWEGIFJhAUBRYQZAUjN/npbdO5l6KiV+7E35u26vYm4gbfX1Q72WNoLRQzAL4xBgQGEGIKJgAGL///9VAFtjPBV+ZGAAURQVYU3lVzQVYUxbV2AAgP1bYARUMxRhTGlXYACA/VtgCVRiAVGAgYGDARAVYUx/V2AAgP1bgIIBkFCQUEIQFWFMkldgAID9W0JiAVGAgYGDARAVYUymV2AAgP1bgIIBkFCQUGAkNRAVYUy7V2AAgP1bYQFAUWAGWAFhAKlWW2EBgFJhAUBSYQGAUWEBQFJgAGAENREVYUzwV2IPQkBgBDUQYUzzVltgAFthTPxXYACA/VthAUBRYAQ1EBUVYU01V2EBQFFgCoCCAoIVgoSDBBQXYU0kV2AAgP1bgJBQkFCQUGAENREVYU04VltgAFsVYU1EV2ABYU2AVlthAUBRYAQ1EBVhTXxXYQFAUWAENWAKgIICghWChIMEFBdhTW5XYACA/VuAkFCQUJBQEBVhTX9WW2AAW1tbYU2KV2AAgP1bYQFAUWAHVWAENWAIVUJgCVVgJDVgClVhAUBRYQGgUmAENWEBwFJCYQHgUmAkNWECAFJ/orcext+UkwC1mqs2tV4Ylpe3UBGd00n8+owPd56DwlRggGEBoKEAW2NVGmWIYABRFBVhTnVXNBVhTf5XYACA/VtgBFQzFGFODFdgAID9W2EBQFFgBlgBYQCpVlthAYBSYQFAUmEBgFFhAUBSYQFAUWAHVWEBQFFgCFVCYAlVQmAKVWEBQFFhAaBSQmEBwFJ/RuIvs3Ca0on2LOY9RpJIU228eNgrhKPX50rWBtwgGThgQGEBoKEAW2NbWhRnYABRFBVhTz5XNBVhTo5XYACA/VtgBFQzFGFOnFdgAID9W2ALVBVhTqlXYACA/VtkASoF8gBgBDURFWFOvVdgAID9W2QCVAvkAGAkNREVYU7RV2AAgP1bQmID9ICBgYMBEBVhTuVXYACA/VuAggGQUJBQYQFAUmEBQFFgC1VgBDVgDVVgJDVgDlVgBDVhAWBSYCQ1YQGAUmEBQFF/NR/F2i+/SA8iJd6/NmSkvJD6mSN0Oq1YtGA/ZI6TH+BgQGEBYKIAW2NPEv6XYABRFBVhT91XNBVhT1dXYACA/VtgBFQzFGFPZVdgAID9W2ALVEIQFWFPdFdgAID9W2AAYAtUGGFPg1dgAID9W2AAYAtVYA1UYQFAUmAOVGEBYFJhAUBRYAJVYQFgUWADVWEBQFFhAYBSYQFgUWEBoFJ/vhKFm2Nq7WB9UjCyzCcR9o1w5RBg5syh9XXvXS/MldFgQGEBgKEAW2MiaED7YABRFBVhUAtXNBVhT/ZXYACA/VtgBFQzFGFQBFdgAID9W2AAYAtVAFtja0QaQGAAURQVYVCsVzQVYVAkV2AAgP1bYAQ1YCBRgRBhUDVXYACA/VtQYARUMxRhUERXYACA/VtgDFQVYVBRV2AAgP1bQmID9ICBgYMBEBVhUGVXYACA/VuAggGQUJBQYQFAUmEBQFFgDFVgBDVgD1VgBDVhAUBRfxgao6oX1Mv5kmXdREProAlDPTzeedYBZP3h0aGSvrk1YABgAKMAW2NqHAWuYABRFBVhUTBXNBVhUMVXYACA/VtgBFQzFGFQ01dgAID9W2AMVEIQFWFQ4ldgAID9W2AAYAxUGGFQ8VdgAID9W2AAYAxVYA9UYQFAUmEBQFFgBFVhAUBRf3FhQHG4je5eCyrleKndey676a6DK6QZ3AJCzQZaKQtsYABgAKIAW2OG+/GTYABRFBVhUV5XNBVhUUlXYACA/VtgBFQzFGFRV1dgAID9W2AAYAxVAFtj4ufSZGAAURQVYVIFVzQVYVF3V2AAgP1bYCBhAcBgJGNwoIIxYQFAUjBhAWBSYQFcYAQ1YAWBEGFRn1dgAID9W2AAYMBSYCBgwCABVFr6YVG2V2AAgP1bYB89EWFRw1dgAID9W2AAUGEBwFFgBDVgBYEQYVHaV2AAgP1bYAFgwFJgIGDAIAFUgIIQFWFR81dgAID9W4CCA5BQkFBgAFJgIGAA81AAW2MwxUCFYABRFBVhVCtXNBVhUh5XYACA/VtgBFQzFGFSLFdgAID9W2EBQGAAYAWBg1IBW2EBQFFgBYEQYVJJV2AAgP1bYABgwFJgIGDAIAFUYQFgUmAgYQIgYCRjcKCCMWEBoFIwYQHAUmEBvGEBYFFa+mFSgFdgAID9W2AfPRFhUo1XYACA/VtgAFBhAiBRYQFAUWAFgRBhUqVXYACA/VtgAWDAUmAgYMAgAVSAghAVYVK+V2AAgP1bgIIDkFCQUGEBgFJgAGEBgFERFWFUFldgAGAEYQKgUn+pBZy7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGECwFJhAqBgBIBgIIRhAwABAYJgIIUBYABgBFrxUFCAUYIBkVBQM2AggmEDAAEBUmAggQGQUGEBgFFgIIJhAwABAVJgIIEBkFCAYQMAUmEDAJBQgFFgIAGAYQOggoRgAGAEWvFhU2tXYACA/VtQUGAgYQRgYQOgUWEDwGAAYQFgUVrxYVOKV2AAgP1bYCA9gIIRFWFTm1eAYVOdVluBW5BQkFBhBEBSYQRAgFFgIAGAYQJAgoRgAGAEWvFhU8JXYACA/VtQUGAAYQJAUREVYVQVV2ECQIBgIAFRYACCUYBgIJATFWFT61dgAID9W4CRkBIVYVP5V2AAgP1bgGAgA2EBAAqCBJBQkFCQUBUVYVQUV2AAgP1bW1tbgVFgAQGAg1KBFBVhUjhXW1BQAFtjUkw5AWAAURQVYVTkVzQVYVREV2AAgP1bYARUMxRhVFJXYACA/VthAUBgAGAFgYNSAVtgIGEB4GAkY3CggjFhAWBSMGEBgFJhAXxhAUBRYAWBEGFUh1dgAID9W2AAYMBSYCBgwCABVFr6YVSeV2AAgP1bYB89EWFUq1dgAID9W2AAUGEB4FFhAUBRYAWBEGFUw1dgAID9W2ABYMBSYCBgwCABVVuBUWABAYCDUoEUFWFUXldbUFAAW2PjaYhTYABRFBVhVSBXNBVhVP1XYACA/VtgBFQzFGFVC1dgAID9W0JgEVQRYVUZV2AAgP1bYAFgEFUAW2MwRvlyYABRFBVhVU5XNBVhVTlXYACA/VtgBFQzFGFVR1dgAID9W2AAYBBVAFtjxmEGV2AAURQVYVWOVzQVYVVnV2AAgP1bYAQ1YAWBEGFVd1dgAID9W2AAYMBSYCBgwCABVGAAUmAgYADzUABbY0kDsNFgAFEUFWFVzlc0FWFVp1dgAID9W2AENWAFgRBhVbdXYACA/VtgAWDAUmAgYMAgAVRgAFJgIGAA81AAW2Pdyj9DYABRFBVhVfVXNBVhVedXYACA/VtgAlRgAFJgIGAA81AAW2P+4/f5YABRFBVhVhxXNBVhVg5XYACA/VtgA1RgAFJgIGAA81AAW2ONpctbYABRFBVhVkNXNBVhVjVXYACA/VtgBFRgAFJgIGAA81AAW2OCxjBmYABRFBVhVmpXNBVhVlxXYACA/VtgBVRgAFJgIGAA81AAW2NUCUkaYABRFBVhVpFXNBVhVoNXYACA/VtgB1RgAFJgIGAA81AAW2O0tXetYABRFBVhVrhXNBVhVqpXYACA/VtgCFRgAFJgIGAA81AAW2MggQZsYABRFBVhVt9XNBVhVtFXYACA/VtgCVRgAFJgIGAA81AAW2MUBSKIYABRFBVhVwZXNBVhVvhXYACA/VtgClRgAFJgIGAA81AAW2NAXij4YABRFBVhVy1XNBVhVx9XYACA/VtgC1RgAFJgIGAA81AAW2PgoLWGYABRFBVhV1RXNBVhV0ZXYACA/VtgDFRgAFJgIGAA81AAW2NYaA0LYABRFBVhV3tXNBVhV21XYACA/VtgDVRgAFJgIGAA81AAW2PjgkRiYABRFBVhV6JXNBVhV5RXYACA/VtgDlRgAFJgIGAA81AAW2MewM3BYABRFBVhV8lXNBVhV7tXYACA/VtgD1RgAFJgIGAA81AAW1tgAGAA/Q==" + }, + { + "key": "BwPCMFMViItOEVFSZVvL6PptDjVgxA==", + "proof": [], + "value": "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" + }, + { + "key": "BwPO0wGqlC9yDUadiBuPrx1IdGybfQ==", + "proof": [], + "value": "YIBgQFI0gBVhABBXYACA/VtQYAQ2EGEATFdgADVg4ByAY4MZfvAUYQBRV4BjjaXLWxRhAFtXgGOv4W5EFGEAi1eAY9gFt4wUYQCuV1tgAID9W2EAWWEA0VZbAFtgAVRhAG6QYAFgAWCgGwMWgVZbYEBRYAFgAWCgGwOQkRaBUmAgAVtgQFGAkQOQ81thAJ5hAJk2YARhAa9WW2EBKlZbYEBRkBUVgVJgIAFhAIJWW2EAnmEAvDZgBGEBr1ZbYACQgVJgIIGQUmBAkCBUYP8WkFZbYAFUYAFgAWCgGwMWMxRhARxXYEBRYkYbzWDlG4FSYCBgBIIBUmAJYCSCAVJoNze6EDe7tzK5YLkbYESCAVJgZAFbYEBRgJEDkP1bYAFUYAFgAWCgGwMW/1tgAVRgAJBgAWABYKAbAxYzFGEBc1dgQFFiRhvNYOUbgVJgIGAEggFSYAlgJIIBUmg3N7oQN7u3MrlguRtgRIIBUmBkAWEBE1ZbYACCgVJgIIGQUmBAkCBUYP8WFWEBkldQYAGRkFBWW1BgAJCBUmAggZBSYECBIIBUYP8ZFmABF5BVkFZbYABgIIKEAxIVYQHBV2AAgP1bUDWRkFBW/qJkaXBmc1giEiAmjF/tE12k0guM8pcZUmg65fOfIOGnXSXA2v6hMNz+VWRzb2xjQwAICgAz" + }, + { + "key": "BwPgwCG9gEDVTmHxB8hqDX7rfCv4sw==", + "proof": [], + "value": "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" + }, + { + "key": "BwPidktZ1Z81M6wwyDnRjKKpuXoPKA==", + "proof": [], + "value": "YIBgQFI0gBVhABBXYACA/VtQYAQ2EGEBFldgADVg4ByAY3YuOmMRYQCiV4Bj2nQiKBFhAHFXgGPadCIoFGECQ1eAY+eM6pIUYQJWV4Bj8v3jixRhAmlXgGP1Z9yGFGECfFeAY/jIdl4UYQKPV2AAgP1bgGN2LjpjFGEB+1eAY32gqHcUYQIOV4BjjaXLWxRhAh9XgGPI9cLYFGECMFdgAID9W4BjSG/wzRFhAOlXgGNIb/DNFGEBhleAY1crbAUUYQGbV4BjY6787BRhAc1XgGNkJWZrFGEB4FeAY3FQGKYUYQHzV2AAgP1bgGMO37qlFGEBG1eAYyr4lvsUYQEwV4BjLYjQzxRhAWBXgGM93P+2FGEBc1dbYACA/VthAS5hASk2YARhTb9WW2EColZbAFtgalRhAUOQYAFgAWCgGwMWgVZbYEBRYAFgAWCgGwOQkRaBUmAgAVtgQFGAkQOQ81thAS5hAW42YARhTkRWW2ELFFZbYQEuYQGBNmAEYU6NVlthGM1WW2EBjmEZtlZbYEBRYQFXkZBhT05WW2EBvWEBqTZgBGFPgVZbYGVUYAFgAWCgGwORghaRFhSQVltgQFGQFRWBUmAgAWEBV1ZbYQEuYQHbNmAEYU+wVlthGkRWW2BpVGEBQ5BgAWABYKAbAxaBVlthAS5hIbBWW2EBLmECCTZgBGFP71ZbYSIFVltgZVRgAWABYKAbAxZhAUNWW2AzVGABYAFgoBsDFmEBQ1ZbYQEuYQI+NmAEYVBkVlthJ79WW2EBLmECUTZgBGFPgVZbYTICVltga1RhAUOQYAFgAWCgGwMWgVZbYQEuYQJ3NmAEYU+BVlthMldWW2EBLmECijZgBGFQxlZbYTMOVlthAS5hAp02YARhUSlWW2FGgVZbYABgaIFhArdggIgBYGCJAWFPgVZbYAFgAWCgGwOQgRaCUmAgggGSkJJSYEABYAAgVBaQUGEC5IFggIcBNWFHwFZbYAFgAWCgGwOBFmMJXqezYQMDYICIAWBgiQFhT4FWW4dggAE1YEBRg2P/////FmDgG4FSYAQBYQMlkpGQYVGFVltgIGBAUYCDA4FgAIda8RWAFWEDRFc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhA2iRkGFRnlZbUGBAUWNwoIIxYOAbgVIwYASCAVJgAJBgAWABYKAbA4MWkGNwoIIxkGAkAWAgYEBRgIMDgYZa+hWAFWEDsFc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhA9SRkGFRwFZbkFBgAGED6GCAiAFgYIkBYU+BVltgAWABYKAbAxZjzCsn12CAiQE1YQQLYMCLAWCgjAFhUdlWW2BAUWABYAFg4BsDGWDghZAbFoFSYASBAZKQklJgDwtgJIIBUmBEAWAgYEBRgIMDgYZa+hWAFWEET1c9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhBHORkGFRwFZbkFCAh2DAATURFWEE+FdhBKZhBJVhAQCJAWDgigFhT4FWW2ABYAFgoBsDhRaQhGFIfFZbYACAUWAgYVS1gzmBUZFSYQTFYICJAWBgigFhT4FWW4RhBNdhAQCLAWDgjAFhT4FWW4VgQFFhBOiUk5KRkGFR/FZbYEBRgJEDkKFQUFBhCw5WW2EFCGCAiAFgYIkBYU+BVltgAWABYKAbAxZjGk0B0mCAiQE1YQUrYMCLAWCgjAFhUdlWW2BAUWABYAFg4BsDGWDghZAbFoFSYASBAZKQklJgDwtgJIIBUmAAYESCAVJgZAFgAGBAUYCDA4FgAIeAOxWAFWEFc1dgAID9W1Ba8RWAFWEFh1c9YACAPj1gAP1bUFBQUFBQUGAAYQXchWCgAWAggQGQYQWmkZBhUdlWW2APC2BnYABhBb1ggIoBYGCLAWFPgVZbYAFgAWCgGwMWgVJgIIEBkZCRUmBAAWAAIJBhSNdWW2BAUWNwoIIxYOAbgVIwYASCAVJgAWABYKAbA5GQkRaQY3CggjGQYCQBYCBgQFGAgwOBhlr6FYAVYQYiVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEGRpGQYVHAVluQUGAAYQZXYCCHAYdhT4FWW2ABYAFgoBsDFmPMKyfXg2EGdmBAigFgIIsBYVHZVltgQFFgAWABYOAbAxlg4IWQGxaBUmAEgQGSkJJSYA8LYCSCAVJgRAFgIGBAUYCDA4GGWvoVgBVhBrpXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYQbekZBhUcBWW5BQgIZgQAE1ERVhB6xXYQc4YQcAYQEAiAFg4IkBYU+BVluDYQcoYQcUYECLAWAgjAFhUdlWW2APC2BnYABhBb1gII4BjmFPgVZbYAFgAWCgGwMWkZBhSHxWW2AAgFFgIGFUtYM5gVGRUmEHVGAgiAGIYU+BVlthB3thB2dgQIoBYCCLAWFR2VZbYA8LYGdgAGEFvWAgjQGNYU+BVlthB4xhAQCKAWDgiwFhT4FWW4VgQFFhB52Uk5KRkGFR/FZbYEBRgJEDkKFQUGELDlZbYQfTYQe/YECIAWAgiQFhUdlWW2APC2BnYABhBb1gIIsBi2FPgVZbYAFgAWCgGwMWYwlep7NhB+5gIIkBiWFPgVZbhGBAUYNj/////xZg4BuBUmAEAWEIDJKRkGFRhVZbYCBgQFGAgwOBYACHWvEVgBVhCCtXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYQhPkZBhUZ5WW1BhCF1gIIcBh2FPgVZbYAFgAWCgGwMWYxpNAdKDYQh8YECKAWAgiwFhUdlWW2BAUWABYAFg4BsDGWDghZAbFoFSYASBAZKQklJgDwtgJIIBUmAAYESCAVJgZAFgAGBAUYCDA4FgAIeAOxWAFWEIxFdgAID9W1Ba8RWAFWEI2Fc9YACAPj1gAP1bUFBQUGAAYQkIh2AgAWAggQGQYQj0kZBhUdlWW2APC2BnYABhBb1gIIwBjGFPgVZbYEBRY3CggjFg4BuBUjBgBIIBUmABYAFgoBsDkZCRFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhCU5XPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYQlykZBhUcBWW5BQgxVhCuJXYQmNYQj0YECJAWAgigFhUdlWW2BqVGBAUWMJXqezYOAbgVJgAWABYKAbA5KDFpJjCV6ns5JhCcCSkRaQhZBgBAFhUYVWW2AgYEBRgIMDgWAAh1rxFYAVYQnfVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEKA5GQYVGeVltQYECAUWBggQGCUmABYAFgoBsDgIkWglKHgRZgIICEAZGQkVKChAGIkFJgalSSk5KQkRaRY0UcdjWRYQpkkWEKUJGQjQGQjQFhUdlWW2APC2BnYABhBb1gII8Bj2FPgVZbhDBhCndhAQCOAWDgjwFhT4FWW4ZgQFGGY/////8WYOAbgVJgBAFhCpiVlJOSkZBhUiZWW2AgYEBRgIMDgWAAh1rxFYAVYQq3Vz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEK25GQYVHAVltQUGELClZbYQsKYQr2YQEAiQFg4IoBYU+BVluCYQcoYQpQYECMAWAgjQFhUdlWW1BQUFtQUFBQVltgAFtgBYEQFWEMTldgAIKCYAWBEGELNFdhCzRhUnNWW2AgAgE1ERVhDDxXYQuDg4JgBYEQYQtUV2ELVGFSc1ZbYCACAWAggQGQYQtnkZBhT4FWW4ODYAWBEGELeVdhC3lhUnNWW2AgAgE1YUfAVluCgWAFgRBhC5VXYQuVYVJzVltgIAIBYCCBAZBhC6iRkGFPgVZbYAFgAWCgGwMWYwlep7NhC8NgIIcBh2FPgVZbhIRgBYEQYQvVV2EL1WFSc1ZbYCACATVgQFGDY/////8WYOAbgVJgBAFhC/eSkZBhUYVWW2AgYEBRgIMDgWAAh1rxFYAVYQwWVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEMOpGQYVGeVltQW4BhDEaBYVKJVluRUFBhCxdWW1BgAGEMXmAghQGFYU+BVltgAWABYKAbAxZjft6JxYNgAWBAUYNj/////xZg4BuBUmAEAWEMjJKRkGFSslZbYCBgQFGAgwOBhlr6FYAVYQypVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEMzZGQYVHAVluQUICEYGABNREVYQ3zV2AAW2AFgRAVYQ3sV2AAg4JgBYEQYQz7V2EM+2FSc1ZbYCACATURFWEN2ldhDVdhDRthAUCHAWEBIIgBYU+BVluEg2AFgRBhDS1XYQ0tYVJzVltgIAIBNYaEYAWBEGENRFdhDURhUnNWW2AgAgFgIIEBkGEHKJGQYU+BVltgAIBRYCBhVLWDOYFRkVJhDXNgIIcBh2FPgVZbhYNgBYEQYQ2FV2ENhWFSc1ZbYCACAWAggQGQYQ2YkZBhT4FWW2ENqmEBQIkBYQEgigFhT4FWW4aFYAWBEGENvFdhDbxhUnNWW2AgAgE1YEBRYQ3RlJOSkZBhUfxWW2BAUYCRA5ChW4BhDeSBYVKJVluRUFBhDN5WW1BQUFBQVlthDgBgIIUBhWFPgVZbYAFgAWCgGwMWY4RzhJmDYABgQFGDY/////8WYOAbgVJgBAFhDi6SkZBhUspWW2AAYEBRgIMDgWAAh4A7FYAVYQ5IV2AAgP1bUFrxFYAVYQ5cVz1gAIA+PWAA/VtQYQ5zk1BQYMCGAZFQUGCghQFhUdlWW2APC2EOhmCghQFggIYBYVHZVltgDwsUYRNFV2AAYGiBYQ6gYCCHAYdhT4FWW2ABYAFgoBsDkIEWglJgIICDAZOQk1JgQJGCAWAAIFQWklCCkWMJXqezkWEO2ZGQiAGQiAFhT4FWW2BAUWNwoIIxYOAbgVIwYASCAVJgAWABYKAbA4UWkGNwoIIxkGAkAWAgYEBRgIMDgYZa+hWAFWEPHVc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhD0GRkGFRwFZbYEBRg2P/////FmDgG4FSYAQBYQ9ekpGQYVGFVltgIGBAUYCDA4FgAIda8RWAFWEPfVc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhD6GRkGFRnlZbUGBAUWNwoIIxYOAbgVIwYASCAVJgAJBgAWABYKAbA4MWkGNwoIIxkGAkAWAgYEBRgIMDgYZa+hWAFWEP6Vc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhEA2RkGFRwFZbkFBgAGEQIWBAhwFgIIgBYU+BVltgAWABYKAbAxZjXg1EP2EQP2CgiQFggIoBYVHZVlthEE9gwIoBYKCLAWFR2VZbYEBRYAFgAWDgGwMZYOCFkBsWgVJgD5KDC2AEggFSkQtgJIIBUmBEgQGFkFJgZAFgIGBAUYCDA4GGWvoVgBVhEJtXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYRC/kZBhUcBWW5BQgIZgwAE1ERVhEptXYRGgYRDiYQFAiAFhASCJAWFPgVZbYREMYRD1YKCKAWCAiwFhUdlWW2APC2BnYABhBb1gQI0BYCCOAWFPgVZbYEBRY3CggjFg4BuBUjBgBIIBUmABYAFgoBsDkZCRFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhEVJXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYRF2kZBhUcBWW2EHKGERiWCgiwFggIwBYVHZVltgDwtgZ2AAYQW9YECOAWAgjwFhT4FWW2AAgFFgIGFUtYM5gVGRUmERv2BAiAFgIIkBYU+BVlthEdJhEPVgoIoBYICLAWFR2VZbYRHkYQFAigFhASCLAWFPgVZbYRIRYRH3YKCMAWCAjQFhUdlWW2APC2BnYACNYCABYCCBAZBhBb2RkGFPgVZbYEBRY3CggjFg4BuBUjBgBIIBUmABYAFgoBsDkZCRFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhEldXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYRJ7kZBhUcBWW2BAUWESi5STkpGQYVH8VltgQFGAkQOQoVBQUFBQUFZbYRKrYECHAWAgiAFhT4FWW2ABYAFgoBsDFmM98CEkYRLJYKCJAWCAigFhUdlWW2ES2WDAigFgoIsBYVHZVltgQFFgAWABYOAbAxlg4IWQGxaBUmAPkoMLYASCAVKRC2AkggFSYESBAYWQUmBkgQGEkFJghAFgAGBAUYCDA4FgAIeAOxWAFWETKVdgAID9W1Ba8RWAFWETPVc9YACAPj1gAP1bUFBQUFBQUFtgAGBogWETWmBghwFgQIgBYU+BVltgAWABYKAbA5CBFoJSYCCCAZKQklJgQJCBAWAAIFSQkRaRUIGQYwlep7OQYROVkGBgiAGQiAFhT4FWW2BAUWNwoIIxYOAbgVIwYASCAVJgAWABYKAbA4UWkGNwoIIxkGAkAWAgYEBRgIMDgYZa+hWAFWET2Vc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhE/2RkGFRwFZbYEBRg2P/////FmDgG4FSYAQBYRQakpGQYVGFVltgIGBAUYCDA4FgAIda8RWAFWEUOVc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhFF2RkGFRnlZbUGBAUWNwoIIxYOAbgVIwYASCAVJgAJBgAWABYKAbA4MWkGNwoIIxkGAkAWAgYEBRgIMDgYZa+hWAFWEUpVc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhFMmRkGFRwFZbkFBgAGEU3WBghwFgQIgBYU+BVltgAWABYKAbAxZjzCsn14NhFP1hAQCKAWDgiwFhUdlWW2BAUWABYAFg4BsDGWDghZAbFoFSYASBAZKQklJgDwtgJIIBUmBEAWAgYEBRgIMDgYZa+hWAFWEVQVc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhFWWRkGFRwFZbkFCAhmEBAAE1ERVhFcxXYRWJYQSVYQFAiAFhASCJAWFPgVZbYACAUWAgYVS1gzmBUZFSYRWoYGCIAWBAiQFhT4FWW4RhFbthAUCKAWEBIIsBYU+BVluFYEBRYRKLlJOSkZBhUfxWW2EV3GBghwFgQIgBYU+BVltgAWABYKAbAxZjGk0B0oNhFfxhAQCKAWDgiwFhUdlWW2BAUWABYAFg4BsDGWDghZAbFoFSYASBAZKQklJgDwtgJIIBUmAAYESCAVJgZAFgAGBAUYCDA4FgAIeAOxWAFWEWRFdgAID9W1Ba8RWAFWEWWFc9YACAPj1gAP1bUFBQUFBQUGAAYRaOhGDgAWAggQGQYRZ3kZBhUdlWW2APC2BnYABhBb1gYIkBYECKAWFPgVZbYEBRY3CggjFg4BuBUjBgBIIBUmABYAFgoBsDkZCRFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhFtRXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYRb4kZBhUcBWW5BQYQGghAE1FWEYo1dhFxlhFndhAQCGAWDghwFhUdlWW2BqVGBAUWMJXqezYOAbgVJgAWABYKAbA5KDFpJjCV6ns5JhF0ySkRaQhZBgBAFhUYVWW2AgYEBRgIMDgWAAh1rxFYAVYRdrVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEXj5GQYVGeVltQYABgQFGAYGABYEBSgIZhAWABYCCBAZBhF7GRkGFPgVZbYAFgAWCgGwMWgVJgIAFhF9FhAaCIAWEBgIkBYU+BVltgAWABYKAbA5CBFoJSYQGgiAE1YCCQkgGRkJFSYGpUkZJQFmNFHHY1YRgkYRgNYQEAiQFg4IoBYVHZVltgDwtgZ2AAYQW9YGCMAWBAjQFhT4FWW4QwYRg4YQFAiwFhASCMAWFPgVZbhmBAUYZj/////xZg4BuBUmAEAWEYWZWUk5KRkGFSJlZbYCBgQFGAgwOBYACHWvEVgBVhGHhXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYRickZBhUcBWW1BQYQsOVlthCw5hGLhhAUCGAWEBIIcBYU+BVluCYQcoYRgNYQEAiQFg4IoBYVHZVlthGNVhSOxWW2ABYAFgoBsDFmEY8GAzVGABYAFgoBsDFpBWW2ABYAFgoBsDFhRhGR9XYEBRYkYbzWDlG4FSYAQBYRkWkGFS4lZbYEBRgJEDkP1bYABbgYEQFWEZhVdhGXKDg4OBgRBhGT9XYRk/YVJzVluQUGAgAgFgIIEBkGEZVJGQYU+BVltgAWABYKAbA4cWYACQgVJgZ2AgUmBAkCCQYUkgVltQgGEZfYFhUolWW5FQUGEZIlZbUFBQYAFgAWCgGwORghZgAJCBUmBoYCBSYECQIIBUYAFgAWCgGwMZFpGQkhYXkFVWW2BmgFRhGcOQYVMXVluAYB8BYCCAkQQCYCABYEBRkIEBYEBSgJKRkIGBUmAgAYKAVGEZ75BhUxdWW4AVYRo8V4BgHxBhGhFXYQEAgINUBAKDUpFgIAGRYRo8VluCAZGQYABSYCBgACCQW4FUgVKQYAEBkGAgAYCDEWEaH1eCkANgHxaCAZFbUFBQUFCBVltgAFtgBYEQFWEbT1dgAIKCYAWBEGEaZFdhGmRhUnNWW2AgAgE1ERVhGz1XYRqEg4JgBYEQYQtUV2ELVGFSc1ZbgoFgBYEQYRqWV2EalmFSc1ZbYCACAWAggQGQYRqpkZBhT4FWW2ABYAFgoBsDFmMJXqezYRrEYCCHAYdhT4FWW4SEYAWBEGEa1ldhGtZhUnNWW2AgAgE1YEBRg2P/////FmDgG4FSYAQBYRr4kpGQYVGFVltgIGBAUYCDA4FgAIda8RWAFWEbF1c9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhGzuRkGFRnlZbUFuAYRtHgWFSiVZbkVBQYRpHVltQYABhG19gIIUBhWFPgVZbYAFgAWCgGwMWY37eicWDYAFgQFGDY/////8WYOAbgVJgBAFhG42SkZBhUrJWW2AgYEBRgIMDgYZa+hWAFWEbqlc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhG86RkGFRwFZbkFCAhGAgATURFWEcrVdgAFtgBYEQFWEN7FdgAIOCYAWBEGEb/FdhG/xhUnNWW2AgAgE1ERVhHJtXYRwaYQ0bYMCHAWCgiAFhT4FWW2AAgFFgIGFUtYM5gVGRUmEcNmAghwGHYU+BVluFg2AFgRBhHEhXYRxIYVJzVltgIAIBYCCBAZBhHFuRkGFPgVZbYRxrYMCJAWCgigFhT4FWW4aFYAWBEGEcfVdhHH1hUnNWW2AgAgE1YEBRYRySlJOSkZBhUfxWW2BAUYCRA5ChW4BhHKWBYVKJVluRUFBhG99WW2EcumAghQGFYU+BVltgAWABYKAbAxZjhHOEmYNgAGBAUYNj/////xZg4BuBUmAEAWEc6JKRkGFSylZbYABgQFGAgwOBYACHgDsVgBVhHQJXYACA/VtQWvEVgBVhHRZXPWAAgD49YAD9W1BgaJJQYACRUGEdLpBQYCCHAYdhT4FWW2ABYAFgoBsDkIEWglJgIIIBkpCSUmBAAWAAIFQWYwlep7NhHWBggIcBYGCIAWFPgVZbYGhgAGEdcWAgigGKYU+BVltgAWABYKAbA5CBFoJSYCCCAZKQklJgQJCBAWAAIFSQUWNwoIIxYOAbgVIwYASCAVKRFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhHcpXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYR3ukZBhUcBWW2BAUYNj/////xZg4BuBUmAEAWEeC5KRkGFRhVZbYCBgQFGAgwOBYACHWvEVgBVhHipXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYR5OkZBhUZ5WW1BhHldhTNVWW2BoYABhHmhgIIgBiGFPgVZbYAFgAWCgGwOQgRaCUmAgggGSkJJSYECQgQFgACBUkFFjcKCCMWDgG4FSMGAEggFSkRaQY3CggjGQYCQBYCBgQFGAgwOBhlr6FYAVYR7BVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEe5ZGQYVHAVluBhmBAATVgA4EQYR77V2Ee+2FSc1ZbYCACAVJgAGEfEmCAhwFgYIgBYU+BVltgAWABYKAbAxZjOIPhGYNgAWBAUYNj/////xZg4BuBUmAEAWEfQJKRkGFTb1ZbYCBgQFGAgwOBhlr6FYAVYR9dVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEfgZGQYVHAVluQUICGYIABNREVYSCAV2Ef9WEfomDAiAFgoIkBYU+BVluDiGBAATVgA4EQYR+4V2EfuGFSc1ZbYCACAVFgaGAAYR/RYICMAWBgjQFhT4FWW2ABYAFgoBsDkIEWglJgIIIBkpCSUmBAAWAAIFQWkZBhSHxWW2AAgFFgIGFUtYM5gVGRUmEgFGCAiAFgYIkBYU+BVltgaGAAYSAoYICLAWBgjAFhT4FWW2ABYAFgoBsDkIEWglJgIIIBkpCSUmBAAWAAIFQWYSBVYMCKAWCgiwFhT4FWW4WKYEABNWADgRBhIGtXYSBrYVJzVltgIAIBUWBAUWESi5STkpGQYVH8VlthIJBggIcBYGCIAWFPgVZbYAFgAWCgGwMWY0UVzvODYABgQFGDY/////8WYOAbgVJgBAFhIL6SkZBhU4xWW2AAYEBRgIMDgWAAh4A7FYAVYSDYV2AAgP1bUFrxFYAVYSDsVz1gAIA+PWAA/VtQUFBQYABgaGAAiGBgAWAggQGQYSEJkZBhT4FWW2ABYAFgoBsDkIEWglJgIIIBkpCSUmBAkIEBYAAgVJBRY3CggjFg4BuBUjBgBIIBUpEWkGNwoIIxkGAkAWAgYEBRgIMDgYZa+hWAFWEhYlc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhIYaRkGFRwFZbkFBhCwphIZtgwIkBYKCKAWFPgVZbgmBoYABhH9FggI0BYGCOAWFPgVZbYSG4YUjsVltgAWABYKAbAxZhIdNgM1RgAWABYKAbAxaQVltgAWABYKAbAxYUYSH5V2BAUWJGG81g5RuBUmAEAWEZFpBhUuJWW2EiA2AAYUk1VltWW2EiDWFI7FZbYGtUYAFgAWCgGwOQgRaRFhRhIidXYACA/VthIi9hTPNWW2AAW2AFgRAVYSSWV2BqVGABYAFgoBsDFmO8pzgjhoNgBYEQYSJeV2EiXmFSc1ZbYCACAWAggQGQYSJxkZBhT4FWW2BAUWDgg5AbYAFgAWDgGwMZFoFSYAFgAWCgGwOQkRZgBIIBUmAkAWAgYEBRgIMDgYZa+hWAFWEitVc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhItmRkGFTp1ZbgoJgBYEQYSLrV2Ei62FSc1ZbYAFgAWCgGwOQkhZgIJKQkgIBUmAAhIJgBYEQYSMSV2EjEmFSc1ZbYCACATURFWEkhFdgalRgAWABYKAbAxZj0yqZHoSDYAWBEGEjQFdhI0BhUnNWW2AgAgE1h4RgBYEQYSNXV2EjV2FSc1ZbYCACAWAggQGQYSNqkZBhT4FWW4eFYAWBEGEjfFdhI3xhUnNWW2AgAgE1MGBAUYVj/////xZg4BuBUmAEAWEjoZSTkpGQYVPEVltgAGBAUYCDA4FgAIeAOxWAFWEju1dgAID9W1Ba8RWAFWEjz1c9YACAPj1gAP1bUFBQUIGBYAWBEGEj5VdhI+VhUnNWW2AgAgFRYAFgAWCgGwMWYwlep7OIYAABYCCBAZBhJAuRkGFPgVZbhoRgBYEQYSQdV2EkHWFSc1ZbYCACATVgQFGDY/////8WYOAbgVJgBAFhJD+SkZBhUYVWW2AgYEBRgIMDgWAAh1rxFYAVYSReVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEkgpGQYVGeVltQW4BhJI6BYVKJVluRUFBhIjJWW1BgAGEkpmAgiAGIYU+BVltgAWABYKAbAxZjft6JxYVgAWBAUYNj/////xZg4BuBUmAEAWEk1JKRkGFSslZbYCBgQFGAgwOBhlr6FYAVYSTxVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGElFZGQYVHAVluQUICHYEABNREVYSaeV2AAW2AFgRAVYSaWV2AAhYJgBYEQYSVDV2ElQ2FSc1ZbYCACATURFWEmhFdgalRgAWABYKAbAxZjlQASW4WDYAWBEGElcVdhJXFhUnNWW2AgAgE1iWAAAWAggQGQYSWJkZBhT4FWW2ElmWBAjAFgII0BYU+BVltgQIwBNWElrmCAjgFgYI8BYVPrVluNYIABNY5goAE1YEBRiGP/////FmDgG4FSYAQBYSXal5aVlJOSkZBhVA5WW2AAYEBRgIMDgWAAh4A7FYAVYSX0V2AAgP1bUFrxFYAVYSYIVz1gAIA+PWAA/VtQYACAUWAgYVS1gzmBUZFSklBhJiqRUFBgIIoBimFPgVZbhINgBYEQYSY8V2EmPGFSc1ZbYCACAVGKYCABYCCBAZBhJlSRkGFPgVZbiIVgBYEQYSZmV2EmZmFSc1ZbYCACATVgQFFhJnuUk5KRkGFR/FZbYEBRgJEDkKFbgGEmjoFhUolWW5FQUGElJlZbUFBQYQ3sVlthJqtgIIgBiGFPgVZbYAFgAWCgGwMWY4RzhJmFYABgQFGDY/////8WYOAbgVJgBAFhJtmSkZBhUspWW2AAYEBRgIMDgWAAh4A7FYAVYSbzV2AAgP1bUFrxFYAVYScHVz1gAIA+PWAA/VtQYQsKklBhJyCRUFBgQIkBYCCKAWFPgVZbYGhgAGEnMWAgjAGMYU+BVltgAWABYKAbA5CBFoJSYCCCAZKQklJgQJCBAWAAIFSQUWNwoIIxYOAbgVIwYASCAVKRFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhJ4pXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYSeukZBhUcBWW2BoYABhH9FgII0BjWFPgVZbYSfHYUjsVltga1RgAWABYKAbA5CBFpEWFGEn4VdgAID9W2En6WFM81ZbYABbYAWBEBVhKlBXYGpUYAFgAWCgGwMWY7ynOCOGg2AFgRBhKBhXYSgYYVJzVltgIAIBYCCBAZBhKCuRkGFPgVZbYEBRYOCDkBtgAWABYOAbAxkWgVJgAWABYKAbA5CRFmAEggFSYCQBYCBgQFGAgwOBhlr6FYAVYShvVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEok5GQYVOnVluCgmAFgRBhKKVXYSilYVJzVltgAWABYKAbA5CSFmAgkpCSAgFSYACEgmAFgRBhKMxXYSjMYVJzVltgIAIBNREVYSo+V2BqVGABYAFgoBsDFmPTKpkehINgBYEQYSj6V2Eo+mFSc1ZbYCACATWHhGAFgRBhKRFXYSkRYVJzVltgIAIBYCCBAZBhKSSRkGFPgVZbh4VgBYEQYSk2V2EpNmFSc1ZbYCACATUwYEBRhWP/////FmDgG4FSYAQBYSlblJOSkZBhU8RWW2AAYEBRgIMDgWAAh4A7FYAVYSl1V2AAgP1bUFrxFYAVYSmJVz1gAIA+PWAA/VtQUFBQgYFgBYEQYSmfV2Epn2FSc1ZbYCACAVFgAWABYKAbAxZjCV6ns4hgAAFgIIEBkGEpxZGQYU+BVluGhGAFgRBhKddXYSnXYVJzVltgIAIBNWBAUYNj/////xZg4BuBUmAEAWEp+ZKRkGFRhVZbYCBgQFGAgwOBYACHWvEVgBVhKhhXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYSo8kZBhUZ5WW1BbgGEqSIFhUolWW5FQUGEn7FZbUGAAYSpgYCCIAYhhT4FWW2ABYAFgoBsDFmN+3onFhWABYEBRg2P/////FmDgG4FSYAQBYSqOkpGQYVKyVltgIGBAUYCDA4GGWvoVgBVhKqtXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYSrPkZBhUcBWW5BQgIdgIAE1ERVhLE1XYABbYAWBEBVhJpZXYACFgmAFgRBhKv1XYSr9YVJzVltgIAIBNREVYSw7V2BqVGABYAFgoBsDFmOVABJbhYNgBYEQYSsrV2ErK2FSc1ZbYCACATWJYAABYCCBAZBhK0ORkGFPgVZbYStTYECMAWAgjQFhT4FWW2BAjAE1YStoYICOAWBgjwFhU+tWW41ggAE1jmCgATVgQFGIY/////8WYOAbgVJgBAFhK5SXlpWUk5KRkGFUDlZbYABgQFGAgwOBYACHgDsVgBVhK65XYACA/VtQWvEVgBVhK8JXPWAAgD49YAD9W1BgAIBRYCBhVLWDOYFRkVKSUGEr5JFQUGAgigGKYU+BVluEg2AFgRBhK/ZXYSv2YVJzVltgIAIBUWEsC2DAjAFgoI0BYU+BVluIhWAFgRBhLB1XYSwdYVJzVltgIAIBNWBAUWEsMpSTkpGQYVH8VltgQFGAkQOQoVuAYSxFgWFSiVZbkVBQYSrgVlthLFpgIIgBiGFPgVZbYAFgAWCgGwMWY4RzhJmFYABgQFGDY/////8WYOAbgVJgBAFhLIiSkZBhUspWW2AAYEBRgIMDgWAAh4A7FYAVYSyiV2AAgP1bUFrxFYAVYSy2Vz1gAIA+PWAA/VtQYGiUUGAAk1BhLNCSUFBQYCCIAYhhT4FWW2ABYAFgoBsDkIEWglJgIIIBkpCSUmBAAWAAIFQWYwlep7NhLQJggIgBYGCJAWFPgVZbYGhgAGEtE2AgiwGLYU+BVltgAWABYKAbA5CBFoJSYCCCAZKQklJgQJCBAWAAIFSQUWNwoIIxYOAbgVIwYASCAVKRFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhLWxXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYS2QkZBhUcBWW2BAUYNj/////xZg4BuBUmAEAWEtrZKRkGFRhVZbYCBgQFGAgwOBYACHWvEVgBVhLcxXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYS3wkZBhUZ5WW1BhLflhTNVWW2BoYABhLgpgIIkBiWFPgVZbYAFgAWCgGwOQgRaCUmAgggGSkJJSYECQgQFgACBUkFFjcKCCMWDgG4FSMGAEggFSkRaQY3CggjGQYCQBYCBgQFGAgwOBhlr6FYAVYS5jVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEuh5GQYVHAVluBh2BAATVgA4EQYS6dV2EunWFSc1ZbYCACAVJgAGEutGCAiAFgYIkBYU+BVltgAWABYKAbAxZjOIPhGYNgAWBAUYNj/////xZg4BuBUmAEAWEu4pKRkGFTb1ZbYCBgQFGAgwOBhlr6FYAVYS7/Vz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEvI5GQYVHAVluQUICHYIABNREVYTDIV2AAW2AFgRAVYTAtV2AAhYJgBYEQYS9RV2EvUWFSc1ZbYCACATURFWEwG1dgalRgAWABYKAbAxZjlQASW4WDYAWBEGEvf1dhL39hUnNWW2AgAgE1iWAAAWAggQGQYS+XkZBhT4FWW2Evp2BAjAFgII0BYU+BVltgQIwBNWEvvGCAjgFgYI8BYVPrVluNYIABNY5goAE1YEBRiGP/////FmDgG4FSYAQBYS/ol5aVlJOSkZBhVA5WW2AAYEBRgIMDgWAAh4A7FYAVYTACV2AAgP1bUFrxFYAVYTAWVz1gAIA+PWAA/VtQUFBQW4BhMCWBYVKJVluRUFBhLzRWW1BgAIBRYCBhVLWDOYFRkVJhME1ggIkBYGCKAWFPgVZbYGhgAGEwYWCAjAFgYI0BYU+BVltgAWABYKAbA5CBFoJSYCCCAZKQklJgQAFgACBUFmEwjmDAiwFgoIwBYU+BVluFi2BAATVgA4EQYTCkV2EwpGFSc1ZbYCACAVFgQFFhMLmUk5KRkGFR/FZbYEBRgJEDkKFQUGEN7FZbYTDYYICIAWBgiQFhT4FWW2ABYAFgoBsDFmNFFc7zg2AAYEBRg2P/////FmDgG4FSYAQBYTEGkpGQYVOMVltgAGBAUYCDA4FgAIeAOxWAFWExIFdgAID9W1Ba8RWAFWExNFc9YACAPj1gAP1bUFBQUGAAYGhgAIlgYAFgIIEBkGExUZGQYU+BVltgAWABYKAbA5CBFoJSYCCCAZKQklJgQJCBAWAAIFSQUWNwoIIxYOAbgVIwYASCAVKRFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhMapXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYTHOkZBhUcBWW5BQYTH4YTHjYMCKAWCgiwFhT4FWW4JgaGAAYR/RYICOAWBgjwFhT4FWW1BQUFBQUFBQVlthMgphSOxWW2ABYAFgoBsDFmEyJWAzVGABYAFgoBsDFpBWW2ABYAFgoBsDFhRhMktXYEBRYkYbzWDlG4FSYAQBYRkWkGFS4lZbYTJUgWFJh1ZbUFZbYTJfYUjsVltgAWABYKAbAxZhMnpgM1RgAWABYKAbAxaQVltgAWABYKAbAxYUYTKgV2BAUWJGG81g5RuBUmAEAWEZFpBhUuJWW2ABYAFgoBsDgRZhMwVXYEBRYkYbzWDlG4FSYCBgBIIBUmAmYCSCAVJ/T3duYWJsZTogbmV3IG93bmVyIGlzIHRoZSB6ZXJvIGFgRIIBUmVkZHJlc3Ng0BtgZIIBUmCEAWEZFlZbYTJUgWFJNVZbYTMWYUjsVltga1RgAWABYKAbA5CBFpEWFGEzMFdgAID9W2EzOGFM81ZbYABbYAWBEBVhNZ9XYGpUYAFgAWCgGwMWY7ynOCOGg2AFgRBhM2dXYTNnYVJzVltgIAIBYCCBAZBhM3qRkGFPgVZbYEBRYOCDkBtgAWABYOAbAxkWgVJgAWABYKAbA5CRFmAEggFSYCQBYCBgQFGAgwOBhlr6FYAVYTO+Vz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGEz4pGQYVOnVluCgmAFgRBhM/RXYTP0YVJzVltgAWABYKAbA5CSFmAgkpCSAgFSYACEgmAFgRBhNBtXYTQbYVJzVltgIAIBNREVYTWNV2BqVGABYAFgoBsDFmPTKpkehINgBYEQYTRJV2E0SWFSc1ZbYCACATWHhGAFgRBhNGBXYTRgYVJzVltgIAIBYCCBAZBhNHORkGFPgVZbh4VgBYEQYTSFV2E0hWFSc1ZbYCACATUwYEBRhWP/////FmDgG4FSYAQBYTSqlJOSkZBhU8RWW2AAYEBRgIMDgWAAh4A7FYAVYTTEV2AAgP1bUFrxFYAVYTTYVz1gAIA+PWAA/VtQUFBQgYFgBYEQYTTuV2E07mFSc1ZbYCACAVFgAWABYKAbAxZjCV6ns4hgAAFgIIEBkGE1FJGQYU+BVluGhGAFgRBhNSZXYTUmYVJzVltgIAIBNWBAUYNj/////xZg4BuBUmAEAWE1SJKRkGFRhVZbYCBgQFGAgwOBYACHWvEVgBVhNWdXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYTWLkZBhUZ5WW1BbgGE1l4FhUolWW5FQUGEzO1ZbUGAAYTWvYCCIAYhhT4FWW2ABYAFgoBsDFmN+3onFhWABYEBRg2P/////FmDgG4FSYAQBYTXdkpGQYVKyVltgIGBAUYCDA4GGWvoVgBVhNfpXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYTYekZBhUcBWW5BQgIdgYAE1ERVhN55XYABbYAWBEBVhJpZXYACFgmAFgRBhNkxXYTZMYVJzVltgIAIBNREVYTeMV2BqVGABYAFgoBsDFmOVABJbhYNgBYEQYTZ6V2E2emFSc1ZbYCACATWJYAABYCCBAZBhNpKRkGFPgVZbYTaiYECMAWAgjQFhT4FWW2BAjAE1YTa3YICOAWBgjwFhU+tWW41ggAE1jmCgATVgQFGIY/////8WYOAbgVJgBAFhNuOXlpWUk5KRkGFUDlZbYABgQFGAgwOBYACHgDsVgBVhNv1XYACA/VtQWvEVgBVhNxFXPWAAgD49YAD9W1BgAIBRYCBhVLWDOYFRkVKSUGE3M5FQUGAgigGKYU+BVluEg2AFgRBhN0VXYTdFYVJzVltgIAIBUWE3XGEBQIwBYQEgjQFhT4FWW4iFYAWBEGE3bldhN25hUnNWW2AgAgE1YEBRYTeDlJOSkZBhUfxWW2BAUYCRA5ChW4BhN5aBYVKJVluRUFBhNi9WW2E3q2AgiAGIYU+BVltgAWABYKAbAxZjhHOEmYVgAGBAUYNj/////xZg4BuBUmAEAWE32ZKRkGFSylZbYABgQFGAgwOBYACHgDsVgBVhN/NXYACA/VtQWvEVgBVhOAdXPWAAgD49YAD9W1BQUFBQUIRgoAFgIIEBkGE4IJGQYVHZVltgDwthODNgoIcBYICIAWFR2VZbYA8LFGE+E1dgAGBogWE4TWAgiQGJYU+BVltgAWABYKAbA5CBFoJSYCCAgwGTkJNSYECRggFgACBUFpJQgpFjCV6ns5FhOIaRkIoBkIoBYU+BVltgQFFjcKCCMWDgG4FSMGAEggFSYAFgAWCgGwOFFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhOMpXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYTjukZBhUcBWW2BAUYNj/////xZg4BuBUmAEAWE5C5KRkGFRhVZbYCBgQFGAgwOBYACHWvEVgBVhOSpXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYTlOkZBhUZ5WW1BgQFFjcKCCMWDgG4FSMGAEggFSYACQYAFgAWCgGwODFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhOZZXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYTm6kZBhUcBWW5BQYTnMYECIAWAgiQFhT4FWW2ABYAFgoBsDFmNeDUQ/YTnqYKCKAWCAiwFhUdlWW2E5+mDAiwFgoIwBYVHZVltgQFFgAWABYOAbAxlg4IWQGxaBUmAPkoMLYASCAVKRC2AkggFSYESBAYSQUmBkAWAgYEBRgIMDgYZa+pJQUFCAFWE6YldQYECAUWAfPZCBAWAfGRaCAZCSUmE6X5GBAZBhUcBWW2ABW2E7YldgAFtgBYEQFWEmlldgAIWCYAWBEGE6hldhOoZhUnNWW2AgAgE1ERVhO1BXYGpUYAFgAWCgGwMWY5UAEluFg2AFgRBhOrRXYTq0YVJzVltgIAIBNYlgAAFgIIEBkGE6zJGQYU+BVlthOtxgQIwBYCCNAWFPgVZbYECMATVhOvFggI4BYGCPAWFT61ZbjWCAATWOYKABNWBAUYhj/////xZg4BuBUmAEAWE7HZeWlZSTkpGQYVQOVltgAGBAUYCDA4FgAIeAOxWAFWE7N1dgAID9W1Ba8RWAFWE7S1c9YACAPj1gAP1bUFBQUFuAYTtagWFSiVZbkVBQYTppVluAiGDAATURFWE9aVdgAFtgBYEQFWE8bVdgAIaCYAWBEGE7jldhO45hUnNWW2AgAgE1ERVhPFtXYGpUYAFgAWCgGwMWY5UAEluGg2AFgRBhO7xXYTu8YVJzVltgIAIBNYpgAAFgIIEBkGE71JGQYU+BVlthO+RgQI0BYCCOAWFPgVZbjGBAATWNYGABYCCBAZBhO/yRkGFT61ZbjmCAATWPYKABNWBAUYhj/////xZg4BuBUmAEAWE8KJeWlZSTkpGQYVQOVltgAGBAUYCDA4FgAIeAOxWAFWE8QldgAID9W1Ba8RWAFWE8Vlc9YACAPj1gAP1bUFBQUFuAYTxlgWFSiVZbkVBQYTtxVltQYACAUWAgYVS1gzmBUZFSYTyNYECKAWAgiwFhT4FWW2E8oGER92CgjAFggI0BYVHZVlthPLJhAUCMAWEBII0BYU+BVlthPN9hPMVgoI4BYICPAWFR2VZbYA8LYGdgAI9gIAFgIIEBkGEFvZGQYU+BVltgQFFjcKCCMWDgG4FSMGAEggFSYAFgAWCgGwORkJEWkGNwoIIxkGAkAWAgYEBRgIMDgYZa+hWAFWE9JVc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhPUmRkGFRwFZbYEBRYT1ZlJOSkZBhUfxWW2BAUYCRA5ChUFBQYQ3sVlthPXlgQIkBYCCKAWFPgVZbYAFgAWCgGwMWYz3wISRhPZdgoIsBYICMAWFR2VZbYT2nYMCMAWCgjQFhUdlWW2BAUWABYAFg4BsDGWDghZAbFoFSYA+SgwtgBIIBUpELYCSCAVJgRIEBhZBSYGSBAYSQUmCEAWAAYEBRgIMDgWAAh4A7FYAVYT33V2AAgP1bUFrxFYAVYT4LVz1gAIA+PWAA/VtQUFBQUFBQW2AAYGiBYT4oYGCJAWBAigFhT4FWW2ABYAFgoBsDkIEWglJgIIIBkpCSUmBAkIEBYAAgVJCRFpFQgZBjCV6ns5BhPmOQYGCKAZCKAWFPgVZbYEBRY3CggjFg4BuBUjBgBIIBUmABYAFgoBsDhRaQY3CggjGQYCQBYCBgQFGAgwOBhlr6FYAVYT6nVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGE+y5GQYVHAVltgQFGDY/////8WYOAbgVJgBAFhPuiSkZBhUYVWW2AgYEBRgIMDgWAAh1rxFYAVYT8HVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGE/K5GQYVGeVltQYEBRY3CggjFg4BuBUjBgBIIBUmAAkGABYAFgoBsDgxaQY3CggjGQYCQBYCBgQFGAgwOBhlr6FYAVYT9zVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGE/l5GQYVHAVluQUGE/qWBgiAFgQIkBYU+BVltgAWABYKAbAxZjzCsn14JhP8lhAQCLAWDgjAFhUdlWW2BAUWABYAFg4BsDGWDghZAbFoFSYASBAZKQklJgDwtgJIIBUmBEAWAgYEBRgIMDgYZa+pJQUFCAFWFAKVdQYECAUWAfPZCBAWAfGRaCAZCSUmFAJpGBAZBhUcBWW2ABW2FBL1dgAFtgBYEQFWFBKVdgAIWCYAWBEGFATVdhQE1hUnNWW2AgAgE1ERVhQRdXYGpUYAFgAWCgGwMWY5UAEluFg2AFgRBhQHtXYUB7YVJzVltgIAIBNYlgAAFgIIEBkGFAk5GQYU+BVlthQKNgQIwBYCCNAWFPgVZbYECMATVhQLhggI4BYGCPAWFT61ZbjWCAATWOYKABNWBAUYhj/////xZg4BuBUmAEAWFA5JeWlZSTkpGQYVQOVltgAGBAUYCDA4FgAIeAOxWAFWFA/ldgAID9W1Ba8RWAFWFBElc9YACAPj1gAP1bUFBQUFuAYUEhgWFSiVZbkVBQYUAwVltQYUKBVluAiGEBAAE1ERVhQn9XYABbYAWBEBVhQjtXYACGgmAFgRBhQVxXYUFcYVJzVltgIAIBNREVYUIpV2BqVGABYAFgoBsDFmOVABJbhoNgBYEQYUGKV2FBimFSc1ZbYCACATWKYAABYCCBAZBhQaKRkGFPgVZbYUGyYECNAWAgjgFhT4FWW4xgQAE1jWBgAWAggQGQYUHKkZBhU+tWW45ggAE1j2CgATVgQFGIY/////8WYOAbgVJgBAFhQfaXlpWUk5KRkGFUDlZbYABgQFGAgwOBYACHgDsVgBVhQhBXYACA/VtQWvEVgBVhQiRXPWAAgD49YAD9W1BQUFBbgGFCM4FhUolWW5FQUGFBP1ZbUGAAgFFgIGFUtYM5gVGRUmFCW2BgigFgQIsBYU+BVluEYUJuYQFAjAFhASCNAWFPgVZbhWBAUWE9WZSTkpGQYVH8VltQW2FCkWBgiAFgQIkBYU+BVltgAWABYKAbAxZjGk0B0oJhQrFhAQCLAWDgjAFhUdlWW2BAUWABYAFg4BsDGWDghZAbFoFSYASBAZKQklJgDwtgJIIBUmAAYESCAVJgZAFgAGBAUYCDA4FgAIeAOxWAFWFC+VdgAID9W1Ba8ZJQUFCAFWFDCldQYAFbYUQQV2AAW2AFgRAVYUQKV2AAhYJgBYEQYUMuV2FDLmFSc1ZbYCACATURFWFD+FdgalRgAWABYKAbAxZjlQASW4WDYAWBEGFDXFdhQ1xhUnNWW2AgAgE1iWAAAWAggQGQYUN0kZBhT4FWW2FDhGBAjAFgII0BYU+BVltgQIwBNWFDmWCAjgFgYI8BYVPrVluNYIABNY5goAE1YEBRiGP/////FmDgG4FSYAQBYUPFl5aVlJOSkZBhVA5WW2AAYEBRgIMDgWAAh4A7FYAVYUPfV2AAgP1bUFrxFYAVYUPzVz1gAIA+PWAA/VtQUFBQW4BhRAKBYVKJVluRUFBhQxFWW1BhCwpWW2AAYUQ9YUQmYQEAigFg4IsBYVHZVltgDwtgZ2AAYQW9YGCNAWBAjgFhT4FWW2BAUWNwoIIxYOAbgVIwYASCAVJgAWABYKAbA5GQkRaQY3CggjGQYCQBYCBgQFGAgwOBhlr6FYAVYUSDVz1gAIA+PWAA/VtQUFBQYEBRPWAfGWAfggEWggGAYEBSUIEBkGFEp5GQYVHAVluQUGEBoIgBNRVhRldXYUTIYUQmYQEAigFg4IsBYVHZVltgalRgQFFjCV6ns2DgG4FSYAFgAWCgGwOSgxaSYwlep7OSYUT7kpEWkIWQYAQBYVGFVltgIGBAUYCDA4FgAIda8RWAFWFFGlc9YACAPj1gAP1bUFBQUGBAUT1gHxlgH4IBFoIBgGBAUlCBAZBhRT6RkGFRnlZbUGAAYEBRgGBgAWBAUoCKYQFgAWAggQGQYUVgkZBhT4FWW2ABYAFgoBsDFoFSYCABYUWAYQGgjAFhAYCNAWFPgVZbYAFgAWCgGwOQgRaCUmEBoIwBNWAgkJIBkZCRUmBqVJGSUBZjRRx2NWFF1mFFvGEBAI0BYOCOAWFR2VZbYA8LYGdgAI5gQAFgIIEBkGEFvZGQYU+BVluEMI1hASABYCCBAZBhReyRkGFPgVZbhmBAUYZj/////xZg4BuBUmAEAWFGDZWUk5KRkGFSJlZbYCBgQFGAgwOBYACHWvEVgBVhRixXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYUZQkZBhUcBWW1BQYTH4VlthMfhhRmxhAUCKAWEBIIsBYU+BVluCYQcoYUW8YQEAjQFg4I4BYVHZVltgAFRhAQCQBGD/FmFGnFdgAFRg/xYVYUagVlswOxVbYUcDV2BAUWJGG81g5RuBUmAgYASCAVJgLmAkggFSf0luaXRpYWxpemFibGU6IGNvbnRyYWN0IGlzIGFscmVhYESCAVJtGR5IGluaXRpYWxpemVlgkhtgZIIBUmCEAWEZFlZbYABUYQEAkARg/xYVgBVhRyVXYACAVGH//xkWYQEBF5BVW2FHLWFJqVZbYUc1YUnQVlthRz6FYUmHVltgaYBUYAFgAWCgGwOAhxZgAWABYKAbAxmSgxYXkJJVYGqAVIaEFpCDFheQVWBrgFSShRaSkJEWkZCRF5BVYECAUYCCAZCRUmAFgIJSZDIuMi4zYNgbYCCQkgGRglJhR6eRYGaRYU0RVltQgBVhDexXYACAVGH/ABkWkFVQUFBQUFZbYEBRY3CggjFg4BuBUjBgBIIBUoGQYAFgAWCgGwOEFpBjcKCCMZBgJAFgIGBAUYCDA4GGWvoVgBVhSAZXPWAAgD49YAD9W1BQUFBgQFE9YB8ZYB+CARaCAYBgQFJQgQGQYUgqkZBhUcBWWxAVYUh4V2BAUWJGG81g5RuBUmAgYASCAYGQUmAkggFSf0N1cnZlUHJveHk6IGluc3VmZmljaWVudCBiYWxhbmNlYESCAVJgZAFhGRZWW1BQVlthSNKDY6kFnLtg4BuEhGBAUWAkAWFIm5KRkGFRhVZbYECAUWAfGYGEAwGBUpGQUmAggQGAUWABYAFg4BsDFmABYAFg4BsDGZCTFpKQkheQkVJhSgdWW1BQUFZbYABhSOODg2FK2VZbkFBbkpFQUFZbYABgFDYQgBWQYUkJV1BgZVRgAWABYKAbAxYzFFsVYUkbV1BgExk2ATVgYByQVltQM5BWW2AAYUjjg2ABYAFgoBsDhBZhSwNWW2AzgFRgAWABYKAbA4OBFmABYAFgoBsDGYMWgReQk1VgQFGRFpGQgpB/i+AHnFMWWRQTRM0f0KTyhBlJf5cio9qv47QYb2tkV+CQYACQo1BQVltgZYBUYAFgAWCgGwMZFmABYAFgoBsDkpCSFpGQkReQVVZbYABUYQEAkARg/xZhIgNXYEBRYkYbzWDlG4FSYAQBYRkWkGFUTVZbYABUYQEAkARg/xZhSfdXYEBRYkYbzWDlG4FSYAQBYRkWkGFUTVZbYSIDYUoCYUjsVlthSTVWW2AAYUpcgmBAUYBgQAFgQFKAYCCBUmAgAX9TYWZlRVJDMjA6IGxvdy1sZXZlbCBjYWxsIGZhaWxlZIFSUIVgAWABYKAbAxZhS1KQkpGQY/////8WVluAUZCRUBVhSNJXgIBgIAGQUYEBkGFKepGQYVGeVlthSNJXYEBRYkYbzWDlG4FSYCBgBIIBUmAqYCSCAVJ/U2FmZUVSQzIwOiBFUkMyMCBvcGVyYXRpb24gZGlkIG5gRIIBUmkb3Qgc3VjY2VlZYLIbYGSCAVJghAFhGRZWW2AAgmAAAYKBVIEQYUrwV2FK8GFSc1ZbkGAAUmAgYAAgAVSQUJKRUFBWW2AAgYFSYAGDAWAgUmBAgSBUYUtKV1CBVGABgYEBhFVgAISBUmAggIIgkJMBhJBVhFSEglKChgGQk1JgQJAgkZCRVWFI5lZbUGAAYUjmVltgYGFLYYSEYACFYUtrVluQUFuTklBQUFZbYGCCRxAVYUvMV2BAUWJGG81g5RuBUmAgYASCAVJgJmAkggFSf0FkZHJlc3M6IGluc3VmZmljaWVudCBiYWxhbmNlIGZvYESCAVJlHIgY2FsbYNIbYGSCAVJghAFhGRZWW2ABYAFgoBsDhRY7YUwjV2BAUWJGG81g5RuBUmAgYASCAVJgHWAkggFSf0FkZHJlc3M6IGNhbGwgdG8gbm9uLWNvbnRyYWN0AAAAYESCAVJgZAFhGRZWW2AAgIZgAWABYKAbAxaFh2BAUWFMP5GQYVSYVltgAGBAUYCDA4GFh1rxklBQUD2AYACBFGFMfFdgQFGRUGAfGWA/PQEWggFgQFI9glI9YABgIIQBPmFMgVZbYGCRUFtQkVCRUGFMkYKChmFMnFZbl5ZQUFBQUFBQVltgYIMVYUyrV1CBYUtkVluCURVhTLtXglGAhGAgAf1bgWBAUWJGG81g5RuBUmAEAWEZFpGQYU9OVltgQFGAYGABYEBSgGADkGAgggKANoM3UJGSkVBQVltgQFGAYKABYEBSgGAFkGAgggKANoM3UJGSkVBQVluCgFRhTR2QYVMXVluQYABSYCBgACCQYB8BYCCQBIEBkoJhTT9XYACFVWFNhVZbgmAfEGFNWFeAUWD/GRaDgAEXhVVhTYVWW4KAAWABAYVVghVhTYVXkYIBW4KBERVhTYVXglGCVZFgIAGRkGABAZBhTWpWW1BhTZGSkVBhTZVWW1CQVltbgIIRFWFNkVdgAIFVYAEBYU2WVltgAWABYKAbA4EWgRRhMlRXYACA/VtgAIBgAICEhgNhAWCBEhVhTddXYACA/VthAQCAghIVYU3nV2AAgP1bhpVQhQE1kFBhTfiBYU2qVluSUGEBIIUBNWFOCYFhTapWW5OWkpVQkpNhAUABNZJQUFZbYABhAcCChAMSFWFOLVdgAID9W1CRkFBWW4BgoIEBgxAVYUjmV2AAgP1bYACAYABhAwCEhgMSFWFOWldgAID9W2FOZIWFYU4aVluSUGFOdIVhAcCGAWFOM1ZbkVBhToSFYQJghgFhTjNWW5BQklCSUJJWW2AAgGAAgGBghYcDEhVhTqNXYACA/VuENWFOroFhTapWW5NQYCCFATVhTr6BYU2qVluSUGBAhQE1Z///////////gIIRFWFO21dgAID9W4GHAZFQh2AfgwESYU7vV2AAgP1bgTWBgREVYU7+V2AAgP1biGAggmAFG4UBAREVYU8TV2AAgP1blZiUl1BQYCABlFBQUFZbYABbg4EQFWFPPVeBgQFRg4IBUmAgAWFPJVZbg4ERFWELDldQUGAAkQFSVltgIIFSYACCUYBgIIQBUmFPbYFgQIUBYCCHAWFPIlZbYB8BYB8ZFpGQkQFgQAGSkVBQVltgAGAggoQDEhVhT5NXYACA/VuBNWFLZIFhTapWW2AAYMCChAMSFWFOLVdgAID9W2AAgGAAYQIAhIYDEhVhT8ZXYACA/VthT9CFhWFPnlZbklBhT9+FYMCGAWFOM1ZbkVBhToSFYQFghgFhTjNWW2AAgGAAgGAAhYcDYQNAgRIVYVAJV2AAgP1bYKCBEhVhUBdXYACA/VtQhZRQYVAoh2CgiAFhT55WW5NQYVA4h2EBYIgBYU4zVluSUGFQSIdhAgCIAWFOM1ZbkVBhUFiHYQKgiAFhTjNWW5BQkpVQkpWQk1BWW2AAgGAAgGAAYQNghogDEhVhUH1XYACA/VthUIeHh2FPnlZblFBhUJaHYMCIAWFPnlZbk1BhUKaHYQGAiAFhTjNWW5JQYVC2h2ECIIgBYU4zVluRUGFQWIdhAsCIAWFOM1ZbYACAYACAYABhBGCGiAMSFWFQ31dgAID9W2FQ6YeHYU4aVluUUGFQ+YdhAcCIAWFPnlZbk1BhUQmHYQKAiAFhTjNWW5JQYVEZh2EDIIgBYU4zVluRUGFQWIdhA8CIAWFOM1ZbYACAYACAYICFhwMSFWFRP1dgAID9W4Q1YVFKgWFNqlZbk1BgIIUBNWFRWoFhTapWW5JQYECFATVhUWqBYU2qVluRUGBghQE1YVF6gWFNqlZbk5aSlVCQk1BQVltgAWABYKAbA5KQkhaCUmAgggFSYEABkFZbYABgIIKEAxIVYVGwV2AAgP1bgVGAFRWBFGFLZFdgAID9W2AAYCCChAMSFWFR0ldgAID9W1BRkZBQVltgAGAggoQDEhVhUetXYACA/VuBNYBgDwuBFGFLZFdgAID9W2ABYAFgoBsDlIUWgVKShBZgIIQBUpIWYECCAVJgYIEBkZCRUmCAAZBWW2ABYAFgoBsDlYYWgVJgIICCAZWQlVKShRZgQICFAZGQkVKRhRZgYIQBUoBRhRZggIQBUpKDAVGQkxZgoIIBUpEBUWDAggFSYOABkFZbY05Ie3Fg4BtgAFJgMmAEUmAkYAD9W2AAYAAZghQVYVKrV2NOSHtxYOAbYABSYBFgBFJgJGAA/VtQYAEBkFZbYMCBAWCghIM3kRUVYKCRkJEBUpGQUFZbYMCBAWCghIM3YKCRkJEBkZCRUpGQUFZbYCCAglKBgQFSf093bmFibGU6IGNhbGxlciBpcyBub3QgdGhlIG93bmVyYECCAVJgYAGQVltgAYGBHJCCFoBhUytXYH+CFpFQW2AgghCBFBVhTi1XY05Ie3Fg4BtgAFJgImAEUmAkYAD9W4BgAFtgA4EQFWELDleBUYRSYCCThAGTkJEBkGABAWFTUFZbYICBAWFTfYKFYVNMVluCFRVgYIMBUpOSUFBQVltggIEBYVOagoVhU0xWW4JgYIMBUpOSUFBQVltgAGAggoQDEhVhU7lXYACA/VuBUWFLZIFhTapWW5OEUmABYAFgoBsDkoMWYCCFAVJgQIQBkZCRUhZgYIIBUmCAAZBWW2AAYCCChAMSFWFT/VdgAID9W4E1YP+BFoEUYUtkV2AAgP1blodSYAFgAWCgGwOVhhZgIIgBUpOQlBZgQIYBUmBghQGRkJFSYP8WYICEAVJgoIMBkZCRUmDAggFSYOABkFZbYCCAglJgK5CCAVJ/SW5pdGlhbGl6YWJsZTogY29udHJhY3QgaXMgbm90IGlgQIIBUmpuaXRpYWxpemluZ2CoG2BgggFSYIABkFZbYACCUWFUqoGEYCCHAWFPIlZbkZCRAZKRUFBW/i5evLwQ4SPiXGxwuDJD6xNzVkxxH8CIyU1R7SkSRCQHomRpcGZzWCISIHT6kHD8p5FSYoQeYeRZLA75OXV1khFtsGyhAyk1ACuiZHNvbGNDAAgKADM=" + }, + { + "key": "BwPjC5Q5M8SiTrTfBVJR+ZKm3g1q0Q==", + "proof": [], + "value": "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" + }, + { + "key": "BwPpXZ7l7J29EQeNilR0tEJ54pIvhQ==", + "proof": [], + "value": "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" + }, + { + "key": "BwP7UPpdjx8B02RTHBJm7g7nu4MC+g==", + "proof": [], + "value": "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" + }, + { + "key": "BwQIohKKF0n0FEsN/ObdMF573LHv8QEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAg8/JgDEKYI2IXH/77M52IKFea6M=" + }, + { + "key": "BwQIohKKF0n0FEsN/ObdMF573LHv8QEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwQIohKKF0n0FEsN/ObdMF573LHv8QEAAADUN2BQv249cqoTpvPSJCGsDfdXsb+5X9PKsrPVBeyfzA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABl", + "proof": [], + "value": "AAAAAAAAAAAAAAAAQLAyRIBKP+7bMt33r2kMtJwASTU=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABq", + "proof": [], + "value": "AAAAAAAAAAAAAAAAg8/JgDEKYI2IXH/77M52IKFea6M=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABr", + "proof": [], + "value": "AAAAAAAAAAAAAAAA4MAhvYBA1U5h8QfIag1+63wr+LM=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCwwIExcxFxImRXAFwcXN2wPokb9D27wNk+NPWPHOSNPph", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCwzYIlKE7oaMhBmfIKEktuY3KPiB2zDc1qSCjylBdOCu8", + "proof": [], + "value": "AAAAAAAAAAAAAAAA4nZLWdWfNTOsMMg50Yyiqbl6Dyg=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCw3Nku8xGDuHysoClQimR6KFgDp0gAHt2pS06vUaxytGa", + "proof": [], + "value": "AAAAAAAAAAAAAAAA6V2e5eydvREHjYpUdLRCeeKSL4U=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCw7UxJ2hKVosxc64TufimAW4kPmO26O4ReNanF4ULXWED", + "proof": [], + "value": "AAAAAAAAAAAAAAAAuJ5vWld9BOQXyhnyF+lJLat/aDM=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCw8cvFIdnGwUfbLLWbVN2Ap5ZfpjR8JQjlyGb84/wLa26", + "proof": [], + "value": "AAAAAAAAAAAAAAAA+1D6XY8fAdNkUxwSZu4O57uDAvo=" + }, + { + "key": "BwQS4RoP3Sh2Lur7zng1ukN6GSVCw+agx/iyZBRZKr7/QBGkodNPU3M36jIW9zJZ0pf6dmAa", + "proof": [], + "value": "AAAAAAAAAAAAAAAA4wuUOTPEok603wVSUfmSpt4NatE=" + }, + { + "key": "BwR1lEzuYMKXasxmD3VzaJCh3xpiQgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9CQA=" + }, + { + "key": "BwR1lEzuYMKXasxmD3VzaJCh3xpiQgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASoF8gA=" + }, + { + "key": "BwR1lEzuYMKXasxmD3VzaJCh3xpiQgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ=" + }, + { + "key": "BwR1lEzuYMKXasxmD3VzaJCh3xpiQgEAAAApDezZVItiqNYDRamIOG/IS6a8lUhACPY2L5MWDvPlYw==", + "proof": [], + "value": "AAAAAAAAAAAAAAAA+1D6XY8fAdNkUxwSZu4O57uDAvo=" + }, + { + "key": "BwR1lEzuYMKXasxmD3VzaJCh3xpiQgEAAAApDezZVItiqNYDRamIOG/IS6a8lUhACPY2L5MWDvPlZA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAA6V2e5eydvREHjYpUdLRCeeKSL4U=" + }, + { + "key": "BwR1lEzuYMKXasxmD3VzaJCh3xpiQgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM9g==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAABnZceT+hAHnQAAAA=" + }, + { + "key": "BwR1lEzuYMKXasxmD3VzaJCh3xpiQgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM9w==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAABnZceT+hAHnQAAAA=" + }, + { + "key": "BwR1lEzuYMKXasxmD3VzaJCh3xpiQgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM+A==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAABnZceT+hAHnQAAAA=" + }, + { + "key": "BwSDz8mAMQpgjYhcf/vsznYgoV5rowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABl", + "proof": [], + "value": "AAAAAAAAAAAAAAAAQLAyRIBKP+7bMt33r2kMtJwASTU=" + }, + { + "key": "BwSDz8mAMQpgjYhcf/vsznYgoV5rowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABs", + "proof": [], + "value": "AAAAAAAAAAAAAAAA4MAhvYBA1U5h8QfIag1+63wr+LM=" + }, + { + "key": "BwSDz8mAMQpgjYhcf/vsznYgoV5rowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt", + "proof": [], + "value": "AAAAAAAAAAAAAAAAEuEaD90odi7q+854NbpDehklQsM=" + }, + { + "key": "BwSDz8mAMQpgjYhcf/vsznYgoV5rowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABw", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5FQVM=" + }, + { + "key": "BwSDz8mAMQpgjYhcf/vsznYgoV5roy1VdSihy4ZrDZZZB7+JET6t8fGHzRcQvSYESYzKjk5f", + "proof": [], + "value": "AAAAAAAAAAAAAAAACKISihdJ9BRLDfzm3TBee9yx7/E=" + }, + { + "key": "BwSDz8mAMQpgjYhcf/vsznYgoV5rozYIlKE7oaMhBmfIKEktuY3KPiB2zDc1qSCjylBdOCu8", + "proof": [], + "value": "AAAAAAAAAAAAAAAAM8Hw/S2Iwp/3vfqcGaR115y5k8s=" + }, + { + "key": "BwSDz8mAMQpgjYhcf/vsznYgoV5ro2CPqmMTWkB/iImDZZvbDahShMDMz/Tsx+Mrwtrm29b1", + "proof": [], + "value": "AAAAAAAAAAAAAAAAEO5GL/Urijzfv0OhdssDCmTq+BM=" + }, + { + "key": "BwSDz8mAMQpgjYhcf/vsznYgoV5ro7UxJ2hKVosxc64TufimAW4kPmO26O4ReNanF4ULXWED", + "proof": [], + "value": "AAAAAAAAAAAAAAAAuJ5vWld9BOQXyhnyF+lJLat/aDM=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9CQA=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAA+1D6XY8fAdNkUxwSZu4O57uDAvo=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAAApDezZVItiqNYDRamIOG/IS6a8lUhACPY2L5MWDvPlYw==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAHWcBDYCdkO1KbCIBlbcWTU28JBE=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAAApDezZVItiqNYDRamIOG/IS6a8lUhACPY2L5MWDvPlZA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAACKISihdJ9BRLDfzm3TBee9yx7/E=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAAApDezZVItiqNYDRamIOG/IS6a8lUhACPY2L5MWDvPlZQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAU4gYlZ+9++dhhLYxVOgfyV35Tq0=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAAApDezZVItiqNYDRamIOG/IS6a8lUhACPY2L5MWDvPlZg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAASGbV3m+t2WBXbKuyz1bK31X1O2c=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAAApDezZVItiqNYDRamIOG/IS6a8lUhACPY2L5MWDvPlZw==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAsZLASMuU5Da1+ukmuuMYiA084FY=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM9g==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM9w==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM+A==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM+Q==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwSzIZ1VKG1hyqRjpvnnTkHugTxvHgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM+g==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9CQA=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAA6V2e5eydvREHjYpUdLRCeeKSL4U=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAAApDezZVItiqNYDRamIOG/IS6a8lUhACPY2L5MWDvPlZg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAA4wuUOTPEok603wVSUfmSpt4NatE=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM9g==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM9w==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM+A==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM+Q==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwS7YyZJhdwHBWt9Alu8TULUn8bBpgEAAACxDi1SdhIHOybuzf1xfmoyDPRLSvrCsHMtn8vit/oM+g==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwTO0wGqlC9yDUadiBuPrx1IdGybfQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAA4MAhvYBA1U5h8QfIag1+63wr+LM=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4swAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABn", + "proof": [], + "value": "AAAAAAAAAAAAAAAAQLAyRIBKP+7bMt33r2kMtJwASTU=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4swAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABp", + "proof": [], + "value": "L+WXwU1n4CJ3E0hNjQcgYSMf2T1Ei6PwyN+IuWYVMlk=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4swAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABq", + "proof": [], + "value": "FWR6a/DmuGoMeyVYCosw9OqcHDfvVWBCH/tIsoKf6RU=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4swAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABr", + "proof": [], + "value": "ArgrzwJfBEPxWFKCXOXonQ2Lmi06Z3RDeFMH8mfPZYc=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4swAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABs", + "proof": [], + "value": "LbVNu545W4N1Z7vY5rhNfScNVvglvifLVyo6h19+P+o=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4swAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt", + "proof": [], + "value": "AAAAAAAAAAAAAAIHZ4bXpdfxiYIgUDqjVSclCyddu+k=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4swAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABu", + "proof": [], + "value": "AAAAAAAAAAAAAAAAztMBqpQvcg1GnYgbj68dSHRsm30=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4szYIlKE7oaMhBmfIKEktuY3KPiB2zDc1qSCjylBdOCu8", + "proof": [], + "value": "AAAAAAAAAAAAAAAAwjBTFYiLThFRUmVby+j6bQ41YMQ=" + }, + { + "key": "BwTgwCG9gEDVTmHxB8hqDX7rfCv4s7UxJ2hKVosxc64TufimAW4kPmO26O4ReNanF4ULXWED", + "proof": [], + "value": "AAAAAAAAAAAAAAAAuJ5vWld9BOQXyhnyF+lJLat/aDM=" + }, + { + "key": "BwTjC5Q5M8SiTrTfBVJR+ZKm3g1q0QEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAg8/JgDEKYI2IXH/77M52IKFea6M=" + }, + { + "key": "BwTjC5Q5M8SiTrTfBVJR+ZKm3g1q0QEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwTjC5Q5M8SiTrTfBVJR+ZKm3g1q0QEAAABg+JTDvuE2veAf0Har2kGUrHIMG/r9udIX3bp6OX0Hwg==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA=" + }, + { + "key": "BwTpXZ7l7J29EQeNilR0tEJ54pIvhQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAABnZceT+hAHnQAAAA=" + }, + { + "key": "BwTpXZ7l7J29EQeNilR0tEJ54pIvhQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAu2MmSYXcBwVrfQJbvE1C1J/GwaY=" + }, + { + "key": "BwTpXZ7l7J29EQeNilR0tEJ54pIvhQEAAADd1Logm8B4KM/Vfs4y1bZWm2xeMHXVNiTzfsYjNwg3RQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAABnZceT+hAHnQAAAA=" + }, + { + "key": "BwT7UPpdjx8B02RTHBJm7g7nu4MC+gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACA==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAABnZceT+hAHnQAAAA=" + }, + { + "key": "BwT7UPpdjx8B02RTHBJm7g7nu4MC+gEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAsyGdVShtYcqkY6b5505B7oE8bx4=" + }, + { + "key": "BwT7UPpdjx8B02RTHBJm7g7nu4MC+gEAAADd1Logm8B4KM/Vfs4y1bZWm2xeMHXVNiTzfsYjNwg3RQ==", + "proof": [], + "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAABnZceT+hAHnQAAAA=" + }, + { + "key": "BwcIohKKF0n0FEsN/ObdMF573LHv8Q==", + "proof": [], + "value": "AAAAAQ==" + }, + { + "key": "Bwd1lEzuYMKXasxmD3VzaJCh3xpiQg==", + "proof": [], + "value": "AAAAAQ==" + }, + { + "key": "BwezIZ1VKG1hyqRjpvnnTkHugTxvHg==", + "proof": [], + "value": "AAAAAQ==" + }, + { + "key": "Bwe7YyZJhdwHBWt9Alu8TULUn8bBpg==", + "proof": [], + "value": "AAAAAQ==" + }, + { + "key": "BwfO0wGqlC9yDUadiBuPrx1IdGybfQ==", + "proof": [], + "value": "AAAAAQ==" + }, + { + "key": "BwfjC5Q5M8SiTrTfBVJR+ZKm3g1q0Q==", + "proof": [], + "value": "AAAAAQ==" + }, + { + "key": "BwfpXZ7l7J29EQeNilR0tEJ54pIvhQ==", + "proof": [], + "value": "AAAAAQ==" + }, + { + "key": "Bwf7UPpdjx8B02RTHBJm7g7nu4MC+g==", + "proof": [], + "value": "AAAAAQ==" + } + ] + } +} \ No newline at end of file diff --git a/engine-tests/src/tests/res/input_Emufid2.hex b/engine-tests/src/tests/res/input_Emufid2.hex new file mode 100644 index 000000000..a2f09fbfb --- /dev/null +++ b/engine-tests/src/tests/res/input_Emufid2.hex @@ -0,0 +1 @@ +f907ae81bb830aae60835b8d8094e0c021bd8040d54e61f107c86a0d7eeb7c2bf8b380b90744135160af00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000005e0000000000000000000000000000000000000000000000000000000000000078000000000000000402e391e5b58a27c54190a834915d896908893a2364141565a0d1a47f18551eec63a024d831c7b45fb5fefff986e448a829f60d54f44f0911acbc089bf801883d515d5683057303e4b8713c03df07578f76d3a07558f61c957148e2a7beae02c80000000000ac918d000000000000001a000000000000000000000000000000000000000000000000000000000000000000000000000004c6fdc304c417506cc9158d1020cf40bf69a313125e581f2f4c164213dccd5a67db1966ed7d3c869e0ac46a8a56120d29087a5eba713dfc2f00000000000000000000000012e11a0fdd28762eeafbce7835ba437a192542c3fd6404f567dc86000000000000000000000000b3219d55286d61caa463a6f9e74e41ee813c6f1e00000000000000000000000075944cee60c2976acc660f75736890a1df1a6242000000000000000000000000bb63264985dc07056b7d025bbc4d42d49fc6c1a60000000000000000000000000000000000000000000000001b9b127fa4651078000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000001b983ed4909b967a00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000001b96d5240cfbca7a0000000000000000000000003353b1b76a969e834403ebdc8c6191fef7290fea0000000000000000000000004f51a71522f7dc1499a2cc0aebc9cdd6730ed6910000000000000000000000004f51a71522f7dc1499a2cc0aebc9cdd6730ed691000000000000000000000000e5586fc3ce557134b0cbc2e66bf62c45358853e0000000000000000000000000000000000000000000000000000000000000a8690000000000000000000000000b05b4cf9a69d0be1f93f32b88e14d5fcf793ea70000000000000000000000007d3c869e0ac46a8a56120d29087a5eba713dfc2f0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000037576628d531c2dd89b99a3f575178d9f4724d3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc16d674ec800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000562443fb8af52225a96690c6fa94c636bba479cc529228edc88b5522516b4a620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005341454e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008022c82aa719953a0038617373b7da4c0286d4a0ffea798d7c952198195288dc3011b5e79f800762abb4d45832987ee6df02032b7a7808bdb7193cfb7f96871fd01aed7ade72a214db88a8a58e2c7d92ee19778a95385f3e904ca7be44fa83b2900c8627e3ebec315728983f4b47b90cf98142dd38bc4307ed84196db3e6ec061700000000000000000000000000000000000000000000000000000000000000400c5b142e835cbc45fe5a92911c22b2a0dbfaa3b60c4808db0275dd9cb95a02b117728ade96a41f42f14a98e405383c65527f8f9668f1833f5d00985dc0257fc4849c8a82c9a0ba4d6481f50e109922c33bddc68a3f16997833e0b54ab5c72392066e7e0f0a39a03d042184e20e9c261d761158efc84c7676dc570f31d44a119ac1029c84970712 diff --git a/engine-tests/src/tests/sanity.rs b/engine-tests/src/tests/sanity.rs index 944b78704..eae9b9a00 100644 --- a/engine-tests/src/tests/sanity.rs +++ b/engine-tests/src/tests/sanity.rs @@ -289,16 +289,14 @@ fn test_is_contract() { }; // Should return false for accounts that don't exist - assert_eq!( - call_contract(Address::from_array([1; 20]), &mut runner, &mut signer), - false, - ); + assert!(!call_contract( + Address::from_array([1; 20]), + &mut runner, + &mut signer + )); // Should return false for accounts that don't have contract code - assert_eq!( - call_contract(signer_address, &mut runner, &mut signer), - false, - ); + assert!(!call_contract(signer_address, &mut runner, &mut signer),); // Should return true for contracts let erc20_constructor = test_utils::erc20::ERC20Constructor::load(); @@ -308,10 +306,7 @@ fn test_is_contract() { |c| c.deploy("TOKEN_A", "TA", nonce.into()), erc20_constructor, ); - assert_eq!( - call_contract(token_a.address, &mut runner, &mut signer), - true, - ); + assert!(call_contract(token_a.address, &mut runner, &mut signer),); } #[test] @@ -423,6 +418,41 @@ fn test_revert_during_contract_deploy() { assert_eq!(revert_message.as_str(), "Revert message"); } +#[test] +fn test_call_too_deep_error() { + let (mut runner, mut signer, _) = initialize_transfer(); + + let constructor = test_utils::solidity::ContractConstructor::compile_from_source( + "src/tests/res", + "target/solidity_build", + "CallTooDeep.sol", + "CallTooDeep", + ); + + let nonce = signer.use_nonce(); + let contract = runner.deploy_contract( + &signer.secret_key, + |c| c.deploy_without_constructor(nonce.into()), + constructor, + ); + + let result = runner + .submit_with_signer(&mut signer, |nonce| { + contract.call_method_without_args("test", nonce) + }) + .unwrap(); + + // It is counter-intuitive that this returns a `Revert` instead of `CallTooDeep`. + // The reason this is the case is because it is only the last call that triggers the + // `CallTooDeep` exit status, while the one before only sees that the call it made failed + // and therefore reverts. As a result, the `CallTooDeep` exit status is not actually + // visible to users. + match result.status { + TransactionStatus::Revert(_) => (), + other => panic!("Unexpected status {:?}", other), + } +} + #[test] fn test_timestamp() { let (mut runner, mut signer, _) = initialize_transfer(); @@ -995,7 +1025,7 @@ fn query_address_sim( ) -> U256 { let x = aurora.call(method, address.as_bytes()); match &x.outcome().status { - near_sdk_sim::transaction::ExecutionStatus::SuccessValue(b) => U256::from_big_endian(&b), + near_sdk_sim::transaction::ExecutionStatus::SuccessValue(b) => U256::from_big_endian(b), other => panic!("Unexpected outcome: {:?}", other), } } diff --git a/engine-tests/src/tests/standalone/json_snapshot.rs b/engine-tests/src/tests/standalone/json_snapshot.rs index dcc67ff2d..764ddef0b 100644 --- a/engine-tests/src/tests/standalone/json_snapshot.rs +++ b/engine-tests/src/tests/standalone/json_snapshot.rs @@ -44,8 +44,10 @@ fn test_produce_snapshot() { "src/tests/res/contract.aurora.block51077328.json", ) .unwrap(); - let mut runner = standalone::StandaloneRunner::default(); - runner.chain_id = 1313161554; + let mut runner = standalone::StandaloneRunner { + chain_id: 1313161554, + ..Default::default() + }; runner .storage .set_engine_account_id(&"aurora".parse().unwrap()) @@ -94,7 +96,7 @@ fn test_produce_snapshot() { for entry in snapshot.result.values { let key = base64::decode(entry.key).unwrap(); // skip the eth-connector keys; they were changed by minting the new account - if &key[0..3] == &[7, 6, 1] { + if key[0..3] == [7, 6, 1] { continue; } let value = base64::decode(entry.value).unwrap(); diff --git a/engine-tests/src/tests/standalone/sanity.rs b/engine-tests/src/tests/standalone/sanity.rs index f537951d5..26197c6a3 100644 --- a/engine-tests/src/tests/standalone/sanity.rs +++ b/engine-tests/src/tests/standalone/sanity.rs @@ -1,6 +1,7 @@ -use crate::test_utils::standalone::mocks::{promise, storage}; use aurora_engine::engine; use aurora_engine_sdk::env::DEFAULT_PREPAID_GAS; +use aurora_engine_test_doubles::io::{Storage, StoragePointer}; +use aurora_engine_test_doubles::promise::PromiseTracker; use aurora_engine_types::types::{Address, Wei}; use aurora_engine_types::{account_id::AccountId, H160, H256, U256}; use std::sync::RwLock; @@ -21,8 +22,8 @@ fn test_deploy_code() { upgrade_delay_blocks: 0, }; let origin = Address::new(H160([0u8; 20])); - let storage = RwLock::new(storage::Storage::default()); - let io = storage::StoragePointer(&storage); + let storage = RwLock::new(Storage::default()); + let io = StoragePointer(&storage); let env = aurora_engine_sdk::env::Fixed { signer_account_id: owner_id.clone(), current_account_id: owner_id.clone(), @@ -33,7 +34,7 @@ fn test_deploy_code() { random_seed: H256::zero(), prepaid_gas: DEFAULT_PREPAID_GAS, }; - let mut handler = promise::PromiseTracker::default(); + let mut handler = PromiseTracker::default(); let mut engine = engine::Engine::new_with_state(state, origin, owner_id, io, &env); let code_to_deploy = vec![1, 2, 3, 4, 5, 6]; let result = engine.deploy_code( diff --git a/engine-tests/src/tests/standalone/storage.rs b/engine-tests/src/tests/standalone/storage.rs index b21584da0..be5de9d1d 100644 --- a/engine-tests/src/tests/standalone/storage.rs +++ b/engine-tests/src/tests/standalone/storage.rs @@ -198,9 +198,7 @@ fn test_block_index() { let missing_block_height = block_height + 1; let missing_block_hash = H256([32u8; 32]); match storage.get_block_hash_by_height(missing_block_height) { - Err(engine_standalone_storage::Error::NoBlockAtHeight(h)) if h == missing_block_height => { - () // ok - } + Err(engine_standalone_storage::Error::NoBlockAtHeight(h)) if h == missing_block_height => {} other => panic!("Unexpected response: {:?}", other), } match storage.get_block_height_by_hash(missing_block_hash) { @@ -233,7 +231,7 @@ fn test_block_index() { let prev_height = block_height - 1; let prev_hash = H256([0xbb; 32]); storage - .set_block_data(prev_hash, prev_height, block_metadata.clone()) + .set_block_data(prev_hash, prev_height, block_metadata) .unwrap(); // check earliest+latest blocks are still correct @@ -313,10 +311,7 @@ fn test_transaction_index() { let missing_tx_hash = H256([13u8; 32]); match storage.get_transaction_data(missing_tx_hash) { Err(engine_standalone_storage::Error::TransactionHashNotFound(h)) - if h == missing_tx_hash => - { - () // ok - } + if h == missing_tx_hash => {} other => panic!("Unexpected response: {:?}", other), } match storage.get_transaction_by_position(tx_not_included) { diff --git a/engine-tests/src/tests/standalone/sync.rs b/engine-tests/src/tests/standalone/sync.rs index 6f4252832..1aa6d2b60 100644 --- a/engine-tests/src/tests/standalone/sync.rs +++ b/engine-tests/src/tests/standalone/sync.rs @@ -220,7 +220,7 @@ fn test_consume_deploy_erc20_message() { runner.env.block_height += 1; runner.env.signer_account_id = "some_account.near".parse().unwrap(); - runner.env.predecessor_account_id = token.clone(); + runner.env.predecessor_account_id = token; test_utils::standalone::mocks::insert_block(&mut runner.storage, runner.env.block_height); let block_hash = test_utils::standalone::mocks::compute_block_hash(runner.env.block_height); diff --git a/engine-tests/src/tests/standalone/tracing.rs b/engine-tests/src/tests/standalone/tracing.rs index 0b929b3a5..163569947 100644 --- a/engine-tests/src/tests/standalone/tracing.rs +++ b/engine-tests/src/tests/standalone/tracing.rs @@ -20,10 +20,8 @@ fn test_evm_tracing_with_storage() { let mut runner = standalone::StandaloneRunner::default(); let mut signer = test_utils::Signer::random(); let signer_address = test_utils::address_from_secret_key(&signer.secret_key); - let sender_address = - Address::decode(&"304ee8ae14eceb3a544dff53a27eb1bb1aaa471f".to_string()).unwrap(); - let weth_address = - Address::decode(&"c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2".to_string()).unwrap(); + let sender_address = Address::decode("304ee8ae14eceb3a544dff53a27eb1bb1aaa471f").unwrap(); + let weth_address = Address::decode("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2").unwrap(); // Initialize EVM runner.init_evm_with_chain_id(1); diff --git a/engine-tests/src/tests/standard_precompiles.rs b/engine-tests/src/tests/standard_precompiles.rs index 94454ba63..9d16dfc3c 100644 --- a/engine-tests/src/tests/standard_precompiles.rs +++ b/engine-tests/src/tests/standard_precompiles.rs @@ -54,7 +54,7 @@ fn profile_identity() { #[test] fn profile_modexp() { let profile = precompile_execution_profile("test_modexp"); - test_utils::assert_gas_bound(profile.all_gas(), 7); + test_utils::assert_gas_bound(profile.all_gas(), 8); } #[test] diff --git a/engine-tests/src/tests/state_migration.rs b/engine-tests/src/tests/state_migration.rs index f96cc7558..e175e0fca 100644 --- a/engine-tests/src/tests/state_migration.rs +++ b/engine-tests/src/tests/state_migration.rs @@ -40,7 +40,7 @@ pub fn deploy_evm() -> AuroraAccount { let prover_account = str_to_account_id("prover.near"); let new_args = NewCallArgs { chain_id: crate::prelude::u256_to_arr(&U256::from(aurora_runner.chain_id)), - owner_id: str_to_account_id(main_account.account_id.clone().as_str()), + owner_id: str_to_account_id(main_account.account_id.as_str()), bridge_prover_id: prover_account.clone(), upgrade_delay_blocks: 1, }; diff --git a/engine-tests/src/tests/uniswap.rs b/engine-tests/src/tests/uniswap.rs index 8582de8a9..c200b416c 100644 --- a/engine-tests/src/tests/uniswap.rs +++ b/engine-tests/src/tests/uniswap.rs @@ -33,7 +33,7 @@ fn test_uniswap_input_multihop() { let tokens = context.create_tokens(10, MINT_AMOUNT.into()); for (token_a, token_b) in tokens.iter().zip(tokens.iter().skip(1)) { context.create_pool(token_a, token_b); - context.add_equal_liquidity(LIQUIDITY_AMOUNT.into(), &token_a, &token_b); + context.add_equal_liquidity(LIQUIDITY_AMOUNT.into(), token_a, token_b); } let (_amount_out, _evm_gas, profile) = context.exact_input(&tokens, INPUT_AMOUNT.into()); @@ -52,7 +52,7 @@ fn test_uniswap_exact_output() { test_utils::assert_gas_bound(profile.all_gas(), 33); let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); assert!( - 40 <= wasm_fraction && wasm_fraction <= 50, + (40..=50).contains(&wasm_fraction), "{}% is not between 40% and 50%", wasm_fraction ); @@ -62,7 +62,7 @@ fn test_uniswap_exact_output() { test_utils::assert_gas_bound(profile.all_gas(), 18); let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); assert!( - 45 <= wasm_fraction && wasm_fraction <= 55, + (45..=55).contains(&wasm_fraction), "{}% is not between 45% and 55%", wasm_fraction ); @@ -154,8 +154,8 @@ impl UniswapTestContext { } pub fn create_tokens(&mut self, n: usize, mint_amount: U256) -> Vec { - let names = ('a'..'z').into_iter().map(|c| format!("token_{}", c)); - let symbols = ('A'..'Z').into_iter().map(|c| format!("{}{}{}", c, c, c)); + let names = ('a'..='z').into_iter().map(|c| format!("token_{}", c)); + let symbols = ('A'..='Z').into_iter().map(|c| format!("{}{}{}", c, c, c)); let mut result: Vec = names .zip(symbols) .take(n) @@ -210,7 +210,7 @@ impl UniswapTestContext { MintParams { token0, token1, - fee: POOL_FEE.into(), + fee: POOL_FEE, tick_lower: -1000, tick_upper: 1000, amount0_desired: amount, @@ -243,11 +243,11 @@ impl UniswapTestContext { let result = { let mut values = [U256::zero(); 4]; let result_bytes = test_utils::unwrap_success(result); - for i in 0..4 { + for (i, item) in values.iter_mut().enumerate() { let lower = i * 32; let upper = (i + 1) * 32; let value = U256::from_big_endian(&result_bytes[lower..upper]); - values[i] = value; + *item = value; } LiquidityResult { token_id: values[0], @@ -327,8 +327,8 @@ impl UniswapTestContext { token_out: &ERC20, amount_out: U256, ) -> (U256, ExecutionProfile) { - self.approve_erc20(&token_in, self.swap_router.0.address, U256::MAX); - self.approve_erc20(&token_out, self.swap_router.0.address, U256::MAX); + self.approve_erc20(token_in, self.swap_router.0.address, U256::MAX); + self.approve_erc20(token_out, self.swap_router.0.address, U256::MAX); let params = self.exact_output_single_params(amount_out, token_in, token_out); let swap_router = &self.swap_router; diff --git a/engine-tests/src/tests/xcc.rs b/engine-tests/src/tests/xcc.rs index 6f9bbad15..ed05df32a 100644 --- a/engine-tests/src/tests/xcc.rs +++ b/engine-tests/src/tests/xcc.rs @@ -4,8 +4,10 @@ use crate::tests::erc20_connector::sim_tests; use crate::tests::state_migration::{deploy_evm, AuroraAccount}; use aurora_engine_precompiles::xcc::{self, costs, cross_contract_call}; use aurora_engine_transactions::legacy::TransactionLegacy; +use aurora_engine_types::account_id::AccountId; use aurora_engine_types::parameters::{ - CrossContractCallArgs, PromiseArgs, PromiseCreateArgs, PromiseWithCallbackArgs, + CrossContractCallArgs, NearPromise, PromiseArgs, PromiseCreateArgs, PromiseWithCallbackArgs, + SimpleNearPromise, }; use aurora_engine_types::types::{Address, EthGas, NearGas, Wei, Yocto}; use aurora_engine_types::U256; @@ -132,9 +134,14 @@ fn test_xcc_eth_gas_cost() { costs::CROSS_CONTRACT_CALL_BYTE ); - // As a sanity check, confirm that the total EVM gas spent aligns with expectations - let total_gas1 = y1 + baseline.all_gas(); - let total_gas2 = y2 + baseline.all_gas(); + // As a sanity check, confirm that the total EVM gas spent aligns with expectations. + // The additional gas added is the amount attached to the XCC call (this is "used", but not + // "burnt"). + let total_gas1 = y1 + baseline.all_gas() + costs::ROUTER_EXEC_BASE.as_u64(); + let total_gas2 = y2 + + baseline.all_gas() + + costs::ROUTER_EXEC_BASE.as_u64() + + costs::ROUTER_EXEC_PER_CALLBACK.as_u64(); assert!( test_utils::within_x_percent(20, evm1, total_gas1 / costs::CROSS_CONTRACT_CALL_NEAR_GAS), "Incorrect EVM gas used. Expected: {} Actual: {}", @@ -159,62 +166,146 @@ fn test_xcc_precompile_scheduled() { test_xcc_precompile_common(true) } -fn test_xcc_precompile_common(is_scheduled: bool) { - let aurora = deploy_evm(); - let chain_id = AuroraRunner::default().chain_id; - let xcc_wasm_bytes = contract_bytes(); - aurora - .user - .call( - aurora.contract.account_id(), - "factory_update", - &xcc_wasm_bytes, - near_sdk_sim::DEFAULT_GAS, - 0, - ) - .assert_success(); +/// This test uses the XCC feature where the promise has many nested callbacks. +/// The contract it uses is one which computes Fibonacci numbers in an inefficient way. +/// The contract has two functions: `seed` and `accumulate`. +/// The `seed` function always returns `{"a": "0", "b": "1"}`. +/// The `accumulate` function performs one step of the Fibonacci recursion relation using +/// a promise result (i.e. result from prior call) as input. +/// Therefore, we can compute Fibonacci numbers by creating a long chain of callbacks. +/// For example, to compute the 6th number: +/// `seed.then(accumulate).then(accumulate).then(accumulate).then(accumulate).then(accumulate)`. +#[test] +fn test_xcc_multiple_callbacks() { + let XccTestContext { + aurora, + mut signer, + signer_address, + chain_id, + .. + } = init_xcc(); - let mut signer = test_utils::Signer::random(); - let signer_address = test_utils::address_from_secret_key(&signer.secret_key); + // 1. Deploy Fibonacci contract + let fib_account_id = deploy_fibonacci(&aurora); - // Setup wNEAR contract and bridge it to Aurora - let wnear_account = deploy_wnear(&aurora); - let wnear_erc20 = sim_tests::deploy_erc20_from_nep_141(&wnear_account, &aurora); - sim_tests::transfer_nep_141_to_erc_20( - &wnear_account, - &wnear_erc20, - &aurora.user, + // 2. Create XCC account, schedule Fibonacci call + let n = 6; + let promise = make_fib_promise(n, &fib_account_id); + let xcc_args = CrossContractCallArgs::Delayed(PromiseArgs::Recursive(promise)); + let _result = submit_xcc_transaction(xcc_args, &aurora, &mut signer, chain_id); + + // 3. Make Fibonacci call + let router_account = format!( + "{}.{}", + hex::encode(signer_address.as_bytes()), + aurora.contract.account_id.as_str() + ); + let result = aurora.user.call( + router_account.parse().unwrap(), + "execute_scheduled", + b"{\"nonce\": \"0\"}", + near_sdk_sim::DEFAULT_GAS, + 0, + ); + result.assert_success(); + + // 4. Check the result is correct + let output = result.unwrap_json_value(); + check_fib_result(output, n); +} + +/// This test is similar to `test_xcc_multiple_callbacks`, but instead of computing +/// Fibonacci numbers through repeated callbacks, it uses the `And` promise combinator. +#[test] +fn test_xcc_and_combinator() { + let XccTestContext { + aurora, + mut signer, signer_address, - WNEAR_AMOUNT, - &aurora, + chain_id, + .. + } = init_xcc(); + + // 1. Deploy Fibonacci contract + let fib_account_id = deploy_fibonacci(&aurora); + + // 2. Create XCC account, schedule Fibonacci call + let n = 6; + let promise = NearPromise::Then { + base: Box::new(NearPromise::And(vec![ + NearPromise::Simple(SimpleNearPromise::Create(PromiseCreateArgs { + target_account_id: fib_account_id.clone(), + method: "fib".into(), + args: format!(r#"{{"n": {}}}"#, n - 1).into_bytes(), + attached_balance: Yocto::new(0), + attached_gas: NearGas::new(10_000_000_000_000_u64 * n), + })), + NearPromise::Simple(SimpleNearPromise::Create(PromiseCreateArgs { + target_account_id: fib_account_id.clone(), + method: "fib".into(), + args: format!(r#"{{"n": {}}}"#, n - 2).into_bytes(), + attached_balance: Yocto::new(0), + attached_gas: NearGas::new(10_000_000_000_000_u64 * n), + })), + ])), + callback: SimpleNearPromise::Create(PromiseCreateArgs { + target_account_id: fib_account_id, + method: "sum".into(), + args: Vec::new(), + attached_balance: Yocto::new(0), + attached_gas: NearGas::new(5_000_000_000_000), + }), + }; + let xcc_args = CrossContractCallArgs::Delayed(PromiseArgs::Recursive(promise)); + let _result = submit_xcc_transaction(xcc_args, &aurora, &mut signer, chain_id); + + // 3. Make Fibonacci call + let router_account = format!( + "{}.{}", + hex::encode(signer_address.as_bytes()), + aurora.contract.account_id.as_str() ); - aurora - .user - .call( - aurora.contract.account_id(), - "factory_set_wnear_address", - wnear_erc20.0.address.as_bytes(), - near_sdk_sim::DEFAULT_GAS, - 0, - ) - .assert_success(); - let approve_tx = wnear_erc20.approve( - cross_contract_call::ADDRESS, - WNEAR_AMOUNT.into(), - signer.use_nonce().into(), + let result = aurora.user.call( + router_account.parse().unwrap(), + "execute_scheduled", + b"{\"nonce\": \"0\"}", + near_sdk_sim::DEFAULT_GAS, + 0, ); - let signed_transaction = - test_utils::sign_transaction(approve_tx, Some(chain_id), &signer.secret_key); - aurora - .user - .call( - aurora.contract.account_id(), - "submit", - &rlp::encode(&signed_transaction), - near_sdk_sim::DEFAULT_GAS, - 0, - ) - .assert_success(); + result.assert_success(); + + // 4. Check the result is correct + let output = result.unwrap_json_value(); + check_fib_result(output, usize::try_from(n).unwrap()); +} + +fn check_fib_result(output: serde_json::Value, n: usize) { + let fib_numbers: [u8; 8] = [0, 1, 1, 2, 3, 5, 8, 13]; + let get_number = |field_name: &str| -> u8 { + output + .as_object() + .unwrap() + .get(field_name) + .unwrap() + .as_str() + .unwrap() + .parse() + .unwrap() + }; + let a = get_number("a"); + let b = get_number("b"); + assert_eq!(a, fib_numbers[n]); + assert_eq!(b, fib_numbers[n + 1]); +} + +fn test_xcc_precompile_common(is_scheduled: bool) { + let XccTestContext { + aurora, + mut signer, + signer_address, + chain_id, + wnear_account, + } = init_xcc(); let router_account = format!( "{}.{}", @@ -285,34 +376,24 @@ fn test_xcc_precompile_common(is_scheduled: bool) { attached_balance: Yocto::new(1), attached_gas: NearGas::new(100_000_000_000_000), }; + let callback = PromiseCreateArgs { + target_account_id: nep_141_token.account_id.as_str().parse().unwrap(), + method: "ft_balance_of".into(), + args: format!("{{\"account_id\":\"{}\"}}", router_account).into_bytes(), + attached_balance: Yocto::new(0), + attached_gas: NearGas::new(2_000_000_000_000), + }; + let promise_args = PromiseArgs::Callback(PromiseWithCallbackArgs { + base: promise, + callback, + }); let xcc_args = if is_scheduled { - CrossContractCallArgs::Delayed(PromiseArgs::Create(promise)) + CrossContractCallArgs::Delayed(promise_args) } else { - CrossContractCallArgs::Eager(PromiseArgs::Create(promise)) - }; - let transaction = TransactionLegacy { - nonce: signer.use_nonce().into(), - gas_price: 0u64.into(), - gas_limit: u64::MAX.into(), - to: Some(cross_contract_call::ADDRESS), - value: Wei::zero(), - data: xcc_args.try_to_vec().unwrap(), + CrossContractCallArgs::Eager(promise_args) }; - let signed_transaction = - test_utils::sign_transaction(transaction, Some(chain_id), &signer.secret_key); let engine_balance_before_xcc = get_engine_near_balance(&aurora); - let result = aurora.user.call( - aurora.contract.account_id(), - "submit", - &rlp::encode(&signed_transaction), - near_sdk_sim::DEFAULT_GAS, - 0, - ); - result.assert_success(); - let submit_result: aurora_engine::parameters::SubmitResult = result.unwrap_borsh(); - if !submit_result.status.is_ok() { - panic!("Unexpected result {:?}", submit_result); - } + let _result = submit_xcc_transaction(xcc_args, &aurora, &mut signer, chain_id); print_outcomes(&aurora); let engine_balance_after_xcc = get_engine_near_balance(&aurora); @@ -369,11 +450,117 @@ fn test_xcc_precompile_common(is_scheduled: bool) { ); } +/// Deploys the EVM, sets xcc router code, deploys wnear contract, bridges wnear into EVM, and calls `factory_set_wnear_address` +fn init_xcc() -> XccTestContext { + let aurora = deploy_evm(); + let chain_id = AuroraRunner::default().chain_id; + let xcc_wasm_bytes = contract_bytes(); + aurora + .user + .call( + aurora.contract.account_id(), + "factory_update", + &xcc_wasm_bytes, + near_sdk_sim::DEFAULT_GAS, + 0, + ) + .assert_success(); + + let mut signer = test_utils::Signer::random(); + let signer_address = test_utils::address_from_secret_key(&signer.secret_key); + + // Setup wNEAR contract and bridge it to Aurora + let wnear_account = deploy_wnear(&aurora); + let wnear_erc20 = sim_tests::deploy_erc20_from_nep_141(&wnear_account, &aurora); + sim_tests::transfer_nep_141_to_erc_20( + &wnear_account, + &wnear_erc20, + &aurora.user, + signer_address, + WNEAR_AMOUNT, + &aurora, + ); + aurora + .user + .call( + aurora.contract.account_id(), + "factory_set_wnear_address", + wnear_erc20.0.address.as_bytes(), + near_sdk_sim::DEFAULT_GAS, + 0, + ) + .assert_success(); + let approve_tx = wnear_erc20.approve( + cross_contract_call::ADDRESS, + WNEAR_AMOUNT.into(), + signer.use_nonce().into(), + ); + let signed_transaction = + test_utils::sign_transaction(approve_tx, Some(chain_id), &signer.secret_key); + aurora + .user + .call( + aurora.contract.account_id(), + "submit", + &rlp::encode(&signed_transaction), + near_sdk_sim::DEFAULT_GAS, + 0, + ) + .assert_success(); + + XccTestContext { + aurora, + signer, + signer_address, + chain_id, + wnear_account, + } +} + +struct XccTestContext { + pub aurora: AuroraAccount, + pub signer: test_utils::Signer, + pub signer_address: Address, + pub chain_id: u64, + pub wnear_account: UserAccount, +} + +fn submit_xcc_transaction( + xcc_args: CrossContractCallArgs, + aurora: &AuroraAccount, + signer: &mut test_utils::Signer, + chain_id: u64, +) -> near_sdk_sim::ExecutionResult { + let transaction = TransactionLegacy { + nonce: signer.use_nonce().into(), + gas_price: 0u64.into(), + gas_limit: u64::MAX.into(), + to: Some(cross_contract_call::ADDRESS), + value: Wei::zero(), + data: xcc_args.try_to_vec().unwrap(), + }; + let signed_transaction = + test_utils::sign_transaction(transaction, Some(chain_id), &signer.secret_key); + let result = aurora.user.call( + aurora.contract.account_id(), + "submit", + &rlp::encode(&signed_transaction), + near_sdk_sim::DEFAULT_GAS, + 0, + ); + result.assert_success(); + let submit_result: aurora_engine::parameters::SubmitResult = result.unwrap_borsh(); + if !submit_result.status.is_ok() { + panic!("Unexpected result {:?}", submit_result); + } + result +} + fn get_engine_near_balance(aurora: &AuroraAccount) -> u128 { aurora .user .borrow_runtime() - .view_account(&aurora.contract.account_id.as_str()) + .view_account(aurora.contract.account_id.as_str()) .unwrap() .amount() } @@ -400,7 +587,7 @@ fn test_xcc_schedule_gas() { let (maybe_outcome, maybe_error) = router.call( "schedule", "aurora", - PromiseArgs::Create(promise.clone()).try_to_vec().unwrap(), + PromiseArgs::Create(promise).try_to_vec().unwrap(), ); assert!(maybe_error.is_none()); let outcome = maybe_outcome.unwrap(); @@ -418,6 +605,17 @@ fn test_xcc_schedule_gas() { fn test_xcc_exec_gas() { let mut router = deploy_router(); + let create_promise_chain = + |base_promise: &PromiseCreateArgs, callback_count: usize| -> NearPromise { + let mut result = NearPromise::Simple(SimpleNearPromise::Create(base_promise.clone())); + for _ in 0..callback_count { + result = NearPromise::Then { + base: Box::new(result), + callback: SimpleNearPromise::Create(base_promise.clone()), + }; + } + result + }; let promise = PromiseCreateArgs { target_account_id: "some_account.near".parse().unwrap(), method: "some_method".into(), @@ -426,42 +624,68 @@ fn test_xcc_exec_gas() { attached_gas: NearGas::new(100_000_000_000_000), }; - let (maybe_outcome, maybe_error) = router.call( - "execute", - "aurora", - PromiseArgs::Create(promise.clone()).try_to_vec().unwrap(), - ); - assert!(maybe_error.is_none()); - let outcome = maybe_outcome.unwrap(); + for callback_count in 0..5 { + let x = create_promise_chain(&promise, callback_count); + let args = PromiseArgs::Recursive(x); + + let (maybe_outcome, maybe_error) = + router.call("execute", "aurora", args.try_to_vec().unwrap()); + assert!(maybe_error.is_none()); + let outcome = maybe_outcome.unwrap(); + + let callback_count = args.promise_count() - 1; + let router_exec_cost = costs::ROUTER_EXEC_BASE + + NearGas::new(callback_count * costs::ROUTER_EXEC_PER_CALLBACK.as_u64()); + assert!( + outcome.burnt_gas < router_exec_cost.as_u64(), + "{:?} not less than {:?}", + outcome.burnt_gas, + router_exec_cost + ); - assert!( - outcome.burnt_gas < costs::ROUTER_EXEC.as_u64(), - "{:?} not less than {:?}", - outcome.burnt_gas, - costs::ROUTER_EXEC - ); - assert_eq!(outcome.action_receipts.len(), 1); - assert_eq!( - outcome.action_receipts[0].0.as_str(), - promise.target_account_id.as_ref() - ); - let receipt = &outcome.action_receipts[0].1; - assert_eq!(receipt.actions.len(), 1); - let action = &receipt.actions[0]; - match action { - Action::FunctionCall(function_call) => { - assert_eq!(function_call.method_name, promise.method); - assert_eq!(function_call.args, promise.args); - assert_eq!(function_call.deposit, promise.attached_balance.as_u128()); - assert_eq!(function_call.gas, promise.attached_gas.as_u64()); + assert_eq!(outcome.action_receipts.len(), args.promise_count() as usize); + for (target_account_id, receipt) in outcome.action_receipts { + assert_eq!( + target_account_id.as_str(), + promise.target_account_id.as_ref() + ); + assert_eq!(receipt.actions.len(), 1); + let action = &receipt.actions[0]; + match action { + Action::FunctionCall(function_call) => { + assert_eq!(function_call.method_name, promise.method); + assert_eq!(function_call.args, promise.args); + assert_eq!(function_call.deposit, promise.attached_balance.as_u128()); + assert_eq!(function_call.gas, promise.attached_gas.as_u64()); + } + other => panic!("Unexpected action {:?}", other), + }; } - other => panic!("Unexpected action {:?}", other), + } +} + +fn deploy_fibonacci(aurora: &AuroraAccount) -> AccountId { + let fib_contract_bytes = { + let base_path = Path::new("..").join("etc").join("tests").join("fibonacci"); + let output_path = + base_path.join("target/wasm32-unknown-unknown/release/fibonacci_on_near.wasm"); + test_utils::rust::compile(base_path); + fs::read(output_path).unwrap() }; + let fib_account_id = format!("fib.{}", aurora.user.account_id.as_str()); + let _fib_account = aurora.user.deploy( + &fib_contract_bytes, + fib_account_id.parse().unwrap(), + near_sdk_sim::STORAGE_AMOUNT, + ); + fib_account_id.parse().unwrap() } fn deploy_router() -> AuroraRunner { - let mut router = AuroraRunner::default(); - router.code = ContractCode::new(contract_bytes(), None); + let mut router = AuroraRunner { + code: ContractCode::new(contract_bytes(), None), + ..Default::default() + }; router.context.current_account_id = "some_address.aurora".parse().unwrap(); router.context.predecessor_account_id = "aurora".parse().unwrap(); @@ -598,3 +822,28 @@ fn contract_bytes() -> Vec { test_utils::rust::compile(base_path); fs::read(output_path).unwrap() } + +fn make_fib_promise(n: usize, account_id: &AccountId) -> NearPromise { + if n == 0 { + NearPromise::Simple(SimpleNearPromise::Create(PromiseCreateArgs { + target_account_id: account_id.clone(), + method: "seed".into(), + args: Vec::new(), + attached_balance: Yocto::new(0), + attached_gas: NearGas::new(5_000_000_000_000), + })) + } else { + let base = make_fib_promise(n - 1, account_id); + let callback = SimpleNearPromise::Create(PromiseCreateArgs { + target_account_id: account_id.clone(), + method: "accumulate".into(), + args: Vec::new(), + attached_balance: Yocto::new(0), + attached_gas: NearGas::new(5_000_000_000_000), + }); + NearPromise::Then { + base: Box::new(base), + callback, + } + } +} diff --git a/engine-transactions/Cargo.toml b/engine-transactions/Cargo.toml index 8b7351786..cfc821832 100644 --- a/engine-transactions/Cargo.toml +++ b/engine-transactions/Cargo.toml @@ -16,7 +16,7 @@ autobenches = false aurora-engine-types = { path = "../engine-types", default-features = false } aurora-engine-sdk = { path = "../engine-sdk", default-features = false } aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false } rlp = { version = "0.5.0", default-features = false } serde = { version = "1", features = ["derive"], optional = true } @@ -24,5 +24,5 @@ serde = { version = "1", features = ["derive"], optional = true } hex = { version = "0.4", default-features = false, features = ["alloc"] } [features] -std = ["aurora-engine-types/std", "aurora-engine-sdk/std", "aurora-engine-precompiles/std", "evm/std", "rlp/std", "hex/std"] +std = ["aurora-engine-types/std", "aurora-engine-sdk/std", "aurora-engine-precompiles/std", "evm/std", "rlp/std"] impl-serde = ["aurora-engine-types/impl-serde", "serde"] diff --git a/engine-transactions/src/legacy.rs b/engine-transactions/src/legacy.rs index 0f83f2050..aa7056d4b 100644 --- a/engine-transactions/src/legacy.rs +++ b/engine-transactions/src/legacy.rs @@ -193,7 +193,7 @@ mod tests { assert_eq!(tx_2.transaction.to, Some(address_from_arr(&[0u8; 20]))); // otherwise, tx_1 and tx_2 are identical. - let mut tx_2_mod = tx_2.clone(); + let mut tx_2_mod = tx_2; tx_2_mod.transaction.to = None; assert_eq!(tx_1.transaction, tx_2_mod.transaction); } diff --git a/engine-types/Cargo.toml b/engine-types/Cargo.toml index 4494c0580..aee2ca266 100644 --- a/engine-types/Cargo.toml +++ b/engine-types/Cargo.toml @@ -15,11 +15,11 @@ autobenches = false [dependencies] borsh = { version = "0.9.3", default-features = false } hex = { version = "0.4", default-features = false, features = ["alloc"] } -primitive-types = { version = "0.11", default-features = false, features = ["rlp"] } +primitive-types = { version = "0.12", default-features = false, features = ["rlp"] } serde = { version = "1", features = ["derive"], optional = true } [dev-dependencies] -rand = "0.7.3" +rand = "0.8.5" [features] default = ["std"] diff --git a/engine-types/src/account_id.rs b/engine-types/src/account_id.rs index 4998d6a90..8b30388ce 100644 --- a/engine-types/src/account_id.rs +++ b/engine-types/src/account_id.rs @@ -14,6 +14,7 @@ pub const MAX_ACCOUNT_ID_LEN: usize = 64; #[derive( BorshSerialize, BorshDeserialize, Default, Eq, Ord, Hash, Clone, Debug, PartialEq, PartialOrd, )] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct AccountId(Box); impl AccountId { @@ -56,7 +57,7 @@ impl AccountId { } (!last_char_is_separator) - .then(|| ()) + .then_some(()) .ok_or(ParseAccountError::Invalid) } } @@ -250,7 +251,7 @@ mod tests { } for account_id in BAD_ACCOUNT_IDS.iter().cloned() { - if let Ok(_) = AccountId::validate(account_id) { + if AccountId::validate(account_id).is_ok() { panic!("Valid account id {:?} marked valid", account_id); } } diff --git a/engine-types/src/lib.rs b/engine-types/src/lib.rs index f2cf3590b..da10bbe53 100644 --- a/engine-types/src/lib.rs +++ b/engine-types/src/lib.rs @@ -18,6 +18,7 @@ mod v0 { boxed::Box, collections::BTreeMap as HashMap, collections::BTreeMap, + collections::BTreeSet, fmt, format, str, string::String, string::ToString, diff --git a/engine-types/src/parameters.rs b/engine-types/src/parameters.rs index 0c78fb1b7..5cd6c9eb4 100644 --- a/engine-types/src/parameters.rs +++ b/engine-types/src/parameters.rs @@ -1,6 +1,7 @@ use crate::account_id::*; use crate::types::*; use crate::*; +use borsh::maybestd::io; use borsh::{BorshDeserialize, BorshSerialize}; #[must_use] @@ -8,13 +9,24 @@ use borsh::{BorshDeserialize, BorshSerialize}; pub enum PromiseArgs { Create(PromiseCreateArgs), Callback(PromiseWithCallbackArgs), + Recursive(NearPromise), } impl PromiseArgs { + /// Counts the total number of promises this call creates (including callbacks). + pub fn promise_count(&self) -> u64 { + match self { + Self::Create(_) => 1, + Self::Callback(_) => 2, + Self::Recursive(p) => p.promise_count(), + } + } + pub fn total_gas(&self) -> NearGas { match self { Self::Create(call) => call.attached_gas, Self::Callback(cb) => cb.base.attached_gas + cb.callback.attached_gas, + Self::Recursive(p) => p.total_gas(), } } @@ -22,6 +34,149 @@ impl PromiseArgs { match self { Self::Create(call) => call.attached_balance, Self::Callback(cb) => cb.base.attached_balance + cb.callback.attached_balance, + Self::Recursive(p) => p.total_near(), + } + } +} + +#[derive(Debug, BorshSerialize, BorshDeserialize, Clone, PartialEq, Eq)] +pub enum SimpleNearPromise { + Create(PromiseCreateArgs), + Batch(PromiseBatchAction), +} + +impl SimpleNearPromise { + pub fn total_gas(&self) -> NearGas { + match self { + Self::Create(call) => call.attached_gas, + Self::Batch(batch) => { + let total: u64 = batch + .actions + .iter() + .filter_map(|a| { + if let PromiseAction::FunctionCall { gas, .. } = a { + Some(gas.as_u64()) + } else { + None + } + }) + .sum(); + NearGas::new(total) + } + } + } + + pub fn total_near(&self) -> Yocto { + match self { + Self::Create(call) => call.attached_balance, + Self::Batch(batch) => { + let total: u128 = batch + .actions + .iter() + .filter_map(|a| match a { + PromiseAction::FunctionCall { attached_yocto, .. } => { + Some(attached_yocto.as_u128()) + } + PromiseAction::Transfer { amount } => Some(amount.as_u128()), + _ => None, + }) + .sum(); + Yocto::new(total) + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NearPromise { + Simple(SimpleNearPromise), + Then { + base: Box, + // Near doesn't allow arbitrary promises in the callback, + // only simple calls to contracts or batches of actions. + callback: SimpleNearPromise, + }, + And(Vec), +} + +impl NearPromise { + pub fn promise_count(&self) -> u64 { + match self { + Self::Simple(_) => 1, + Self::Then { base, .. } => base.promise_count() + 1, + Self::And(ps) => ps.iter().map(Self::promise_count).sum(), + } + } + + pub fn total_gas(&self) -> NearGas { + match self { + Self::Simple(x) => x.total_gas(), + Self::Then { base, callback } => base.total_gas() + callback.total_gas(), + Self::And(promises) => { + let total = promises.iter().map(|p| p.total_gas().as_u64()).sum(); + NearGas::new(total) + } + } + } + + pub fn total_near(&self) -> Yocto { + match self { + Self::Simple(x) => x.total_near(), + Self::Then { base, callback } => base.total_near() + callback.total_near(), + Self::And(promises) => { + let total = promises.iter().map(|p| p.total_near().as_u128()).sum(); + Yocto::new(total) + } + } + } +} + +// Cannot use derive macro on recursive types, so we write it by hand +impl BorshSerialize for NearPromise { + fn serialize(&self, writer: &mut W) -> io::Result<()> { + match self { + Self::Simple(x) => { + writer.write_all(&[0x00])?; + x.serialize(writer) + } + Self::Then { base, callback } => { + writer.write_all(&[0x01])?; + base.serialize(writer)?; + callback.serialize(writer) + } + Self::And(promises) => { + writer.write_all(&[0x02])?; + promises.serialize(writer) + } + } + } +} + +impl BorshDeserialize for NearPromise { + fn deserialize(buf: &mut &[u8]) -> io::Result { + let variant_byte = buf[0]; + *buf = &buf[1..]; + match variant_byte { + 0x00 => { + let inner = SimpleNearPromise::deserialize(buf)?; + Ok(Self::Simple(inner)) + } + 0x01 => { + let base = Self::deserialize(buf)?; + let callback = SimpleNearPromise::deserialize(buf)?; + Ok(Self::Then { + base: Box::new(base), + callback, + }) + } + 0x02 => { + let promises: Vec = Vec::deserialize(buf)?; + Ok(Self::And(promises)) + } + _ => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Invalid variant byte for NearPromise", + )), } } } @@ -43,13 +198,13 @@ pub struct PromiseWithCallbackArgs { pub callback: PromiseCreateArgs, } -#[derive(Debug, BorshSerialize, BorshDeserialize, Clone)] +#[derive(Debug, BorshSerialize, BorshDeserialize, Clone, PartialEq, Eq)] pub enum PromiseAction { CreateAccount, Transfer { amount: Yocto, }, - DeployConotract { + DeployContract { code: Vec, }, FunctionCall { @@ -58,10 +213,39 @@ pub enum PromiseAction { attached_yocto: Yocto, gas: NearGas, }, + Stake { + amount: Yocto, + public_key: NearPublicKey, + }, + AddFullAccessKey { + public_key: NearPublicKey, + nonce: u64, + }, + AddFunctionCallKey { + public_key: NearPublicKey, + nonce: u64, + allowance: Yocto, + receiver_id: AccountId, + function_names: String, + }, + DeleteKey { + public_key: NearPublicKey, + }, + DeleteAccount { + beneficiary_id: AccountId, + }, +} + +#[derive(Debug, BorshSerialize, BorshDeserialize, Clone, PartialEq, Eq)] +pub enum NearPublicKey { + /// ed25519 public keys are 32 bytes + Ed25519([u8; 32]), + /// secp256k1 keys are in the uncompressed 64 byte format + Secp256k1([u8; 64]), } #[must_use] -#[derive(Debug, BorshSerialize, BorshDeserialize, Clone)] +#[derive(Debug, BorshSerialize, BorshDeserialize, Clone, PartialEq, Eq)] pub struct PromiseBatchAction { pub target_account_id: AccountId, pub actions: Vec, diff --git a/engine-types/src/types/address.rs b/engine-types/src/types/address.rs index f006c3cd6..13be5223d 100755 --- a/engine-types/src/types/address.rs +++ b/engine-types/src/types/address.rs @@ -46,7 +46,7 @@ impl Address { Ok(Self::new(H160::from_slice(raw_addr))) } - pub fn from_array(array: [u8; 20]) -> Self { + pub const fn from_array(array: [u8; 20]) -> Self { Self(H160(array)) } @@ -115,13 +115,12 @@ mod tests { fn test_address_decode() { // Test compatibility with previous typ RawAddress. // It was: type RawAddress = [u8;20]; - let eth_address_vec = - hex::decode("096DE9C2B8A5B8c22cEe3289B101f6960d68E51E".to_string()).unwrap(); + let eth_address_vec = hex::decode("096DE9C2B8A5B8c22cEe3289B101f6960d68E51E").unwrap(); let mut eth_address = [0u8; 20]; eth_address.copy_from_slice(ð_address_vec[..]); let aurora_eth_address = - Address::decode(&"096DE9C2B8A5B8c22cEe3289B101f6960d68E51E".to_string()).unwrap(); + Address::decode("096DE9C2B8A5B8c22cEe3289B101f6960d68E51E").unwrap(); assert_eq!(eth_address, aurora_eth_address.as_bytes()); let serialized_addr = eth_address.try_to_vec().unwrap(); diff --git a/engine-types/src/types/wei.rs b/engine-types/src/types/wei.rs index 764229983..ea50a18b9 100644 --- a/engine-types/src/types/wei.rs +++ b/engine-types/src/types/wei.rs @@ -16,6 +16,7 @@ pub type WeiU256 = [u8; 32]; #[derive( Default, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, BorshSerialize, BorshDeserialize, )] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct NEP141Wei(u128); impl Display for NEP141Wei { diff --git a/engine/.catalog-info.yaml b/engine/.catalog-info.yaml new file mode 100644 index 000000000..069046f3f --- /dev/null +++ b/engine/.catalog-info.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: aurora-engine + title: Aurora (engine) + description: |- + The Aurora engine + tags: + - contract + - near + links: [] + annotations: + aurora.dev/security-tier: "1" +spec: + owner: engine-team + type: contract + lifecycle: production + system: aurora-engine + deployedAt: + - contract:near/mainnet/aurora + interactsWith: [] diff --git a/engine/Cargo.toml b/engine/Cargo.toml index b0ba09372..06b9d7cf6 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aurora-engine" -version = "2.7.0" +version = "2.8.0" authors = ["Aurora Labs "] edition = "2021" description = "" @@ -21,10 +21,11 @@ aurora-engine-sdk = { path = "../engine-sdk", default-features = false } aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false } aurora-engine-transactions = { path = "../engine-transactions", default-features = false } base64 = { version = "0.13.0", default-features = false, features = ["alloc"] } +bitflags = { version = "1.3", default-features = false } borsh = { version = "0.9.3", default-features = false } byte-slice-cast = { version = "1.0", default-features = false } -ethabi = { version = "17.1", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.36.0-aurora", default-features = false } +ethabi = { version = "18.0", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false } hex = { version = "0.4", default-features = false, features = ["alloc"] } rjson = { git = "https://github.com/aurora-is-near/rjson", rev = "cc3da949", default-features = false, features = ["integer"] } rlp = { version = "0.5.0", default-features = false } @@ -34,8 +35,11 @@ serde = { version = "1", features = ["derive"], optional = true } wee_alloc = { version = "0.4.5", default-features = false } [dev-dependencies] +aurora-engine-test-doubles = { path = "../engine-test-doubles" } serde_json = "1" -rand = "0.7.3" +test-case = "2.1" +sha3 = "0.10" +digest = "0.10" [features] default = ["std"] @@ -46,6 +50,7 @@ log = ["aurora-engine-sdk/log", "aurora-engine-precompiles/log"] tracing = ["evm/tracing"] error_refund = ["aurora-engine-precompiles/error_refund"] integration-test = ["log"] +all-promise-actions = ["aurora-engine-sdk/all-promise-actions"] mainnet = ["contract", "log", "aurora-engine-sdk/mainnet"] testnet = ["contract", "log", "aurora-engine-sdk/testnet"] impl-serde = ["aurora-engine-types/impl-serde", "serde", "aurora-engine-transactions/impl-serde", "evm/with-serde"] diff --git a/engine/src/accounting.rs b/engine/src/accounting.rs index 9fe3c4c76..5cfa3a9a7 100644 --- a/engine/src/accounting.rs +++ b/engine/src/accounting.rs @@ -51,3 +51,95 @@ pub enum Net { Gained(U256), Lost(U256), } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_removing_loss_is_same_as_decreasing_change() { + let loss = U256::from(16u64); + let change = Change { + new_value: U256::zero(), + old_value: loss, + }; + + let mut changed_accounting = Accounting::default(); + changed_accounting.change(change); + + let mut removed_accounting = Accounting::default(); + removed_accounting.remove(loss); + + assert_eq!(removed_accounting, changed_accounting); + } + + #[test] + fn test_removing_loss_nets_loss() { + let mut actual_accounting = Accounting::default(); + + let loss = U256::from(16u64); + + actual_accounting.remove(loss); + + let actual_net = actual_accounting.net(); + let expected_net = Net::Lost(loss); + + assert_eq!(expected_net, actual_net); + } + + #[test] + fn test_equal_change_nets_zero() { + let mut actual_accounting = Accounting::default(); + + let value = U256::from(16u64); + let equal_change = Change { + new_value: value, + old_value: value, + }; + + actual_accounting.change(equal_change); + + let actual_net = actual_accounting.net(); + let expected_net = Net::Zero; + + assert_eq!(expected_net, actual_net); + } + + #[test] + fn test_decreasing_change_nets_loss() { + let mut actual_accounting = Accounting::default(); + + let new_value = U256::from(16u64); + let old_value = U256::from(32u64); + let decreasing_change = Change { + new_value, + old_value, + }; + + actual_accounting.change(decreasing_change); + + let actual_net = actual_accounting.net(); + let expected_net = Net::Lost(U256::from(16u64)); + + assert_eq!(expected_net, actual_net); + } + + #[test] + fn test_increasing_change_nets_gain() { + let mut actual_accounting = Accounting::default(); + + let new_value = U256::from(32u64); + let old_value = U256::from(16u64); + let increasing_change = Change { + new_value, + old_value, + }; + + actual_accounting.change(increasing_change); + + let actual_net = actual_accounting.net(); + let expected_net = Net::Gained(U256::from(16u64)); + + assert_eq!(expected_net, actual_net); + } +} diff --git a/engine/src/admin_controlled.rs b/engine/src/admin_controlled.rs index 2e274e81b..8121c0005 100644 --- a/engine/src/admin_controlled.rs +++ b/engine/src/admin_controlled.rs @@ -27,8 +27,104 @@ pub trait AdminControlled { } pub struct PausedError; + impl AsRef<[u8]> for PausedError { fn as_ref(&self) -> &[u8] { ERR_PAUSED.as_bytes() } } + +#[cfg(test)] +mod tests { + use super::*; + + struct MockAdminControlled { + mask: PausedMask, + } + + impl MockAdminControlled { + pub fn new() -> Self { + Self { mask: 0 } + } + } + + impl AdminControlled for MockAdminControlled { + fn get_paused(&self) -> PausedMask { + self.mask + } + + fn set_paused(&mut self, paused: PausedMask) { + self.mask = paused + } + } + + #[test] + fn test_setting_paused_mask_with_1_bit_marks_it_as_paused() { + let is_owner = false; + let mask = 1u8; + let mut admin_controlled = MockAdminControlled::new(); + + assert!(!admin_controlled.is_paused(mask, is_owner)); + admin_controlled.set_paused(mask); + assert!(admin_controlled.is_paused(mask, is_owner)); + } + + #[test] + fn test_setting_paused_mask_with_0_bit_marks_it_as_not_paused() { + let is_owner = false; + let mask = 1u8; + let mut admin_controlled = MockAdminControlled::new(); + admin_controlled.set_paused(mask); + + assert!(admin_controlled.is_paused(mask, is_owner)); + admin_controlled.set_paused(0u8); + assert!(!admin_controlled.is_paused(mask, is_owner)); + } + + #[test] + fn test_setting_paused_mask_with_1_bit_fails_to_assert_not_paused() { + let is_owner = false; + let mask = 1u8; + let admin_controlled = MockAdminControlled::new(); + + let result = admin_controlled.assert_not_paused(mask, is_owner); + assert!(result.is_ok(), "asserting as paused failed"); + } + + #[test] + fn test_setting_paused_mask_with_0_bit_asserts_not_paused() { + let is_owner = false; + let mask = 1u8; + let mut admin_controlled = MockAdminControlled::new(); + + admin_controlled.set_paused(mask); + let error = admin_controlled + .assert_not_paused(mask, is_owner) + .expect_err("asserting as not paused failed"); + + let expected_error_message = b"ERR_PAUSED"; + let actual_error_message = error.as_ref(); + assert_eq!(expected_error_message, actual_error_message); + } + + #[test] + fn test_paused_mask_has_no_effect_on_owner() { + let is_owner = true; + let mask = 1u8; + let mut admin_controlled = MockAdminControlled::new(); + + admin_controlled.set_paused(mask); + assert!(!admin_controlled.is_paused(mask, is_owner)); + } + + #[test] + fn test_asserting_paused_mask_has_no_effect_on_owner() { + let is_owner = true; + let mask = 1u8; + let mut admin_controlled = MockAdminControlled::new(); + + admin_controlled.set_paused(mask); + let result = admin_controlled.assert_not_paused(mask, is_owner); + assert!(result.is_ok(), "asserting as not paused failed"); + } +} diff --git a/engine/src/connector.rs b/engine/src/connector.rs index 2fdadcdaa..60bcc141d 100644 --- a/engine/src/connector.rs +++ b/engine/src/connector.rs @@ -142,19 +142,19 @@ impl EthConnectorContract { let event = DepositedEvent::from_log_entry_data(&proof.log_entry_data) .map_err(error::DepositError::EventParseFailed)?; - sdk::log!(&format!( + sdk::log!( "Deposit started: from {} to recipient {:?} with amount: {:?} and fee {:?}", event.sender.encode(), - event.token_message_data.get_recipient(), + event.token_message_data.recipient(), event.amount, event.fee - )); + ); - sdk::log!(&format!( + sdk::log!( "Event's address {}, custodian address {}", event.eth_custodian_address.encode(), self.contract.eth_custodian_address.encode(), - )); + ); if event.eth_custodian_address != self.contract.eth_custodian_address { return Err(error::DepositError::CustodianAddressMismatch); @@ -165,10 +165,10 @@ impl EthConnectorContract { } // Verify proof data with cross-contract call to prover account - sdk::log!(&format!( + sdk::log!( "Deposit verify_log_entry for prover: {}", self.contract.prover_account, - )); + ); // Do not skip bridge call. This is only used for development and diagnostics. let skip_bridge_call = false.try_to_vec().unwrap(); @@ -189,7 +189,7 @@ impl EthConnectorContract { TokenMessageData::Near(account_id) => FinishDepositCallArgs { new_owner_id: account_id, amount: event.amount, - proof_key: proof.get_key(), + proof_key: proof.key(), relayer_id: predecessor_account_id, fee: event.fee, msg: None, @@ -217,7 +217,7 @@ impl EthConnectorContract { FinishDepositCallArgs { new_owner_id: current_account_id.clone(), amount: event.amount, - proof_key: proof.get_key(), + proof_key: proof.key(), relayer_id: predecessor_account_id, fee: event.fee, msg: Some(transfer_data), @@ -252,7 +252,7 @@ impl EthConnectorContract { data: FinishDepositCallArgs, prepaid_gas: NearGas, ) -> Result, error::FinishDepositError> { - sdk::log!(&format!("Finish deposit with the amount: {}", data.amount)); + sdk::log!("Finish deposit with the amount: {}", data.amount); // Mint tokens to recipient minus fee if let Some(msg) = data.msg { @@ -297,7 +297,7 @@ impl EthConnectorContract { /// Record used proof as hash key fn record_proof(&mut self, key: &str) -> Result<(), error::ProofUsed> { - sdk::log!(&format!("Record proof: {}", key)); + sdk::log!("Record proof: {}", key); if self.is_used_event(key) { return Err(error::ProofUsed); @@ -313,7 +313,7 @@ impl EthConnectorContract { owner_id: AccountId, amount: NEP141Wei, ) -> Result<(), fungible_token::error::DepositError> { - sdk::log!(&format!("Mint {} nETH tokens for: {}", amount, owner_id)); + sdk::log!("Mint {} nETH tokens for: {}", amount, owner_id); if self.ft.get_account_eth_balance(&owner_id).is_none() { self.ft.accounts_insert(&owner_id, ZERO_NEP141_WEI); @@ -327,11 +327,7 @@ impl EthConnectorContract { owner_id: Address, amount: Wei, ) -> Result<(), fungible_token::error::DepositError> { - sdk::log!(&format!( - "Mint {} ETH tokens for: {}", - amount, - owner_id.encode() - )); + sdk::log!("Mint {} ETH tokens for: {}", amount, owner_id.encode()); self.ft.internal_deposit_eth_to_aurora(owner_id, amount) } @@ -373,7 +369,7 @@ impl EthConnectorContract { /// Returns total ETH supply on NEAR (nETH as NEP-141 token) pub fn ft_total_eth_supply_on_near(&mut self) { let total_supply = self.ft.ft_total_eth_supply_on_near(); - sdk::log!(&format!("Total ETH supply on NEAR: {}", total_supply)); + sdk::log!("Total ETH supply on NEAR: {}", total_supply); self.io .return_output(format!("\"{}\"", total_supply).as_bytes()); } @@ -381,7 +377,7 @@ impl EthConnectorContract { /// Returns total ETH supply on Aurora (ETH in Aurora EVM) pub fn ft_total_eth_supply_on_aurora(&mut self) { let total_supply = self.ft.ft_total_eth_supply_on_aurora(); - sdk::log!(&format!("Total ETH supply on Aurora: {}", total_supply)); + sdk::log!("Total ETH supply on Aurora: {}", total_supply); self.io .return_output(format!("\"{}\"", total_supply).as_bytes()); } @@ -389,10 +385,7 @@ impl EthConnectorContract { /// Return balance of nETH (ETH on Near) pub fn ft_balance_of(&mut self, args: BalanceOfCallArgs) { let balance = self.ft.ft_balance_of(&args.account_id); - sdk::log!(&format!( - "Balance of nETH [{}]: {}", - args.account_id, balance - )); + sdk::log!("Balance of nETH [{}]: {}", args.account_id, balance); self.io.return_output(format!("\"{}\"", balance).as_bytes()); } @@ -405,11 +398,7 @@ impl EthConnectorContract { let balance = self .ft .internal_unwrap_balance_of_eth_on_aurora(&args.address); - sdk::log!(&format!( - "Balance of ETH [{}]: {}", - args.address.encode(), - balance - )); + sdk::log!("Balance of ETH [{}]: {}", args.address.encode(), balance); self.io.return_output(format!("\"{}\"", balance).as_bytes()); Ok(()) } @@ -427,10 +416,12 @@ impl EthConnectorContract { &args.memo, )?; self.save_ft_contract(); - sdk::log!(&format!( + sdk::log!( "Transfer amount {} to {} success with memo: {:?}", - args.amount, args.receiver_id, args.memo - )); + args.amount, + args.receiver_id, + args.memo + ); Ok(()) } @@ -446,10 +437,11 @@ impl EthConnectorContract { &args.receiver_id, args.amount, ); - sdk::log!(&format!( + sdk::log!( "Resolve transfer from {} to {} success", - args.sender_id, args.receiver_id - )); + args.sender_id, + args.receiver_id + ); // `ft_resolve_transfer` can change `total_supply` so we should save the contract self.save_ft_contract(); self.io.return_output(format!("\"{}\"", amount).as_bytes()); @@ -466,10 +458,11 @@ impl EthConnectorContract { args: TransferCallCallArgs, prepaid_gas: NearGas, ) -> Result { - sdk::log!(&format!( + sdk::log!( "Transfer call to {} amount {}", - args.receiver_id, args.amount, - )); + args.receiver_id, + args.amount, + ); // Verify message data before `ft_on_transfer` call to avoid verification panics // It's allowed empty message if `receiver_id =! current_account_id` @@ -650,7 +643,7 @@ impl EthConnectorContract { /// Checks whether the provided proof was already used pub fn is_used_proof(&self, proof: Proof) -> bool { - self.is_used_event(&proof.get_key()) + self.is_used_event(&proof.key()) } /// Get Eth connector paused flags diff --git a/engine/src/deposit_event.rs b/engine/src/deposit_event.rs index 055e139bd..50f09dfde 100644 --- a/engine/src/deposit_event.rs +++ b/engine/src/deposit_event.rs @@ -15,7 +15,7 @@ pub type EventParams = Vec; /// On-transfer message. Used for `ft_transfer_call` and `ft_on_transfer` functions. /// Message parsed from input args with `parse_on_transfer_message`. #[derive(BorshSerialize, BorshDeserialize)] -#[cfg_attr(not(target_arch = "wasm32"), derive(Debug))] +#[cfg_attr(not(target_arch = "wasm32"), derive(Debug, PartialEq, Eq))] pub struct FtTransferMessageData { pub relayer: AccountId, pub recipient: Address, @@ -85,12 +85,6 @@ impl FtTransferMessageData { fee: Fee, recipient: String, ) -> Result { - // The first data section should contain fee data. - // Pay attention, that for compatibility reasons we used U256 type - // it means 32 bytes for fee data - let mut data = U256::from(fee.as_u128()).as_byte_slice().to_vec(); - - // Check message length. let address = if recipient.len() == 42 { recipient .strip_prefix("0x") @@ -101,12 +95,10 @@ impl FtTransferMessageData { } else { recipient }; + let recipient_address = Address::decode(&address).map_err(ParseEventMessageError::EthAddressValidationError)?; - // Second data section should contain Eth address - data.extend(recipient_address.as_bytes()); - // Add `:` separator between relayer_id and data message - //Ok([relayer_account_id.as_ref(), &hex::encode(data)].join(":")) + Ok(Self { relayer: relayer_account_id.clone(), recipient: recipient_address, @@ -120,7 +112,7 @@ impl FtTransferMessageData { /// The message parsed from event `recipient` field - `log_entry_data` /// after fetching proof `log_entry_data` #[derive(BorshSerialize, BorshDeserialize)] -#[cfg_attr(not(target_arch = "wasm32"), derive(Debug))] +#[cfg_attr(not(target_arch = "wasm32"), derive(Debug, PartialEq, Eq))] pub enum TokenMessageData { /// Deposit no NEAR account Near(AccountId), @@ -168,7 +160,7 @@ impl TokenMessageData { } // Get recipient account id from Eth part of Token message data - pub fn get_recipient(&self) -> AccountId { + pub fn recipient(&self) -> AccountId { match self { Self::Near(acc) => acc.clone(), Self::Eth { @@ -218,6 +210,7 @@ impl EthEvent { } /// Data that was emitted by Deposited event. +#[cfg_attr(not(target_arch = "wasm32"), derive(Debug, PartialEq, Eq))] pub struct DepositedEvent { pub eth_custodian_address: Address, pub sender: Address, @@ -324,7 +317,6 @@ pub mod error { TooManyParts, InvalidAccount, EthAddressValidationError(AddressError), - ParseMessageError(ParseOnTransferMessageError), } impl AsRef<[u8]> for ParseEventMessageError { @@ -333,7 +325,6 @@ pub mod error { Self::TooManyParts => errors::ERR_INVALID_EVENT_MESSAGE_FORMAT, Self::InvalidAccount => errors::ERR_INVALID_ACCOUNT_ID, Self::EthAddressValidationError(e) => e.as_ref(), - Self::ParseMessageError(e) => e.as_ref(), } } } @@ -353,6 +344,7 @@ pub mod error { MessageParseFailed(ParseEventMessageError), OverflowNumber, } + impl AsRef<[u8]> for ParseError { fn as_ref(&self) -> &[u8] { match self { @@ -387,3 +379,217 @@ pub mod error { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::errors; + use aurora_engine_precompiles::make_address; + use aurora_engine_types::H160; + + #[test] + fn test_decoded_and_then_encoded_message_does_not_change() { + let expect_message = + "aurora:05000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + let message_data = + FtTransferMessageData::parse_on_transfer_message(expect_message).unwrap(); + let actual_message = message_data.encode(); + + assert_eq!(expect_message, actual_message); + } + + #[test] + fn test_parsing_message_with_incorrect_amount_of_parts() { + let message = "foo"; + let error = FtTransferMessageData::parse_on_transfer_message(message).unwrap_err(); + let expected_error_message = errors::ERR_INVALID_ON_TRANSFER_MESSAGE_FORMAT; + let actual_error_message = error.as_ref(); + + assert_eq!(expected_error_message, actual_error_message); + } + + #[test] + fn test_parsing_message_with_invalid_account_id() { + let message = "INVALID:0"; + let error = FtTransferMessageData::parse_on_transfer_message(message).unwrap_err(); + let expected_error_message = errors::ERR_INVALID_ACCOUNT_ID; + let actual_error_message = error.as_ref(); + + assert_eq!(expected_error_message, actual_error_message); + } + + #[test] + fn test_parsing_message_with_invalid_hex_data() { + let message = "foo:INVALID"; + let error = FtTransferMessageData::parse_on_transfer_message(message).unwrap_err(); + let expected_error_message = errors::ERR_INVALID_ON_TRANSFER_MESSAGE_HEX; + let actual_error_message = error.as_ref(); + + assert_eq!(expected_error_message, actual_error_message); + } + + #[test] + fn test_parsing_message_with_invalid_length_of_hex_data() { + let message = "foo:dead"; + let error = FtTransferMessageData::parse_on_transfer_message(message).unwrap_err(); + let expected_error_message = errors::ERR_INVALID_ON_TRANSFER_MESSAGE_DATA; + let actual_error_message = error.as_ref(); + + assert_eq!(expected_error_message, actual_error_message); + } + + #[test] + fn test_parsing_message_with_overflowing_fee() { + let message = + "foo:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + let error = FtTransferMessageData::parse_on_transfer_message(message).unwrap_err(); + let expected_error_message = errors::ERR_OVERFLOW_NUMBER; + let actual_error_message = error.as_ref(); + + assert_eq!(expected_error_message, actual_error_message); + } + + #[test] + fn test_eth_token_message_data_decodes_recipient_correctly() { + let fee = Fee::new(NEP141Wei::new(0)); + let address = Address::zero(); + let message = format!("aurora:{}", address.encode()); + + let token_message_data = + TokenMessageData::parse_event_message_and_prepare_token_message_data(&message, fee) + .unwrap(); + let actual_recipient = token_message_data.recipient().to_string(); + let expected_recipient = "aurora"; + + assert_eq!(expected_recipient, actual_recipient); + } + + #[test] + fn test_eth_token_message_data_decodes_recipient_correctly_with_prefix() { + let fee = Fee::new(NEP141Wei::new(0)); + let address = Address::zero(); + let message = format!("aurora:0x{}", address.encode()); + + let token_message_data = + TokenMessageData::parse_event_message_and_prepare_token_message_data(&message, fee) + .unwrap(); + let actual_recipient = token_message_data.recipient().to_string(); + let expected_recipient = "aurora"; + + assert_eq!(expected_recipient, actual_recipient); + } + + #[test] + fn test_near_token_message_data_decodes_recipient_correctly() { + let fee = Fee::new(NEP141Wei::new(0)); + let message = "aurora"; + + let token_message_data = + TokenMessageData::parse_event_message_and_prepare_token_message_data(message, fee) + .unwrap(); + let actual_recipient = token_message_data.recipient().to_string(); + let expected_recipient = "aurora"; + + assert_eq!(expected_recipient, actual_recipient); + } + + #[test] + fn test_token_message_data_fails_with_too_many_parts() { + let fee = Fee::new(NEP141Wei::new(0)); + let message = "aurora:foo:bar"; + + let parse_error = + TokenMessageData::parse_event_message_and_prepare_token_message_data(message, fee) + .unwrap_err(); + let actual_parse_error = parse_error.as_ref(); + let expected_parse_error = errors::ERR_INVALID_EVENT_MESSAGE_FORMAT; + + assert_eq!(expected_parse_error, actual_parse_error); + } + + #[test] + fn test_token_message_data_fails_with_invalid_account() { + let fee = Fee::new(NEP141Wei::new(0)); + let message = "INVALID"; + + let parse_error = + TokenMessageData::parse_event_message_and_prepare_token_message_data(message, fee) + .unwrap_err(); + let actual_parse_error = parse_error.as_ref(); + let expected_parse_error = errors::ERR_INVALID_ACCOUNT_ID; + + assert_eq!(expected_parse_error, actual_parse_error); + } + + #[test] + fn test_eth_token_message_data_fails_with_invalid_address_length() { + let fee = Fee::new(NEP141Wei::new(0)); + let message = "aurora:0xINVALID"; + + let parse_error = + TokenMessageData::parse_event_message_and_prepare_token_message_data(message, fee) + .unwrap_err(); + let actual_parse_error = std::str::from_utf8(parse_error.as_ref()).unwrap(); + let expected_parse_error = AddressError::IncorrectLength.to_string(); + + assert_eq!(expected_parse_error, actual_parse_error); + } + + #[test] + fn test_eth_token_message_data_fails_with_invalid_address() { + let fee = Fee::new(NEP141Wei::new(0)); + let message = "aurora:0xINVALID_ADDRESS_WITH_CORRECT_LENGTH_HERE"; + + let parse_error = + TokenMessageData::parse_event_message_and_prepare_token_message_data(message, fee) + .unwrap_err(); + let actual_parse_error = std::str::from_utf8(parse_error.as_ref()).unwrap(); + let expected_parse_error = AddressError::FailedDecodeHex.to_string(); + + assert_eq!(expected_parse_error, actual_parse_error); + } + + #[test] + fn test_deposited_event_parses_from_log_entry_successfully() { + let recipient_address = Address::zero(); + let eth_custodian_address = make_address(0xd045f7e1, 0x9b2488924b97f9c145b5e51d0d895a65); + + let fee = Fee::new(NEP141Wei::new(0)); + let message = ["aurora", ":", recipient_address.encode().as_str()].concat(); + let token_message_data: TokenMessageData = + TokenMessageData::parse_event_message_and_prepare_token_message_data(&message, fee) + .unwrap(); + + let expected_deposited_event = DepositedEvent { + eth_custodian_address, + sender: Address::new(H160([0u8; 20])), + token_message_data, + amount: NEP141Wei::new(0), + fee, + }; + + let event_schema = Event { + name: DEPOSITED_EVENT.into(), + inputs: DepositedEvent::event_params(), + anonymous: false, + }; + let log_entry = LogEntry { + address: eth_custodian_address.raw(), + topics: vec![ + event_schema.signature(), + // the sender is not important + crate::prelude::H256::zero(), + ], + data: ethabi::encode(&[ + ethabi::Token::String(message), + ethabi::Token::Uint(U256::from(expected_deposited_event.amount.as_u128())), + ethabi::Token::Uint(U256::from(expected_deposited_event.fee.as_u128())), + ]), + }; + + let log_entry_data = rlp::encode(&log_entry).to_vec(); + let actual_deposited_event = DepositedEvent::from_log_entry_data(&log_entry_data).unwrap(); + + assert_eq!(expected_deposited_event, actual_deposited_event); + } +} diff --git a/engine/src/engine.rs b/engine/src/engine.rs index 7172881fc..27c045213 100644 --- a/engine/src/engine.rs +++ b/engine/src/engine.rs @@ -14,6 +14,9 @@ use aurora_engine_sdk::promise::{PromiseHandler, PromiseId, ReadOnlyPromiseHandl use crate::accounting; use crate::parameters::{DeployErc20TokenArgs, NewCallArgs, TransactionStatus}; +use crate::pausables::{ + EngineAuthorizer, EnginePrecompilesPauser, PausedPrecompilesChecker, PrecompileFlags, +}; use crate::prelude::parameters::RefundCallArgs; use crate::prelude::precompiles::native::{exit_to_ethereum, exit_to_near}; use crate::prelude::precompiles::xcc::cross_contract_call; @@ -26,6 +29,7 @@ use crate::prelude::{ }; use aurora_engine_precompiles::PrecompileConstructorContext; use core::cell::RefCell; +use core::iter::once; /// Used as the first byte in the concatenation of data used to compute the blockhash. /// Could be useful in the future as a version byte, or to distinguish different types of blocks. @@ -348,42 +352,13 @@ impl AsRef<[u8]> for EngineStateError { } } -struct StackExecutorParams<'a, I, E, H> { +pub struct StackExecutorParams<'a, I, E, H> { precompiles: Precompiles<'a, I, E, H>, gas_limit: u64, } impl<'env, I: IO + Copy, E: Env, H: ReadOnlyPromiseHandler> StackExecutorParams<'env, I, E, H> { - fn new( - gas_limit: u64, - current_account_id: AccountId, - random_seed: H256, - io: I, - env: &'env E, - ro_promise_handler: H, - ) -> Self { - let precompiles = if cfg!(all(feature = "mainnet", not(feature = "integration-test"))) { - let mut tmp = Precompiles::new_london(PrecompileConstructorContext { - current_account_id, - random_seed, - io, - env, - promise_handler: ro_promise_handler, - }); - // Cross contract calls are not enabled on mainnet yet. - tmp.all_precompiles - .remove(&aurora_engine_precompiles::xcc::cross_contract_call::ADDRESS); - tmp - } else { - Precompiles::new_london(PrecompileConstructorContext { - current_account_id, - random_seed, - io, - env, - promise_handler: ro_promise_handler, - }) - }; - + fn new(gas_limit: u64, precompiles: Precompiles<'env, I, E, H>) -> Self { Self { precompiles, gas_limit, @@ -405,7 +380,7 @@ impl<'env, I: IO + Copy, E: Env, H: ReadOnlyPromiseHandler> StackExecutorParams< } } -#[derive(Debug, Default)] +#[derive(Debug, Default, PartialEq, Eq)] pub struct GasPaymentResult { pub prepaid_amount: Wei, pub effective_gas_price: U256, @@ -414,7 +389,7 @@ pub struct GasPaymentResult { /// Engine internal state, mostly configuration. /// Should not contain anything large or enumerable. -#[derive(BorshSerialize, BorshDeserialize, Default, Clone)] +#[derive(BorshSerialize, BorshDeserialize, Default, Clone, PartialEq, Eq, Debug)] pub struct EngineState { /// Chain id, according to the EIP-155 / ethereum-lists spec. pub chain_id: [u8; 32], @@ -541,14 +516,10 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { access_list: Vec<(H160, Vec)>, // See EIP-2930 handler: &mut P, ) -> EngineResult { - let executor_params = StackExecutorParams::new( - gas_limit, - self.current_account_id.clone(), - self.env.random_seed(), - self.io, - self.env, - handler.read_only(), - ); + let pause_flags = EnginePrecompilesPauser::from_io(self.io).paused(); + let precompiles = self.create_precompiles(pause_flags, handler); + + let executor_params = StackExecutorParams::new(gas_limit, precompiles); let mut executor = executor_params.make_executor(self); let address = executor.create_address(CreateScheme::Legacy { caller: origin.raw(), @@ -628,14 +599,10 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { access_list: Vec<(H160, Vec)>, // See EIP-2930 handler: &mut P, ) -> EngineResult { - let executor_params = StackExecutorParams::new( - gas_limit, - self.current_account_id.clone(), - self.env.random_seed(), - self.io, - self.env, - handler.read_only(), - ); + let pause_flags = EnginePrecompilesPauser::from_io(self.io).paused(); + let precompiles = self.create_precompiles(pause_flags, handler); + + let executor_params = StackExecutorParams::new(gas_limit, precompiles); let mut executor = executor_params.make_executor(self); let (exit_reason, result) = executor.transact_call( origin.raw(), @@ -669,7 +636,19 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { let origin = &args.sender; let contract = &args.address; let value = U256::from_big_endian(&args.amount); - self.view(origin, contract, Wei::new(value), args.input, u64::MAX) + // View calls cannot interact with promises + let mut handler = aurora_engine_sdk::promise::Noop; + let pause_flags = EnginePrecompilesPauser::from_io(self.io).paused(); + let precompiles = self.create_precompiles(pause_flags, &mut handler); + + let executor_params = StackExecutorParams::new(u64::MAX, precompiles); + self.view( + origin, + contract, + Wei::new(value), + args.input, + &executor_params, + ) } pub fn view( @@ -678,24 +657,15 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { contract: &Address, value: Wei, input: Vec, - gas_limit: u64, + executor_params: &StackExecutorParams, ) -> Result { - let executor_params = StackExecutorParams::new( - gas_limit, - self.current_account_id.clone(), - self.env.random_seed(), - self.io, - self.env, - // View calls cannot interact with promises - aurora_engine_sdk::promise::Noop, - ); let mut executor = executor_params.make_executor(self); let (status, result) = executor.transact_call( origin.raw(), contract.raw(), value.raw(), input, - gas_limit, + executor_params.gas_limit, Vec::new(), ); status.into_result(result) @@ -772,7 +742,6 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { pub fn receive_erc20_tokens( &mut self, token: &AccountId, - relayer_account_id: &AccountId, args: &NEP141FtOnTransferArgs, current_account_id: &AccountId, handler: &mut P, @@ -780,23 +749,18 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { let str_amount = crate::prelude::format!("\"{}\"", args.amount); let output_on_fail = str_amount.as_bytes(); - // Parse message to determine recipient and fee - let (recipient, fee) = { + // Parse message to determine recipient + let recipient = { // Message format: // Recipient of the transaction - 40 characters (Address in hex) - // Fee to be paid in ETH (Optional) - 64 characters (Encoded in big endian / hex) let message = args.msg.as_bytes(); assert_or_finish!(message.len() >= 40, output_on_fail, self.io); - let recipient = Address::new(H160(unwrap_res_or_finish!( + Address::new(H160(unwrap_res_or_finish!( hex::decode(&message[..40]).unwrap().as_slice().try_into(), output_on_fail, self.io - ))); - - let fee = U256::zero(); - - (recipient, fee) + ))) }; let erc20_token = Address::from_array(unwrap_res_or_finish!( @@ -811,39 +775,13 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { self.io )); - if fee != U256::from(0) { - let relayer_address = unwrap_res_or_finish!( - self.get_relayer(relayer_account_id.as_bytes()).ok_or(()), - output_on_fail, - self.io - ); - - unwrap_res_or_finish!( - self.transfer( - recipient, - relayer_address, - Wei::new_u64(fee.as_u64()), - u64::MAX, - handler, - ), - output_on_fail, - self.io - ); - } - - let selector = ERC20_MINT_SELECTOR; - let tail = ethabi::encode(&[ - ethabi::Token::Address(recipient.raw()), - ethabi::Token::Uint(U256::from(args.amount.as_u128())), - ]); - let erc20_admin_address = current_address(current_account_id); unwrap_res_or_finish!( self.call( &erc20_admin_address, &erc20_token, Wei::zero(), - [selector, tail.as_slice()].concat(), + setup_receive_erc20_tokens_input(args, &recipient), u64::MAX, Vec::new(), // TODO: are there values we should put here? handler, @@ -889,6 +827,57 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { // Everything succeed so return "0" self.io.return_output(b"\"0\""); } + + fn create_precompiles( + &self, + pause_flags: PrecompileFlags, + handler: &mut P, + ) -> Precompiles<'env, I, E, P::ReadOnly> { + let current_account_id = self.current_account_id.clone(); + let random_seed = self.env.random_seed(); + let io = self.io; + let env = self.env; + let ro_promise_handler = handler.read_only(); + + let precompiles = if cfg!(all(feature = "mainnet", not(feature = "integration-test"))) { + let mut tmp = Precompiles::new_london(PrecompileConstructorContext { + current_account_id, + random_seed, + io, + env, + promise_handler: ro_promise_handler, + }); + // Cross contract calls are not enabled on mainnet yet. + tmp.all_precompiles + .remove(&aurora_engine_precompiles::xcc::cross_contract_call::ADDRESS); + tmp + } else { + Precompiles::new_london(PrecompileConstructorContext { + current_account_id, + random_seed, + io, + env, + promise_handler: ro_promise_handler, + }) + }; + + Self::apply_pause_flags_to_precompiles(precompiles, pause_flags) + } + + fn apply_pause_flags_to_precompiles( + precompiles: Precompiles<'env, I, E, H>, + pause_flags: PrecompileFlags, + ) -> Precompiles<'env, I, E, H> { + Precompiles { + paused_precompiles: precompiles + .all_precompiles + .keys() + .filter(|address| pause_flags.is_paused_by_address(address)) + .copied() + .collect(), + all_precompiles: precompiles.all_precompiles, + } + } } pub fn submit( @@ -934,7 +923,7 @@ pub fn submit( // Retrieve the signer of the transaction: let sender = transaction.address; - sdk::log!(crate::prelude::format!("signer_address {:?}", sender).as_str()); + sdk::log!("signer_address {:?}", sender); check_nonce(&io, &sender, &transaction.nonce)?; @@ -1015,6 +1004,16 @@ pub fn submit( result } +pub fn setup_refund_on_error_input(amount: U256, refund_address: Address) -> Vec { + let selector = ERC20_MINT_SELECTOR; + let mint_args = ethabi::encode(&[ + ethabi::Token::Address(refund_address.raw()), + ethabi::Token::Uint(amount), + ]); + + [selector, mint_args.as_slice()].concat() +} + pub fn refund_on_error( io: I, env: &E, @@ -1032,18 +1031,13 @@ pub fn refund_on_error( let erc20_address = erc20_address; let refund_address = args.recipient_address; let amount = U256::from_big_endian(&args.amount); - - let selector = ERC20_MINT_SELECTOR; - let mint_args = ethabi::encode(&[ - ethabi::Token::Address(refund_address.raw()), - ethabi::Token::Uint(amount), - ]); + let input = setup_refund_on_error_input(amount, refund_address); engine.call( &erc20_admin_address, &erc20_address, Wei::zero(), - [selector, mint_args.as_slice()].concat(), + input, u64::MAX, Vec::new(), handler, @@ -1114,6 +1108,13 @@ pub fn set_state(io: &mut I, state: EngineState) { ); } +pub fn get_authorizer() -> EngineAuthorizer { + // TODO: a temporary account until the engine adapts std with near-plugins + let account = AccountId::new("aurora").expect("Failed to parse account from string"); + + EngineAuthorizer::from_accounts(once(account)) +} + pub fn refund_unused_gas( io: &mut I, sender: &Address, @@ -1146,6 +1147,37 @@ pub fn refund_unused_gas( Ok(()) } +pub fn setup_receive_erc20_tokens_input( + args: &NEP141FtOnTransferArgs, + recipient: &Address, +) -> Vec { + let selector = ERC20_MINT_SELECTOR; + let tail = ethabi::encode(&[ + ethabi::Token::Address(recipient.raw()), + ethabi::Token::Uint(U256::from(args.amount.as_u128())), + ]); + + [selector, tail.as_slice()].concat() +} + +pub fn setup_deploy_erc20_input(current_account_id: &AccountId) -> Vec { + #[cfg(feature = "error_refund")] + let erc20_contract = include_bytes!("../../etc/eth-contracts/res/EvmErc20V2.bin"); + #[cfg(not(feature = "error_refund"))] + let erc20_contract = include_bytes!("../../etc/eth-contracts/res/EvmErc20.bin"); + + let erc20_admin_address = current_address(current_account_id); + + let deploy_args = ethabi::encode(&[ + ethabi::Token::String("Empty".to_string()), + ethabi::Token::String("EMPTY".to_string()), + ethabi::Token::Uint(ethabi::Uint::from(0)), + ethabi::Token::Address(erc20_admin_address.raw()), + ]); + + ([erc20_contract, deploy_args.as_slice()].concat()).to_vec() +} + /// Used to bridge NEP-141 tokens from NEAR to Aurora. On Aurora the NEP-141 becomes an ERC-20. pub fn deploy_erc20_token( args: DeployErc20TokenArgs, @@ -1154,7 +1186,7 @@ pub fn deploy_erc20_token( handler: &mut P, ) -> Result { let current_account_id = env.current_account_id(); - let erc20_admin_address = current_address(¤t_account_id); + let input = setup_deploy_erc20_input(¤t_account_id); let mut engine = Engine::new( aurora_engine_sdk::types::near_account_to_evm_address( env.predecessor_account_id().as_bytes(), @@ -1165,23 +1197,7 @@ pub fn deploy_erc20_token( ) .map_err(DeployErc20Error::State)?; - #[cfg(feature = "error_refund")] - let erc20_contract = include_bytes!("../../etc/eth-contracts/res/EvmErc20V2.bin"); - #[cfg(not(feature = "error_refund"))] - let erc20_contract = include_bytes!("../../etc/eth-contracts/res/EvmErc20.bin"); - - let deploy_args = ethabi::encode(&[ - ethabi::Token::String("Empty".to_string()), - ethabi::Token::String("EMPTY".to_string()), - ethabi::Token::Uint(ethabi::Uint::from(0)), - ethabi::Token::Address(erc20_admin_address.raw()), - ]); - - let address = match Engine::deploy_code_with_input( - &mut engine, - (&[erc20_contract, deploy_args.as_slice()].concat()).to_vec(), - handler, - ) { + let address = match Engine::deploy_code_with_input(&mut engine, input, handler) { Ok(result) => match result.status { TransactionStatus::Succeed(ret) => { Address::new(H160(ret.as_slice().try_into().unwrap())) @@ -1191,7 +1207,7 @@ pub fn deploy_erc20_token( Err(e) => return Err(DeployErc20Error::Engine(e)), }; - sdk::log!(crate::prelude::format!("Deployed ERC-20 in Aurora at: {:#?}", address).as_str()); + sdk::log!("Deployed ERC-20 in Aurora at: {:#?}", address); engine .register_token(address, args.nep141) .map_err(DeployErc20Error::Register)?; @@ -1392,10 +1408,22 @@ where if log.topics.is_empty() { if let Ok(promise) = PromiseArgs::try_from_slice(&log.data) { match promise { - PromiseArgs::Create(promise) => schedule_promise(handler, &promise), + PromiseArgs::Create(promise) => { + // Safety: this promise creation is safe because it does not come from + // users directly. The exit precompiles only create promises which we + // are able to execute without violating any security invariants. + unsafe { schedule_promise(handler, &promise) } + } PromiseArgs::Callback(promise) => { - let base_id = schedule_promise(handler, &promise.base); - schedule_promise_callback(handler, base_id, &promise.callback) + // Safety: This is safe because the promise data comes from our own + // exit precompiles. See note above. + unsafe { + let base_id = schedule_promise(handler, &promise.base); + schedule_promise_callback(handler, base_id, &promise.callback) + } + } + PromiseArgs::Recursive(_) => { + unreachable!("Exit precompiles do not produce recursive promises") } }; } @@ -1433,25 +1461,28 @@ where .collect() } -fn schedule_promise(handler: &mut P, promise: &PromiseCreateArgs) -> PromiseId { - sdk::log!(&crate::prelude::format!( +unsafe fn schedule_promise( + handler: &mut P, + promise: &PromiseCreateArgs, +) -> PromiseId { + sdk::log!( "call_contract {}.{}", promise.target_account_id, promise.method - )); + ); handler.promise_create_call(promise) } -fn schedule_promise_callback( +unsafe fn schedule_promise_callback( handler: &mut P, base_id: PromiseId, promise: &PromiseCreateArgs, ) -> PromiseId { - sdk::log!(&crate::prelude::format!( + sdk::log!( "callback_call_contract {}.{}", promise.target_account_id, promise.method - )); + ); handler.promise_attach_callback(base_id, promise) } @@ -1657,12 +1688,7 @@ impl<'env, J: IO + Copy, E: Env> ApplyBackend for Engine<'env, J, E> { if let Some(code) = code { set_code(&mut self.io, &address, &code); code_bytes_written = code.len(); - sdk::log!(crate::prelude::format!( - "code_write_at_address {:?} {}", - address, - code_bytes_written, - ) - .as_str()); + sdk::log!("code_write_at_address {:?} {}", address, code_bytes_written); } let next_generation = if reset_storage { @@ -1708,9 +1734,7 @@ impl<'env, J: IO + Copy, E: Env> ApplyBackend for Engine<'env, J, E> { match accounting.net() { // Net loss is possible if `SELFDESTRUCT(self)` calls are made. accounting::Net::Lost(amount) => { - sdk::log!( - crate::prelude::format!("Burn {} ETH due to SELFDESTRUCT", amount).as_str() - ); + sdk::log!("Burn {} ETH due to SELFDESTRUCT", amount); // Apply changes for eth-connector. We ignore the `StorageReadError` intentionally since // if we cannot read the storage then there is nothing to remove. EthConnectorContract::init_instance(self.io) @@ -1740,10 +1764,577 @@ impl<'env, J: IO + Copy, E: Env> ApplyBackend for Engine<'env, J, E> { if code_bytes_written > 0 { writes_counter += 1; } - sdk::log!(crate::prelude::format!("total_writes_count {}", writes_counter).as_str()); - sdk::log!(crate::prelude::format!("total_written_bytes {}", total_bytes).as_str()); + sdk::log!( + "total_writes_count {}\ntotal_written_bytes {}", + writes_counter, + total_bytes + ); } } #[cfg(test)] -mod tests {} +mod tests { + use super::*; + use crate::parameters::{FunctionCallArgsV1, FunctionCallArgsV2}; + use aurora_engine_precompiles::make_address; + use aurora_engine_sdk::env::Fixed; + use aurora_engine_sdk::promise::Noop; + use aurora_engine_test_doubles::io::{Storage, StoragePointer}; + use aurora_engine_test_doubles::promise::PromiseTracker; + use aurora_engine_types::types::RawU256; + use sha3::{Digest, Keccak256}; + use std::sync::RwLock; + + #[test] + fn test_view_call_to_empty_contract_without_input_returns_empty_data() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + add_balance(&mut io, &origin, Wei::new_u64(22000)).unwrap(); + let engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let contract = make_address(1, 1); + let value = Wei::new_u64(1000); + let input = vec![]; + let args = ViewCallArgs { + sender: origin, + address: contract, + amount: RawU256::from(value.raw()), + input, + }; + let actual_status = engine.view_with_args(args).unwrap(); + let expected_status = TransactionStatus::Succeed(Vec::new()); + + assert_eq!(expected_status, actual_status); + } + + #[test] + fn test_deploying_code_with_empty_input_succeeds() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let io = StoragePointer(&storage); + let mut engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let input = vec![]; + let mut handler = Noop; + + let actual_result = engine.deploy_code_with_input(input, &mut handler).unwrap(); + + let nonce = U256::zero(); + let expected_address = create_legacy_address(origin.raw(), nonce).0.to_vec(); + let expected_status = TransactionStatus::Succeed(expected_address); + let expected_gas_used = 53000; + let expected_logs = Vec::new(); + let expected_result = SubmitResult::new(expected_status, expected_gas_used, expected_logs); + + assert_eq!(expected_result, actual_result); + } + + #[test] + fn test_call_to_empty_contract_returns_empty_data() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + add_balance(&mut io, &origin, Wei::new_u64(22000)).unwrap(); + let mut engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let input = Vec::::new(); + let mut handler = Noop; + let contract = make_address(1, 1); + let value = Wei::new_u64(1000); + let args = CallArgs::V2(FunctionCallArgsV2 { + contract, + value: RawU256::from(value.raw()), + input, + }); + let actual_result = engine.call_with_args(args, &mut handler).unwrap(); + + let expected_data = Vec::new(); + let expected_status = TransactionStatus::Succeed(expected_data); + let expected_gas_used = 21000; + let expected_logs = Vec::new(); + let expected_result = SubmitResult::new(expected_status, expected_gas_used, expected_logs); + + assert_eq!(expected_result, actual_result); + } + + #[test] + fn test_call_with_empty_balance_fails_with_out_of_funds_error() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let io = StoragePointer(&storage); + let mut engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let input = Vec::::new(); + let mut handler = Noop; + let contract = make_address(1, 1); + let value = Wei::new_u64(1000); + let args = CallArgs::V2(FunctionCallArgsV2 { + contract, + value: RawU256::from(value.raw()), + input, + }); + let actual_result = engine.call_with_args(args, &mut handler).unwrap(); + + let expected_status = TransactionStatus::OutOfFund; + let expected_gas_used = 21000; + let expected_logs = Vec::new(); + let expected_result = SubmitResult::new(expected_status, expected_gas_used, expected_logs); + + assert_eq!(expected_result, actual_result); + } + + #[test] + fn test_transfer_moves_balance_from_sender_to_recipient() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + add_balance(&mut io, &origin, Wei::new_u64(22000)).unwrap(); + let mut engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let gas_limit = u64::MAX; + let mut handler = Noop; + let receiver = make_address(1, 1); + let value = Wei::new_u64(1000); + let actual_result = engine + .transfer(origin, receiver, value, gas_limit, &mut handler) + .unwrap(); + + let expected_data = Vec::new(); + let expected_status = TransactionStatus::Succeed(expected_data); + let expected_gas_used = 21000; + let expected_logs = Vec::new(); + let expected_result = SubmitResult::new(expected_status, expected_gas_used, expected_logs); + + assert_eq!(expected_result, actual_result); + } + + #[test] + fn test_call_with_v1_args_to_empty_contract_returns_empty_data() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + add_balance(&mut io, &origin, Wei::new_u64(22000)).unwrap(); + let mut engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let input = Vec::::new(); + let mut handler = Noop; + let contract = make_address(1, 1); + let args = CallArgs::V1(FunctionCallArgsV1 { contract, input }); + let actual_result = engine.call_with_args(args, &mut handler).unwrap(); + + let expected_data = Vec::new(); + let expected_status = TransactionStatus::Succeed(expected_data); + let expected_gas_used = 21000; + let expected_logs = Vec::new(); + let expected_result = SubmitResult::new(expected_status, expected_gas_used, expected_logs); + + assert_eq!(expected_result, actual_result); + } + + #[test] + fn test_registering_relayer_succeeds() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + add_balance(&mut io, &origin, Wei::new_u64(22000)).unwrap(); + let mut engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let account_id = AccountId::new("relayer").unwrap(); + let expected_relayer_address = make_address(1, 1); + engine.register_relayer(account_id.as_bytes(), expected_relayer_address); + let actual_relayer_address = engine.get_relayer(account_id.as_bytes()).unwrap(); + + assert_eq!(expected_relayer_address, actual_relayer_address); + } + + #[test] + fn test_registering_token_succeeds() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + set_balance(&mut io, &origin, &Wei::new_u64(22000)); + let mut engine = Engine::new_with_state( + EngineState::default(), + origin, + current_account_id.clone(), + io, + &env, + ); + + let receiver = make_address(6, 6); + let erc20_token = make_address(4, 5); + let nep141_token = AccountId::new("testcoin").unwrap(); + let args = NEP141FtOnTransferArgs { + sender_id: Default::default(), + amount: Default::default(), + msg: receiver.encode(), + }; + let mut handler = Noop; + engine + .register_token(erc20_token, nep141_token.clone()) + .unwrap(); + engine.receive_erc20_tokens(&nep141_token, &args, ¤t_account_id, &mut handler); + + let storage_read = storage.read().unwrap(); + let actual_output = std::str::from_utf8(storage_read.output.as_slice()).unwrap(); + let expected_output = "\"0\""; + + assert_eq!(expected_output, actual_output); + } + + #[test] + fn test_deploying_token_succeeds() { + let env = Fixed::default(); + let origin = aurora_engine_sdk::types::near_account_to_evm_address( + env.predecessor_account_id().as_bytes(), + ); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + add_balance(&mut io, &origin, Wei::new_u64(22000)).unwrap(); + set_state(&mut io, EngineState::default()); + + let nep141_token = AccountId::new("testcoin").unwrap(); + let mut handler = Noop; + let args = DeployErc20TokenArgs { + nep141: nep141_token, + }; + let nonce = U256::zero(); + let expected_address = Address::new(create_legacy_address(origin.raw(), nonce)); + let actual_address = deploy_erc20_token(args, io, &env, &mut handler).unwrap(); + + assert_eq!(expected_address, actual_address); + } + + #[test] + fn test_gas_charge_for_empty_transaction_is_zero() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + add_balance(&mut io, &origin, Wei::new_u64(22000)).unwrap(); + let mut engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let transaction = NormalizedEthTransaction { + address: Default::default(), + chain_id: None, + nonce: Default::default(), + gas_limit: U256::MAX, + max_priority_fee_per_gas: Default::default(), + max_fee_per_gas: U256::MAX, + to: None, + value: Default::default(), + data: vec![], + access_list: vec![], + }; + let actual_result = engine.charge_gas(&origin, &transaction).unwrap(); + + let expected_result = GasPaymentResult { + prepaid_amount: Wei::zero(), + effective_gas_price: U256::zero(), + priority_fee_per_gas: U256::zero(), + }; + + assert_eq!(expected_result, actual_result); + } + + #[test] + fn test_scheduling_promise_creates_it() { + use aurora_engine_test_doubles::promise::PromiseArgs; + use std::collections::HashMap; + + let mut promise_tracker = PromiseTracker::default(); + let args = PromiseCreateArgs { + target_account_id: Default::default(), + method: "".to_string(), + args: vec![], + attached_balance: Default::default(), + attached_gas: Default::default(), + }; + // This is safe because it's just a test + let actual_id = unsafe { schedule_promise(&mut promise_tracker, &args) }; + let actual_scheduled_promises = promise_tracker.scheduled_promises; + let expected_scheduled_promises = { + let mut map = HashMap::new(); + map.insert(actual_id.raw(), PromiseArgs::Create(args)); + map + }; + + assert_eq!(expected_scheduled_promises, actual_scheduled_promises); + } + + #[test] + fn test_scheduling_promise_callback_adds_it() { + use aurora_engine_test_doubles::promise::PromiseArgs; + use std::collections::HashMap; + + let mut promise_tracker = PromiseTracker::default(); + let args = PromiseCreateArgs { + target_account_id: Default::default(), + method: "".to_string(), + args: vec![], + attached_balance: Default::default(), + attached_gas: Default::default(), + }; + let base_id = PromiseId::new(6); + // This is safe because it's just a test + let actual_id = unsafe { schedule_promise_callback(&mut promise_tracker, base_id, &args) }; + let actual_scheduled_promises = promise_tracker.scheduled_promises; + let expected_scheduled_promises = { + let mut map = HashMap::new(); + map.insert( + actual_id.raw(), + PromiseArgs::Callback { + base: base_id, + callback: args, + }, + ); + map + }; + + assert_eq!(expected_scheduled_promises, actual_scheduled_promises); + } + + #[test] + fn test_loading_original_storage_loads_stored_value() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + let engine = + Engine::new_with_state(EngineState::default(), origin, current_account_id, io, &env); + + let expected_value = H256::from_low_u64_le(64); + let index = H256::zero(); + let generation = get_generation(&io, &origin); + set_storage(&mut io, &origin, &index, &expected_value, generation); + let actual_value = engine.original_storage(origin.raw(), index).unwrap(); + + assert_eq!(expected_value, actual_value); + } + + #[test] + fn test_loading_engine_from_storage_loads_stored_state() { + let origin = Address::zero(); + let current_account_id = AccountId::default(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + let expected_state = EngineState::default(); + set_state(&mut io, expected_state.clone()); + let engine = Engine::new(origin, current_account_id, io, &env).unwrap(); + let actual_state = engine.state; + + assert_eq!(expected_state, actual_state); + } + + #[test] + fn test_refund_transfer_eth_back_from_precompile_address() { + let recipient_address = make_address(1, 1); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + let expected_state = EngineState::default(); + let refund_amount = Wei::new_u64(1000); + add_balance(&mut io, &exit_to_near::ADDRESS, refund_amount).unwrap(); + set_state(&mut io, expected_state.clone()); + let args = RefundCallArgs { + recipient_address, + erc20_address: None, + amount: RawU256::from(refund_amount.raw()), + }; + let mut handler = Noop; + let actual_result = refund_on_error(io, &env, expected_state, args, &mut handler).unwrap(); + let expected_result = + SubmitResult::new(TransactionStatus::Succeed(Vec::new()), 25800, Vec::new()); + + assert_eq!(expected_result, actual_result); + } + + #[test] + fn test_refund_remint_burned_erc20_tokens() { + let origin = Address::zero(); + let env = Fixed::default(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + let expected_state = EngineState::default(); + set_state(&mut io, expected_state.clone()); + let value = Wei::new_u64(1000); + let args = RefundCallArgs { + recipient_address: Default::default(), + erc20_address: Some(origin), + amount: RawU256::from(value.raw()), + }; + let mut handler = Noop; + let actual_result = refund_on_error(io, &env, expected_state, args, &mut handler).unwrap(); + let expected_result = + SubmitResult::new(TransactionStatus::Succeed(Vec::new()), 21344, Vec::new()); + + assert_eq!(expected_result, actual_result); + } + + #[test] + fn test_refund_free_effective_gas_does_nothing() { + let origin = Address::zero(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + let expected_state = EngineState::default(); + set_state(&mut io, expected_state); + let relayer = make_address(1, 1); + let gas_result = GasPaymentResult { + prepaid_amount: Default::default(), + effective_gas_price: U256::zero(), + priority_fee_per_gas: U256::zero(), + }; + + refund_unused_gas(&mut io, &origin, 1000, gas_result, &relayer).unwrap(); + } + + #[test] + fn test_refund_gas_pays_expected_amount() { + let origin = Address::zero(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + let expected_state = EngineState::default(); + set_state(&mut io, expected_state); + let relayer = make_address(1, 1); + let gas_result = GasPaymentResult { + prepaid_amount: Wei::new_u64(8000), + effective_gas_price: Wei::new_u64(1).raw(), + priority_fee_per_gas: U256::zero(), + }; + let gas_used = 4000; + + refund_unused_gas(&mut io, &origin, gas_used, gas_result, &relayer).unwrap(); + + let actual_refund = get_balance(&io, &origin); + let expected_refund = Wei::new_u64(gas_used); + + assert_eq!(expected_refund, actual_refund); + } + + #[test] + fn test_check_nonce_with_increment_succeeds() { + let origin = Address::zero(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + + increment_nonce(&mut io, &origin); + check_nonce(&io, &origin, &U256::from(1u64)).unwrap(); + } + + #[test] + fn test_check_nonce_without_increment_fails() { + let origin = Address::zero(); + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + + increment_nonce(&mut io, &origin); + let actual_error_kind = check_nonce(&io, &origin, &U256::from(0u64)).unwrap_err(); + let actual_error_kind = std::str::from_utf8(actual_error_kind.as_bytes()).unwrap(); + let expected_error_kind = std::str::from_utf8(errors::ERR_INCORRECT_NONCE).unwrap(); + + assert_eq!(expected_error_kind, actual_error_kind); + } + + #[test] + fn test_missing_engine_state_is_not_found() { + let storage = Storage::default(); + let storage = RwLock::new(storage); + let io = StoragePointer(&storage); + + let actual_error = get_state(&io).unwrap_err(); + let actual_error = std::str::from_utf8(actual_error.as_ref()).unwrap(); + let expected_error = std::str::from_utf8(errors::ERR_STATE_NOT_FOUND).unwrap(); + + assert_eq!(expected_error, actual_error); + } + + #[test] + fn test_empty_engine_state_is_corrupted() { + let storage = Storage::default(); + let storage = RwLock::new(storage); + let mut io = StoragePointer(&storage); + + io.write_storage(&bytes_to_key(KeyPrefix::Config, STATE_KEY), &[]); + let actual_error = get_state(&io).unwrap_err(); + let actual_error = std::str::from_utf8(actual_error.as_ref()).unwrap(); + let expected_error = std::str::from_utf8(errors::ERR_STATE_CORRUPTED).unwrap(); + + assert_eq!(expected_error, actual_error); + } + + #[test] + fn test_filtering_promises_from_logs_with_none_keeps_all() { + let storage = Storage::default(); + let storage = RwLock::new(storage); + let io = StoragePointer(&storage); + let current_account_id = AccountId::default(); + let mut handler = Noop; + let logs = vec![Log { + address: Default::default(), + topics: vec![], + data: vec![], + }]; + + let actual_logs = filter_promises_from_logs(&io, &mut handler, logs, ¤t_account_id); + let expected_logs = vec![ResultLog { + address: Default::default(), + topics: vec![], + data: vec![], + }]; + + assert_eq!(expected_logs, actual_logs); + } + + fn create_legacy_address(address: H160, nonce: U256) -> H160 { + let mut stream = rlp::RlpStream::new_list(2); + stream.append(&address); + stream.append(&nonce); + H256::from_slice(Keccak256::digest(&stream.out()).as_slice()).into() + } +} diff --git a/engine/src/fungible_token.rs b/engine/src/fungible_token.rs index fd73dc778..045e68aec 100644 --- a/engine/src/fungible_token.rs +++ b/engine/src/fungible_token.rs @@ -250,15 +250,10 @@ impl FungibleTokenOps { } self.internal_withdraw_eth_from_near(sender_id, amount)?; self.internal_deposit_eth_to_near(receiver_id, amount)?; - sdk::log!(&crate::prelude::format!( - "Transfer {} from {} to {}", - amount, - sender_id, - receiver_id - )); + sdk::log!("Transfer {} from {} to {}", amount, sender_id, receiver_id); #[cfg(feature = "log")] if let Some(memo) = memo { - sdk::log!(&crate::prelude::format!("Memo: {}", memo)); + sdk::log!("Memo: {}", memo); } Ok(()) } @@ -373,20 +368,20 @@ impl FungibleTokenOps { receiver_balance }; self.accounts_insert(receiver_id, receiver_balance - refund_amount); - sdk::log!(&crate::prelude::format!( + sdk::log!( "Decrease receiver {} balance to: {}", receiver_id, receiver_balance - refund_amount - )); + ); return if let Some(sender_balance) = self.get_account_eth_balance(sender_id) { self.accounts_insert(sender_id, sender_balance + refund_amount); - sdk::log!(&crate::prelude::format!( + sdk::log!( "Refund amount {} from {} to {}", refund_amount, receiver_id, sender_id - )); + ); (amount - refund_amount, ZERO_NEP141_WEI) } else { // Sender's account was deleted, so we need to burn tokens. @@ -434,10 +429,7 @@ impl FungibleTokenOps { Err(error::StorageFundingError::UnRegisterPositiveBalance) } } else { - sdk::log!(&crate::prelude::format!( - "The account {} is not registered", - account_id - )); + sdk::log!("The account {} is not registered", account_id); Err(error::StorageFundingError::NotRegistered) } } diff --git a/engine/src/json.rs b/engine/src/json.rs index 2759a82b3..ad06710a4 100644 --- a/engine/src/json.rs +++ b/engine/src/json.rs @@ -25,7 +25,6 @@ pub enum JsonError { InvalidU128, InvalidBool, InvalidString, - InvalidArray, ExpectedStringGotNumber, OutOfRange(JsonOutOfRangeError), } @@ -108,7 +107,6 @@ impl AsRef<[u8]> for JsonError { Self::InvalidU128 => errors::ERR_FAILED_PARSE_U128, Self::InvalidBool => errors::ERR_FAILED_PARSE_BOOL, Self::InvalidString => errors::ERR_FAILED_PARSE_STRING, - Self::InvalidArray => errors::ERR_FAILED_PARSE_ARRAY, Self::ExpectedStringGotNumber => errors::ERR_EXPECTED_STRING_GOT_NUMBER, Self::OutOfRange(err) => err.as_ref(), } @@ -124,23 +122,6 @@ impl AsRef<[u8]> for JsonOutOfRangeError { } } -#[cfg(test)] -impl std::fmt::Debug for JsonError { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - f.write_fmt(format_args!( - "{}", - std::str::from_utf8(self.as_ref()).unwrap() - )) - } -} - -#[cfg(test)] -impl std::fmt::Display for JsonError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_fmt(format_args!("{:?}", *self)) - } -} - impl Array for JsonArray { fn new() -> Self { JsonArray(Vec::new()) @@ -275,42 +256,72 @@ impl core::fmt::Display for JsonValue { pub fn parse_json(data: &[u8]) -> Option { let data_array: Vec = data.iter().map(|b| char::from(*b)).collect::>(); let mut index = 0; - rjson::parse::(&*data_array, &mut index) + rjson::parse::(&data_array, &mut index) } #[cfg(test)] mod tests { use super::*; + #[test] + fn test_json_all_types_fail_to_parse_missing_key() { + let expected_err = std::str::from_utf8(errors::ERR_JSON_MISSING_VALUE).unwrap(); + let json = parse_json(r#"{"foo": 123}"#.as_bytes()).unwrap(); + + let actual_err = json.string("missing_key").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + + let actual_err = json.bool("missing_key").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + + let actual_err = json.u64("missing_key").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + + let actual_err = json.u128("missing_key").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + } + #[test] fn test_json_type_string() { let json = parse_json(r#"{"foo": "abcd"}"#.as_bytes()).unwrap(); let string_data = json.string("foo").ok().unwrap(); assert_eq!(string_data, "abcd"); + let expected_err = std::str::from_utf8(errors::ERR_FAILED_PARSE_STRING).unwrap(); let json = parse_json(r#"{"foo": 123}"#.as_bytes()).unwrap(); - let err = json.string("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidString); + let actual_err = json.string("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": true}"#.as_bytes()).unwrap(); - let err = json.string("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidString); + let actual_err = json.string("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": ["abcd"]}"#.as_bytes()).unwrap(); - let err = json.string("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidString); + let actual_err = json.string("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": {}}"#.as_bytes()).unwrap(); - let err = json.string("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidString); + let actual_err = json.string("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": null}"#.as_bytes()).unwrap(); - let err = json.string("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidString); + let actual_err = json.string("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + let expected_err = std::str::from_utf8(errors::ERR_NOT_A_JSON_TYPE).unwrap(); let json = JsonValue::Null; - let err = json.string("foo").unwrap_err(); - assert_eq!(err, JsonError::NotJsonType); + let actual_err = json.string("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); } #[test] @@ -329,41 +340,52 @@ mod tests { let val = json.u64("foo").ok().unwrap(); assert_eq!(val, u64::MAX); + let expected_err = std::str::from_utf8(errors::ERR_FAILED_PARSE_U64).unwrap(); let json = parse_json(r#"{"foo": 12.99}"#.as_bytes()).unwrap(); - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU64); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": -123}"#.as_bytes()).unwrap(); - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU64); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": "abcd"}"#.as_bytes()).unwrap(); - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU64); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": "123"}"#.as_bytes()).unwrap(); - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU64); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": true}"#.as_bytes()).unwrap(); - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU64); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": [123]}"#.as_bytes()).unwrap(); - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU64); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": {}}"#.as_bytes()).unwrap(); - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU64); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": null}"#.as_bytes()).unwrap(); - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU64); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + let expected_err = std::str::from_utf8(errors::ERR_NOT_A_JSON_TYPE).unwrap(); let json = JsonValue::Null; - let err = json.u64("foo").unwrap_err(); - assert_eq!(err, JsonError::NotJsonType); + let actual_err = json.u64("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); } #[test] @@ -372,95 +394,118 @@ mod tests { let val = json.u128("foo").ok().unwrap(); assert_eq!(val, 123); + let expected_err = + std::str::from_utf8(JsonOutOfRangeError::OutOfRangeU128.as_ref()).unwrap(); let json = parse_json(r#"{"foo": "-123"}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!( - err, - JsonError::OutOfRange(JsonOutOfRangeError::OutOfRangeU128) - ); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + let expected_err = std::str::from_utf8(errors::ERR_EXPECTED_STRING_GOT_NUMBER).unwrap(); let json = parse_json(r#"{"foo": 123}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::ExpectedStringGotNumber); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": 12.3}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::ExpectedStringGotNumber); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + let expected_err = std::str::from_utf8(errors::ERR_FAILED_PARSE_U128).unwrap(); let json = parse_json(r#"{"foo": "12.3"}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU128); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": "abcd"}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU128); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": true}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU128); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": ["123"]}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU128); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": {}}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU128); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": null}"#.as_bytes()).unwrap(); - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidU128); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + let expected_err = std::str::from_utf8(errors::ERR_NOT_A_JSON_TYPE).unwrap(); let json = JsonValue::Null; - let err = json.u128("foo").unwrap_err(); - assert_eq!(err, JsonError::NotJsonType); + let actual_err = json.u128("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); } #[test] fn test_json_type_bool() { let json = parse_json(r#"{"foo": true}"#.as_bytes()).unwrap(); let val = json.bool("foo").ok().unwrap(); - assert_eq!(val, true); + assert!(val); let json = parse_json(r#"{"foo": false}"#.as_bytes()).unwrap(); let val = json.bool("foo").ok().unwrap(); - assert_eq!(val, false); + assert!(!val); + let expected_err = std::str::from_utf8(errors::ERR_FAILED_PARSE_BOOL).unwrap(); let json = parse_json(r#"{"foo": "true"}"#.as_bytes()).unwrap(); - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidBool); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": "false"}"#.as_bytes()).unwrap(); - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidBool); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": [true]}"#.as_bytes()).unwrap(); - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidBool); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": 123}"#.as_bytes()).unwrap(); - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidBool); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": 12.3}"#.as_bytes()).unwrap(); - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidBool); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": "abcd"}"#.as_bytes()).unwrap(); - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidBool); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": {}}"#.as_bytes()).unwrap(); - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidBool); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); let json = parse_json(r#"{"foo": null}"#.as_bytes()).unwrap(); - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::InvalidBool); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + let expected_err = std::str::from_utf8(errors::ERR_NOT_A_JSON_TYPE).unwrap(); let json = JsonValue::Null; - let err = json.bool("foo").unwrap_err(); - assert_eq!(err, JsonError::NotJsonType); + let actual_err = json.bool("foo").unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); } #[test] @@ -469,20 +514,23 @@ mod tests { let val = JsonValue::parse_u8(&json).ok().unwrap(); assert_eq!(val, 123); + let expected_err = std::str::from_utf8(errors::ERR_FAILED_PARSE_U8).unwrap(); let json = JsonValue::from(-1_i64); - let err = JsonValue::parse_u8(&json).unwrap_err(); - assert_eq!(err, JsonError::InvalidU8); + let actual_err = JsonValue::parse_u8(&json).unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + let expected_err = std::str::from_utf8(JsonOutOfRangeError::OutOfRangeU8.as_ref()).unwrap(); let json = JsonValue::from(256_u64); - let err = JsonValue::parse_u8(&json).unwrap_err(); - assert_eq!( - err, - JsonError::OutOfRange(JsonOutOfRangeError::OutOfRangeU8) - ); + let actual_err = JsonValue::parse_u8(&json).unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); + let expected_err = std::str::from_utf8(errors::ERR_FAILED_PARSE_U8).unwrap(); let json = JsonValue::from("abcd".to_string()); - let err = JsonValue::parse_u8(&json).unwrap_err(); - assert_eq!(err, JsonError::InvalidU8); + let actual_err = JsonValue::parse_u8(&json).unwrap_err(); + let actual_err = std::str::from_utf8(actual_err.as_ref()).unwrap(); + assert_eq!(actual_err, expected_err); } #[test] diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 96be012ff..ff133643a 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -27,6 +27,7 @@ pub mod errors; pub mod fungible_token; pub mod json; pub mod log_entry; +pub mod pausables; mod prelude; pub mod xcc; @@ -71,17 +72,21 @@ mod contract { use crate::connector::{self, EthConnectorContract}; use crate::engine::{self, Engine, EngineState}; - use crate::errors; use crate::fungible_token::FungibleTokenMetadata; use crate::json::parse_json; use crate::parameters::{ self, CallArgs, DeployErc20TokenArgs, GetErc20FromNep141CallArgs, GetStorageAtArgs, InitCallArgs, IsUsedProofCallArgs, NEP141FtOnTransferArgs, NewCallArgs, - PauseEthConnectorCallArgs, ResolveTransferCallArgs, SetContractDataCallArgs, - StorageDepositCallArgs, StorageWithdrawCallArgs, TransferCallCallArgs, ViewCallArgs, + PauseEthConnectorCallArgs, PausePrecompilesCallArgs, ResolveTransferCallArgs, + SetContractDataCallArgs, StorageDepositCallArgs, StorageWithdrawCallArgs, + TransferCallCallArgs, ViewCallArgs, }; #[cfg(feature = "evm_bully")] use crate::parameters::{BeginBlockArgs, BeginChainArgs}; + use crate::pausables::{ + Authorizer, EnginePrecompilesPauser, PausedPrecompilesChecker, PausedPrecompilesManager, + PrecompileFlags, + }; use crate::prelude::account_id::AccountId; use crate::prelude::parameters::RefundCallArgs; use crate::prelude::sdk::types::{ @@ -91,6 +96,7 @@ mod contract { use crate::prelude::{ sdk, u256_to_arr, Address, PromiseResult, ToString, Yocto, ERR_FAILED_PARSE, H256, }; + use crate::{errors, pausables}; use aurora_engine_sdk::env::Env; use aurora_engine_sdk::io::{StorageIntermediate, IO}; use aurora_engine_sdk::near_runtime::{Runtime, ViewEnv}; @@ -196,6 +202,49 @@ mod contract { // TODO: currently we don't have migrations } + /// Resumes previously [`paused`] precompiles. + /// + /// [`paused`]: crate::contract::pause_precompiles + #[no_mangle] + pub extern "C" fn resume_precompiles() { + let io = Runtime; + let state = engine::get_state(&io).sdk_unwrap(); + let predecessor_account_id = io.predecessor_account_id(); + + require_owner_only(&state, &predecessor_account_id); + + let args: PausePrecompilesCallArgs = io.read_input_borsh().sdk_unwrap(); + let flags = PrecompileFlags::from_bits_truncate(args.paused_mask); + let mut pauser = EnginePrecompilesPauser::from_io(io); + pauser.resume_precompiles(flags); + } + + /// Pauses a precompile. + #[no_mangle] + pub extern "C" fn pause_precompiles() { + let io = Runtime; + let authorizer: pausables::EngineAuthorizer = engine::get_authorizer(); + + if !authorizer.is_authorized(&io.predecessor_account_id()) { + sdk::panic_utf8("ERR_UNAUTHORIZED".as_bytes()); + } + + let args: PausePrecompilesCallArgs = io.read_input_borsh().sdk_unwrap(); + let flags = PrecompileFlags::from_bits_truncate(args.paused_mask); + let mut pauser = EnginePrecompilesPauser::from_io(io); + pauser.pause_precompiles(flags); + } + + /// Returns an unsigned integer where each 1-bit means that a precompile corresponding to that bit is paused and + /// 0-bit means not paused. + #[no_mangle] + pub extern "C" fn paused_precompiles() { + let mut io = Runtime; + let pauser = EnginePrecompilesPauser::from_io(io); + let data = pauser.paused().bits().to_le_bytes(); + io.return_output(&data[..]); + } + /// /// MUTATIVE METHODS /// @@ -302,6 +351,12 @@ mod contract { pub extern "C" fn factory_update_address_version() { let mut io = Runtime; io.assert_private_call().sdk_unwrap(); + let check_deploy: Result<(), &[u8]> = match io.promise_result(0) { + Some(PromiseResult::Successful(_)) => Ok(()), + Some(_) => Err(b"ERR_ROUTER_DEPLOY_FAILED"), + None => Err(b"ERR_ROUTER_UPDATE_NOT_CALLBACK"), + }; + check_deploy.sdk_unwrap(); let args: crate::xcc::AddressVersionUpdateArgs = io.read_input_borsh().sdk_unwrap(); crate::xcc::set_code_version_of_address(&mut io, &args.address, args.version); } @@ -346,10 +401,8 @@ mod contract { .ft_on_transfer(&engine, &args) .sdk_unwrap(); } else { - let signer_account_id = io.signer_account_id(); engine.receive_erc20_tokens( &predecessor_account_id, - &signer_account_id, &args, ¤t_account_id, &mut Runtime, @@ -556,7 +609,10 @@ mod contract { .sdk_unwrap() .deposit(raw_proof, current_account_id, predecessor_account_id) .sdk_unwrap(); - let promise_id = io.promise_create_with_callback(&promise_args); + // Safety: this call is safe because it comes from the eth-connector, not users. + // The call is to verify the user-supplied proof for the deposit, with `finish_deposit` + // as a callback. + let promise_id = unsafe { io.promise_create_with_callback(&promise_args) }; io.promise_return(promise_id); } @@ -593,7 +649,10 @@ mod contract { .sdk_unwrap(); if let Some(promise_args) = maybe_promise_args { - let promise_id = io.promise_create_with_callback(&promise_args); + // Safety: this call is safe because it comes from the eth-connector, not users. + // The call will be to the Engine's ft_transfer_call`, which is needed as part + // of the bridge flow (if depositing ETH to an Aurora address). + let promise_id = unsafe { io.promise_create_with_callback(&promise_args) }; io.promise_return(promise_id); } } @@ -710,7 +769,9 @@ mod contract { io.prepaid_gas(), ) .sdk_unwrap(); - let promise_id = io.promise_create_with_callback(&promise_args); + // Safety: this call is safe. It is required by the NEP-141 spec that `ft_transfer_call` + // creates a call to another contract's `ft_on_transfer` method. + let promise_id = unsafe { io.promise_create_with_callback(&promise_args) }; io.promise_return(promise_id); } @@ -725,7 +786,9 @@ mod contract { .storage_deposit(predecessor_account_id, amount, args) .sdk_unwrap(); if let Some(promise) = maybe_promise { - io.promise_create_batch(&promise); + // Safety: This call is safe. It is only a transfer back to the user in the case + // that they over paid for their deposit. + unsafe { io.promise_create_batch(&promise) }; } } @@ -740,7 +803,8 @@ mod contract { .storage_unregister(predecessor_account_id, force) .sdk_unwrap(); if let Some(promise) = maybe_promise { - io.promise_create_batch(&promise); + // Safety: This call is safe. It is only a transfer back to the user for their deposit. + unsafe { io.promise_create_batch(&promise) }; } } @@ -894,12 +958,15 @@ mod contract { attached_balance: ZERO_ATTACHED_BALANCE, attached_gas: GAS_FOR_FINISH, }; - io.promise_create_with_callback( - &aurora_engine_types::parameters::PromiseWithCallbackArgs { - base: verify_call, - callback: finish_call, - }, - ); + // Safety: this call is safe because it is only used in integration tests. + unsafe { + io.promise_create_with_callback( + &aurora_engine_types::parameters::PromiseWithCallbackArgs { + base: verify_call, + callback: finish_call, + }, + ) + }; } /// diff --git a/engine/src/log_entry.rs b/engine/src/log_entry.rs index da6db7a43..a4d74bee3 100644 --- a/engine/src/log_entry.rs +++ b/engine/src/log_entry.rs @@ -26,3 +26,31 @@ impl rlp::Encodable for LogEntry { stream.append(&self.data); } } + +#[cfg(test)] +mod tests { + use super::*; + use rlp::{Decodable, Encodable, Rlp, RlpStream}; + + #[test] + fn test_roundtrip_rlp_encoding() { + let address = H160::from_low_u64_le(32u64); + let topics = vec![H256::zero()]; + let data = vec![0u8, 1u8, 2u8, 3u8]; + let expected_log_entry = LogEntry { + address, + topics, + data, + }; + + let mut stream = RlpStream::new(); + + expected_log_entry.rlp_append(&mut stream); + + let bytes = stream.out(); + let rlp = Rlp::new(bytes.as_ref()); + let actual_log_entry = LogEntry::decode(&rlp).unwrap(); + + assert_eq!(expected_log_entry, actual_log_entry); + } +} diff --git a/engine/src/map.rs b/engine/src/map.rs index d3a54bea6..464f73f81 100644 --- a/engine/src/map.rs +++ b/engine/src/map.rs @@ -55,3 +55,39 @@ impl + TryFrom>, R: AsRef<[u8]> + TryFrom>, I: IO bytes_to_key(self.right_prefix, right.as_ref()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_map_finds_inserted_pair() { + use crate::engine::{ERC20Address, NEP141Account}; + use aurora_engine_test_doubles::io::{Storage, StoragePointer}; + use aurora_engine_types::account_id::AccountId; + use aurora_engine_types::types::Address; + use std::sync::RwLock; + + let storage = RwLock::new(Storage::default()); + let storage = StoragePointer(&storage); + let left_prefix = KeyPrefix::Nep141Erc20Map; + let right_prefix = KeyPrefix::Erc20Nep141Map; + + let mut map: BijectionMap = + BijectionMap::new(left_prefix, right_prefix, storage); + + let erc20_token = Address::zero(); + let nep141_token = AccountId::new("aurora").unwrap(); + let expected_left = NEP141Account(nep141_token); + let expected_right = ERC20Address(erc20_token); + map.insert(&expected_left, &expected_right); + + let actual_right = map.lookup_left(&expected_left).unwrap(); + + assert_eq!(expected_right.0, actual_right.0); + + let actual_left = map.lookup_right(&expected_right).unwrap(); + + assert_eq!(expected_left.0, actual_left.0); + } +} diff --git a/engine/src/parameters.rs b/engine/src/parameters.rs index caa9c5e08..4a6ecfa73 100644 --- a/engine/src/parameters.rs +++ b/engine/src/parameters.rs @@ -310,6 +310,18 @@ pub struct ResolveTransferCallArgs { pub receiver_id: AccountId, } +impl TryFrom for ResolveTransferCallArgs { + type Error = error::ParseTypeFromJsonError; + + fn try_from(v: JsonValue) -> Result { + Ok(Self { + sender_id: AccountId::try_from(v.string("sender_id")?)?, + receiver_id: AccountId::try_from(v.string("receiver_id")?)?, + amount: NEP141Wei::new(v.u128("amount")?), + }) + } +} + /// Finish deposit NEAR eth-connector call args #[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)] pub struct FinishDepositCallArgs { @@ -377,8 +389,9 @@ impl TryFrom for TransferCallCallArgs { /// storage_balance_of eth-connector call args #[derive(BorshSerialize, BorshDeserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct StorageBalanceOfCallArgs { - pub account_id: crate::prelude::account_id::AccountId, + pub account_id: AccountId, } impl TryFrom for StorageBalanceOfCallArgs { @@ -424,6 +437,7 @@ impl From for StorageWithdrawCallArgs { /// transfer args for json invocation #[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct TransferCallArgs { pub receiver_id: AccountId, pub amount: NEP141Wei, @@ -443,12 +457,14 @@ impl TryFrom for TransferCallArgs { } /// balance_of args for json invocation -#[derive(BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BalanceOfCallArgs { pub account_id: AccountId, } -#[derive(BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BalanceOfEthCallArgs { pub address: Address, } @@ -469,20 +485,14 @@ pub struct RegisterRelayerCallArgs { } #[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PauseEthConnectorCallArgs { pub paused_mask: PausedMask, } -impl TryFrom for ResolveTransferCallArgs { - type Error = error::ParseTypeFromJsonError; - - fn try_from(v: JsonValue) -> Result { - Ok(Self { - sender_id: AccountId::try_from(v.string("sender_id")?)?, - receiver_id: AccountId::try_from(v.string("receiver_id")?)?, - amount: NEP141Wei::new(v.u128("amount")?), - }) - } +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)] +pub struct PausePrecompilesCallArgs { + pub paused_mask: u32, } pub mod error { @@ -571,7 +581,7 @@ mod tests { // Using old input format (not wrapped into call args enum) - raw data structure with legacy arguments. let input_bytes = legacy_input.try_to_vec().unwrap(); let parsed_data = CallArgs::deserialize(&input_bytes); - assert_eq!(parsed_data, Some(CallArgs::V1(legacy_input.clone()))); + assert_eq!(parsed_data, Some(CallArgs::V1(legacy_input))); // Using old input format (not wrapped into call args enum) - raw data structure with new argument (`value` field). // Data structures with new arguments allowed only in new input format for future extensibility reason. diff --git a/engine/src/pausables.rs b/engine/src/pausables.rs new file mode 100644 index 000000000..297c237c9 --- /dev/null +++ b/engine/src/pausables.rs @@ -0,0 +1,252 @@ +use crate::prelude::{AccountId, Address, BTreeSet, Vec}; +use aurora_engine_precompiles::native::{exit_to_ethereum, exit_to_near}; +use aurora_engine_sdk::io::{StorageIntermediate, IO}; +use aurora_engine_types::storage::{bytes_to_key, KeyPrefix}; +use bitflags::bitflags; +use borsh::{BorshDeserialize, BorshSerialize}; + +bitflags! { + /// Wraps unsigned integer where each bit identifies a different precompile. + #[derive(BorshSerialize, BorshDeserialize, Default)] + pub struct PrecompileFlags: u32 { + const EXIT_TO_NEAR = 0b01; + const EXIT_TO_ETHEREUM = 0b10; + } +} + +impl PrecompileFlags { + pub fn from_address(address: &Address) -> Option { + Some(if address == &exit_to_ethereum::ADDRESS { + PrecompileFlags::EXIT_TO_ETHEREUM + } else if address == &exit_to_near::ADDRESS { + PrecompileFlags::EXIT_TO_NEAR + } else { + return None; + }) + } + + /// Checks if the precompile belonging to the `address` is marked as paused. + pub fn is_paused_by_address(&self, address: &Address) -> bool { + match Self::from_address(address) { + Some(precompile_flag) => self.contains(precompile_flag), + None => false, + } + } +} + +/// Can check if given account has a permission to pause precompiles. +pub trait Authorizer { + /// Checks if the `account` has the permission to pause precompiles. + fn is_authorized(&self, account: &AccountId) -> bool; +} + +/// Can check if a subset of precompiles is currently paused or not. +pub trait PausedPrecompilesChecker { + /// Checks if all of the `precompiles` are paused. + /// + /// The `precompiles` mask can be a subset and every 1 bit is meant to be checked and every 0 bit is ignored. + fn is_paused(&self, precompiles: PrecompileFlags) -> bool; + + /// Returns a set of all paused precompiles in a bitmask, where every 1 bit means paused and every 0 bit means + /// the opposite. + /// + /// To determine which bit belongs to what precompile, you have to match it with appropriate constant, for example + /// [`PrecompileFlags::EXIT_TO_NEAR`]. + /// + /// # Example + /// ``` + /// # use aurora_engine::pausables::{PausedPrecompilesChecker, PrecompileFlags}; + /// # fn check(checker: impl PausedPrecompilesChecker) { + /// let flags = checker.paused(); + /// + /// if flags.contains(PrecompileFlags::EXIT_TO_NEAR) { + /// println!("EXIT_TO_NEAR is paused!"); + /// } + /// # } + /// ``` + fn paused(&self) -> PrecompileFlags; +} + +/// Responsible for resuming and pausing of precompiles. +pub trait PausedPrecompilesManager { + /// Resumes all the given `precompiles_to_resume`. + /// + /// The `precompiles_to_resume` mask can be a subset and every 1 bit is meant to be resumed and every 0 bit is + /// ignored. + fn resume_precompiles(&mut self, precompiles_to_resume: PrecompileFlags); + + /// Pauses all the given precompiles. + /// + /// The `precompiles_to_pause` mask can be a subset and every 1 bit is meant to be paused and every 0 bit is + /// ignored. + fn pause_precompiles(&mut self, precompiles_to_pause: PrecompileFlags); +} + +#[derive(BorshSerialize, BorshDeserialize, Debug, Default, Clone)] +pub struct EngineAuthorizer { + /// List of [AccountId]s with the permission to pause precompiles. + pub acl: BTreeSet, +} + +impl EngineAuthorizer { + /// Creates new [EngineAuthorizer] and grants permission to pause precompiles for all given `accounts`. + pub fn from_accounts(accounts: impl Iterator) -> Self { + Self { + acl: accounts.collect(), + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Debug, Default, Clone)] +pub struct EnginePrecompilesPauser { + /// Storage to read pause flags from and write into. + io: I, +} + +impl EnginePrecompilesPauser { + /// Key for storing [PrecompileFlags]. + const PAUSE_FLAGS_KEY: &'static [u8; 11] = b"PAUSE_FLAGS"; + + /// Creates new [EnginePrecompilesPauser] instance that reads from and writes into storage accessed using `io`. + pub fn from_io(io: I) -> Self { + Self { io } + } + + fn read_flags_from_storage(&self) -> PrecompileFlags { + match self.io.read_storage(&Self::storage_key()) { + None => PrecompileFlags::empty(), + Some(bytes) => { + let int_length = core::mem::size_of::(); + let input = bytes.to_vec(); + + if input.len() < int_length { + return PrecompileFlags::empty(); + } + + let (int_bytes, _) = input.split_at(int_length); + PrecompileFlags::from_bits_truncate(u32::from_le_bytes( + int_bytes.try_into().unwrap(), + )) + } + } + } + + fn write_flags_into_storage(&mut self, pause_flags: PrecompileFlags) { + self.io + .write_storage(&Self::storage_key(), &pause_flags.bits().to_le_bytes()); + } + + fn storage_key() -> Vec { + bytes_to_key(KeyPrefix::Config, Self::PAUSE_FLAGS_KEY) + } +} + +impl Authorizer for EngineAuthorizer { + fn is_authorized(&self, account: &AccountId) -> bool { + self.acl.get(account).is_some() + } +} + +impl PausedPrecompilesChecker for EnginePrecompilesPauser { + fn is_paused(&self, precompiles: PrecompileFlags) -> bool { + self.read_flags_from_storage().contains(precompiles) + } + + fn paused(&self) -> PrecompileFlags { + self.read_flags_from_storage() + } +} + +impl PausedPrecompilesManager for EnginePrecompilesPauser { + fn resume_precompiles(&mut self, precompiles_to_resume: PrecompileFlags) { + let mut pause_flags = self.read_flags_from_storage(); + pause_flags.remove(precompiles_to_resume); + self.write_flags_into_storage(pause_flags); + } + + fn pause_precompiles(&mut self, precompiles_to_pause: PrecompileFlags) { + let mut pause_flags = self.read_flags_from_storage(); + pause_flags.insert(precompiles_to_pause); + self.write_flags_into_storage(pause_flags); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use aurora_engine_test_doubles::io::{Storage, StoragePointer}; + use std::iter::once; + use std::sync::RwLock; + use test_case::test_case; + + #[test_case(PrecompileFlags::EXIT_TO_ETHEREUM, exit_to_ethereum::ADDRESS)] + #[test_case(PrecompileFlags::EXIT_TO_NEAR, exit_to_near::ADDRESS)] + fn test_paused_flag_marks_precompiles_address_as_paused( + flags: PrecompileFlags, + address: Address, + ) { + assert!(flags.is_paused_by_address(&address)); + } + + #[test] + fn test_unknown_precompile_address_is_not_marked_as_paused() { + let flags = PrecompileFlags::all(); + let address = Address::zero(); + + assert!(!flags.is_paused_by_address(&address)); + } + + #[test] + fn test_pausing_precompile_marks_it_as_paused() { + let storage = RwLock::new(Storage::default()); + let io = StoragePointer(&storage); + let mut pauser = EnginePrecompilesPauser::from_io(io); + let flags = PrecompileFlags::EXIT_TO_NEAR; + + assert!(!pauser.is_paused(flags)); + pauser.pause_precompiles(flags); + assert!(pauser.is_paused(flags)); + } + + #[test] + fn test_resuming_precompile_removes_its_mark_as_paused() { + let storage = RwLock::new(Storage::default()); + let io = StoragePointer(&storage); + let mut pauser = EnginePrecompilesPauser::from_io(io); + let flags = PrecompileFlags::EXIT_TO_NEAR; + pauser.pause_precompiles(flags); + + assert!(pauser.is_paused(flags)); + pauser.resume_precompiles(flags); + assert!(!pauser.is_paused(flags)); + } + + #[test] + fn test_granting_permission_to_account_authorizes_it() { + let account = AccountId::default(); + let authorizer = EngineAuthorizer::from_accounts(once(account.clone())); + + assert!(authorizer.is_authorized(&account)); + } + + #[test] + fn test_revoking_permission_from_account_unauthorizes_it() { + let account = AccountId::default(); + let authorizer = EngineAuthorizer::default(); + + assert!(!authorizer.is_authorized(&account)); + } + + #[test] + fn test_no_precompile_is_paused_if_storage_contains_too_few_bytes() { + let key = EnginePrecompilesPauser::::storage_key(); + let storage = RwLock::new(Storage::default()); + let mut io = StoragePointer(&storage); + io.write_storage(key.as_slice(), &[7u8]); + let pauser = EnginePrecompilesPauser::from_io(io); + + let expected_paused = PrecompileFlags::empty(); + let actual_paused = pauser.paused(); + assert_eq!(expected_paused, actual_paused); + } +} diff --git a/engine/src/proof.rs b/engine/src/proof.rs index 00fccd8f6..c7d3365c6 100644 --- a/engine/src/proof.rs +++ b/engine/src/proof.rs @@ -12,7 +12,7 @@ pub struct Proof { } impl Proof { - pub fn get_key(&self) -> String { + pub fn key(&self) -> String { let mut data = self.log_index.try_to_vec().unwrap(); data.extend(self.receipt_index.try_to_vec().unwrap()); data.extend(self.header_data.clone()); @@ -23,3 +23,76 @@ impl Proof { .collect() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::deposit_event::{DepositedEvent, TokenMessageData, DEPOSITED_EVENT}; + use crate::log_entry::LogEntry; + use aurora_engine_precompiles::make_address; + use aurora_engine_types::types::{Address, Fee, NEP141Wei, Wei}; + use aurora_engine_types::{H160, U256}; + + const ETH_CUSTODIAN_ADDRESS: Address = + make_address(0xd045f7e1, 0x9b2488924b97f9c145b5e51d0d895a65); + + #[test] + fn test_proof_key_generates_successfully() { + let recipient_address = Address::new(H160([22u8; 20])); + let deposit_amount = Wei::new_u64(123_456_789); + let proof = self::create_proof(recipient_address, deposit_amount); + + let expected_key = + "1297721518512077871939115641114233180253108247225100248224214775219368216419218177247"; + let actual_key = proof.key(); + + assert_eq!(expected_key, actual_key); + } + + fn create_proof(recipient_address: Address, deposit_amount: Wei) -> Proof { + let eth_custodian_address = ETH_CUSTODIAN_ADDRESS; + + let fee = Fee::new(NEP141Wei::new(0)); + let message = ["aurora", ":", recipient_address.encode().as_str()].concat(); + let token_message_data: TokenMessageData = + TokenMessageData::parse_event_message_and_prepare_token_message_data(&message, fee) + .unwrap(); + + let deposit_event = DepositedEvent { + eth_custodian_address, + sender: Address::new(H160([0u8; 20])), + token_message_data, + amount: NEP141Wei::new(deposit_amount.raw().as_u128()), + fee, + }; + + let event_schema = ethabi::Event { + name: DEPOSITED_EVENT.into(), + inputs: DepositedEvent::event_params(), + anonymous: false, + }; + let log_entry = LogEntry { + address: eth_custodian_address.raw(), + topics: vec![ + event_schema.signature(), + // the sender is not important + crate::prelude::H256::zero(), + ], + data: ethabi::encode(&[ + ethabi::Token::String(message), + ethabi::Token::Uint(U256::from(deposit_event.amount.as_u128())), + ethabi::Token::Uint(U256::from(deposit_event.fee.as_u128())), + ]), + }; + + Proof { + log_index: 1, + // Only this field matters for the purpose of this test + log_entry_data: rlp::encode(&log_entry).to_vec(), + receipt_index: 1, + receipt_data: Vec::new(), + header_data: Vec::new(), + proof: Vec::new(), + } + } +} diff --git a/engine/src/xcc.rs b/engine/src/xcc.rs index 564dae3a0..514a0bdc9 100644 --- a/engine/src/xcc.rs +++ b/engine/src/xcc.rs @@ -13,10 +13,13 @@ pub const ERR_NO_ROUTER_CODE: &str = "ERR_MISSING_XCC_BYTECODE"; pub const ERR_INVALID_ACCOUNT: &str = "ERR_INVALID_XCC_ACCOUNT"; pub const ERR_ATTACHED_NEAR: &str = "ERR_ATTACHED_XCC_NEAR"; pub const CODE_KEY: &[u8] = b"router_code"; +/// Gas costs estimated from simulation tests. pub const VERSION_UPDATE_GAS: NearGas = NearGas::new(5_000_000_000_000); pub const INITIALIZE_GAS: NearGas = NearGas::new(15_000_000_000_000); pub const UNWRAP_AND_REFUND_GAS: NearGas = NearGas::new(25_000_000_000_000); pub const WITHDRAW_GAS: NearGas = NearGas::new(30_000_000_000_000); +/// Solidity selector for the withdrawToNear function +/// https://www.4byte.directory/signatures/?bytes4_signature=0x6b351848 pub const WITHDRAW_TO_NEAR_SELECTOR: [u8; 4] = [0x6b, 0x35, 0x18, 0x48]; pub use aurora_engine_precompiles::xcc::state::{ @@ -97,7 +100,7 @@ pub fn handle_precompile_promise( amount: STORAGE_AMOUNT, }); } - promise_actions.push(PromiseAction::DeployConotract { + promise_actions.push(PromiseAction::DeployContract { code: get_router_code(io).0.into_owned(), }); // After a deploy we call the contract's initialize function @@ -120,7 +123,11 @@ pub fn handle_precompile_promise( target_account_id: promise.target_account_id.clone(), actions: promise_actions, }; - let promise_id = handler.promise_create_batch(&batch); + // Safety: This batch creation is safe because it only acts on the router sub-account + // (not the main engine account), and the actions performed are only (1) create it + // for the first time and/or (2) deploy the code from our storage (i.e. the deployed + // code is controlled by us, not the user). + let promise_id = unsafe { handler.promise_create_batch(&batch) }; // Add a callback here to update the version of the account let args = AddressVersionUpdateArgs { address: sender, @@ -134,7 +141,10 @@ pub fn handle_precompile_promise( attached_gas: VERSION_UPDATE_GAS, }; - Some(handler.promise_attach_callback(promise_id, &callback)) + // Safety: A call from the engine to the engine's `factory_update_address_version` + // method is safe because that method only writes the specific router sub-account + // metadata that has just been deployed above. + unsafe { Some(handler.promise_attach_callback(promise_id, &callback)) } } AddressVersionStatus::UpToDate => None, }; @@ -160,9 +170,16 @@ pub fn handle_precompile_promise( attached_balance: ZERO_YOCTO, attached_gas: WITHDRAW_GAS, }; - let id = match setup_id { - None => handler.promise_create_call(&withdraw_call), - Some(setup_id) => handler.promise_attach_callback(setup_id, &withdraw_call), + // Safety: This promise is safe. Even though this is a call from the engine account to + // itself invoking the `call` method (which could be dangerous), the argument to `call` + // is controlled entirely by us (not any user). This call will only execute the wnear + // exit precompile, and only for the necessary amount. Note that this amount will always + // be present, otherwise the user's call to the xcc precompile would have failed. + let id = unsafe { + match setup_id { + None => handler.promise_create_call(&withdraw_call), + Some(setup_id) => handler.promise_attach_callback(setup_id, &withdraw_call), + } }; let refund_needed = match deploy_needed { AddressVersionStatus::DeployNeeded { create_needed } => create_needed, @@ -180,12 +197,22 @@ pub fn handle_precompile_promise( attached_balance: ZERO_YOCTO, attached_gas: UNWRAP_AND_REFUND_GAS, }; - Some(handler.promise_attach_callback(id, &unwrap_call)) + // Safety: This call is safe because the router's `unwrap_and_refund_storage` method + // does not violate any security invariants. It only interacts with the wrap.near contract + // to obtain NEAR from WNEAR. + unsafe { Some(handler.promise_attach_callback(id, &unwrap_call)) } }; // 3. Finally we can do the call the user wanted to do. - let _promise_id = match withdraw_id { - None => handler.promise_create_call(&promise), - Some(withdraw_id) => handler.promise_attach_callback(withdraw_id, &promise), + + // Safety: this call is safe because the promise comes from the XCC precompile, not the + // user directly. The XCC precompile will only construct promises that target the `execute` + // and `schedule` methods of the user's router contract. Therefore, the user cannot have + // the engine make arbitrary calls. + let _promise_id = unsafe { + match withdraw_id { + None => handler.promise_create_call(&promise), + Some(withdraw_id) => handler.promise_attach_callback(withdraw_id, &promise), + } }; } diff --git a/etc/eth-contracts/.catalog-info.yaml b/etc/eth-contracts/.catalog-info.yaml new file mode 100644 index 000000000..0840f6e07 --- /dev/null +++ b/etc/eth-contracts/.catalog-info.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: aurora-engine-token + description: |- + Aurora ERC-20 contract for bridged tokens + tags: + - contract + - aurora + links: [] + annotations: + aurora.dev/security-tier: "1" +spec: + owner: engine-team + type: contract + lifecycle: production + system: aurora-engine + deployedAt: + - contract:aurora/mainnet/0x8bec47865ade3b172a928df8f990bc7f2a3b9f79 + interactsWith: [] diff --git a/etc/eth-contracts/package.json b/etc/eth-contracts/package.json index 077a11b4a..da735939d 100644 --- a/etc/eth-contracts/package.json +++ b/etc/eth-contracts/package.json @@ -18,7 +18,7 @@ "eth-gas-reporter": "^0.2.25", "ethereum-waffle": "^3.4.4", "ethers": "^5.6.9", - "hardhat": "^2.9.9", + "hardhat": "^2.12.0", "hardhat-storage-layout": "^0.1.6", "rainbow-bridge-lib": "^3.0.0", "solc": "0.8.15", diff --git a/etc/eth-contracts/yarn.lock b/etc/eth-contracts/yarn.lock index 2bb19c4b6..2e425e2e9 100644 --- a/etc/eth-contracts/yarn.lock +++ b/etc/eth-contracts/yarn.lock @@ -86,75 +86,6 @@ patch-package "^6.2.2" postinstall-postinstall "^2.1.0" -"@ethereumjs/block@^3.5.0", "@ethereumjs/block@^3.6.2", "@ethereumjs/block@^3.6.3": - version "3.6.3" - resolved "https://registry.yarnpkg.com/@ethereumjs/block/-/block-3.6.3.tgz#d96cbd7af38b92ebb3424223dbf773f5ccd27f84" - integrity sha512-CegDeryc2DVKnDkg5COQrE0bJfw/p0v3GBk2W5/Dj5dOVfEmb50Ux0GLnSPypooLnfqjwFaorGuT9FokWB3GRg== - dependencies: - "@ethereumjs/common" "^2.6.5" - "@ethereumjs/tx" "^3.5.2" - ethereumjs-util "^7.1.5" - merkle-patricia-tree "^4.2.4" - -"@ethereumjs/blockchain@^5.5.2", "@ethereumjs/blockchain@^5.5.3": - version "5.5.3" - resolved "https://registry.yarnpkg.com/@ethereumjs/blockchain/-/blockchain-5.5.3.tgz#aa49a6a04789da6b66b5bcbb0d0b98efc369f640" - integrity sha512-bi0wuNJ1gw4ByNCV56H0Z4Q7D+SxUbwyG12Wxzbvqc89PXLRNR20LBcSUZRKpN0+YCPo6m0XZL/JLio3B52LTw== - dependencies: - "@ethereumjs/block" "^3.6.2" - "@ethereumjs/common" "^2.6.4" - "@ethereumjs/ethash" "^1.1.0" - debug "^4.3.3" - ethereumjs-util "^7.1.5" - level-mem "^5.0.1" - lru-cache "^5.1.1" - semaphore-async-await "^1.5.1" - -"@ethereumjs/common@^2.6.4", "@ethereumjs/common@^2.6.5": - version "2.6.5" - resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" - integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== - dependencies: - crc-32 "^1.2.0" - ethereumjs-util "^7.1.5" - -"@ethereumjs/ethash@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/ethash/-/ethash-1.1.0.tgz#7c5918ffcaa9cb9c1dc7d12f77ef038c11fb83fb" - integrity sha512-/U7UOKW6BzpA+Vt+kISAoeDie1vAvY4Zy2KF5JJb+So7+1yKmJeJEHOGSnQIj330e9Zyl3L5Nae6VZyh2TJnAA== - dependencies: - "@ethereumjs/block" "^3.5.0" - "@types/levelup" "^4.3.0" - buffer-xor "^2.0.1" - ethereumjs-util "^7.1.1" - miller-rabin "^4.0.0" - -"@ethereumjs/tx@^3.5.1", "@ethereumjs/tx@^3.5.2": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.2.tgz#197b9b6299582ad84f9527ca961466fce2296c1c" - integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== - dependencies: - "@ethereumjs/common" "^2.6.4" - ethereumjs-util "^7.1.5" - -"@ethereumjs/vm@^5.9.0": - version "5.9.3" - resolved "https://registry.yarnpkg.com/@ethereumjs/vm/-/vm-5.9.3.tgz#6d69202e4c132a4a1e1628ac246e92062e230823" - integrity sha512-Ha04TeF8goEglr8eL7hkkYyjhzdZS0PsoRURzYlTF6I0VVId5KjKb0N7MrA8GMgheN+UeTncfTgYx52D/WhEmg== - dependencies: - "@ethereumjs/block" "^3.6.3" - "@ethereumjs/blockchain" "^5.5.3" - "@ethereumjs/common" "^2.6.5" - "@ethereumjs/tx" "^3.5.2" - async-eventemitter "^0.2.4" - core-js-pure "^3.0.1" - debug "^4.3.3" - ethereumjs-util "^7.1.5" - functional-red-black-tree "^1.0.1" - mcl-wasm "^0.7.1" - merkle-patricia-tree "^4.2.4" - rustbn.js "~0.2.0" - "@ethersproject/abi@5.0.0-beta.153": version "5.0.0-beta.153" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" @@ -1101,6 +1032,204 @@ "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" +"@nomicfoundation/ethereumjs-block@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.0.0.tgz#fdd5c045e7baa5169abeed0e1202bf94e4481c49" + integrity sha512-bk8uP8VuexLgyIZAHExH1QEovqx0Lzhc9Ntm63nCRKLHXIZkobaFaeCVwTESV7YkPKUk7NiK11s8ryed4CS9yA== + dependencies: + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-tx" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-blockchain@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-6.0.0.tgz#1a8c243a46d4d3691631f139bfb3a4a157187b0c" + integrity sha512-pLFEoea6MWd81QQYSReLlLfH7N9v7lH66JC/NMPN848ySPPQA5renWnE7wPByfQFzNrPBuDDRFFULMDmj1C0xw== + dependencies: + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-ethash" "^2.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + abstract-level "^1.0.3" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + level "^8.0.0" + lru-cache "^5.1.1" + memory-level "^1.0.0" + +"@nomicfoundation/ethereumjs-common@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-3.0.0.tgz#f6bcc7753994555e49ab3aa517fc8bcf89c280b9" + integrity sha512-WS7qSshQfxoZOpHG/XqlHEGRG1zmyjYrvmATvc4c62+gZXgre1ymYP8ZNgx/3FyZY0TWe9OjFlKOfLqmgOeYwA== + dependencies: + "@nomicfoundation/ethereumjs-util" "^8.0.0" + crc-32 "^1.2.0" + +"@nomicfoundation/ethereumjs-ethash@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-2.0.0.tgz#11539c32fe0990e1122ff987d1b84cfa34774e81" + integrity sha512-WpDvnRncfDUuXdsAXlI4lXbqUDOA+adYRQaEezIkxqDkc+LDyYDbd/xairmY98GnQzo1zIqsIL6GB5MoMSJDew== + dependencies: + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + abstract-level "^1.0.3" + bigint-crypto-utils "^3.0.23" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-evm@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-1.0.0.tgz#99cd173c03b59107c156a69c5e215409098a370b" + integrity sha512-hVS6qRo3V1PLKCO210UfcEQHvlG7GqR8iFzp0yyjTg2TmJQizcChKgWo8KFsdMw6AyoLgLhHGHw4HdlP8a4i+Q== + dependencies: + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@types/async-eventemitter" "^0.2.1" + async-eventemitter "^0.2.4" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + mcl-wasm "^0.7.1" + rustbn.js "~0.2.0" + +"@nomicfoundation/ethereumjs-rlp@^4.0.0", "@nomicfoundation/ethereumjs-rlp@^4.0.0-beta.2": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-4.0.0.tgz#d9a9c5f0f10310c8849b6525101de455a53e771d" + integrity sha512-GaSOGk5QbUk4eBP5qFbpXoZoZUj/NrW7MRa0tKY4Ew4c2HAS0GXArEMAamtFrkazp0BO4K5p2ZCG3b2FmbShmw== + +"@nomicfoundation/ethereumjs-statemanager@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-1.0.0.tgz#14a9d4e1c828230368f7ab520c144c34d8721e4b" + integrity sha512-jCtqFjcd2QejtuAMjQzbil/4NHf5aAWxUc+CvS0JclQpl+7M0bxMofR2AJdtz+P3u0ke2euhYREDiE7iSO31vQ== + dependencies: + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + functional-red-black-tree "^1.0.1" + +"@nomicfoundation/ethereumjs-trie@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-5.0.0.tgz#dcfbe3be53a94bc061c9767a396c16702bc2f5b7" + integrity sha512-LIj5XdE+s+t6WSuq/ttegJzZ1vliwg6wlb+Y9f4RlBpuK35B9K02bO7xU+E6Rgg9RGptkWd6TVLdedTI4eNc2A== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + ethereum-cryptography "0.1.3" + readable-stream "^3.6.0" + +"@nomicfoundation/ethereumjs-tx@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-4.0.0.tgz#59dc7452b0862b30342966f7052ab9a1f7802f52" + integrity sha512-Gg3Lir2lNUck43Kp/3x6TfBNwcWC9Z1wYue9Nz3v4xjdcv6oDW9QSMJxqsKw9QEGoBBZ+gqwpW7+F05/rs/g1w== + dependencies: + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-util@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-8.0.0.tgz#deb2b15d2c308a731e82977aefc4e61ca0ece6c5" + integrity sha512-2emi0NJ/HmTG+CGY58fa+DQuAoroFeSH9gKu9O6JnwTtlzJtgfTixuoOqLEgyyzZVvwfIpRueuePb8TonL1y+A== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "^4.0.0-beta.2" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-vm@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-6.0.0.tgz#2bb50d332bf41790b01a3767ffec3987585d1de6" + integrity sha512-JMPxvPQ3fzD063Sg3Tp+UdwUkVxMoo1uML6KSzFhMH3hoQi/LMuXBoEHAoW83/vyNS9BxEe6jm6LmT5xdeEJ6w== + dependencies: + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-evm" "^1.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-tx" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@types/async-eventemitter" "^0.2.1" + async-eventemitter "^0.2.4" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + functional-red-black-tree "^1.0.1" + mcl-wasm "^0.7.1" + rustbn.js "~0.2.0" + +"@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.0.tgz#83a7367342bd053a76d04bbcf4f373fef07cf760" + integrity sha512-vEF3yKuuzfMHsZecHQcnkUrqm8mnTWfJeEVFHpg+cO+le96xQA4lAJYdUan8pXZohQxv1fSReQsn4QGNuBNuCw== + +"@nomicfoundation/solidity-analyzer-darwin-x64@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.0.tgz#1225f7da647ae1ad25a87125664704ecc0af6ccc" + integrity sha512-dlHeIg0pTL4dB1l9JDwbi/JG6dHQaU1xpDK+ugYO8eJ1kxx9Dh2isEUtA4d02cQAl22cjOHTvifAk96A+ItEHA== + +"@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.0.tgz#dbc052dcdfd50ae50fd5ae1788b69b4e0fa40040" + integrity sha512-WFCZYMv86WowDA4GiJKnebMQRt3kCcFqHeIomW6NMyqiKqhK1kIZCxSLDYsxqlx396kKLPN1713Q1S8tu68GKg== + +"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.0.tgz#e6b2eea633995b557e74e881d2a43eab4760903d" + integrity sha512-DTw6MNQWWlCgc71Pq7CEhEqkb7fZnS7oly13pujs4cMH1sR0JzNk90Mp1zpSCsCs4oKan2ClhMlLKtNat/XRKQ== + +"@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.0.tgz#af81107f5afa794f19988a368647727806e18dc4" + integrity sha512-wUpUnR/3GV5Da88MhrxXh/lhb9kxh9V3Jya2NpBEhKDIRCDmtXMSqPMXHZmOR9DfCwCvG6vLFPr/+YrPCnUN0w== + +"@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.0.tgz#6877e1da1a06a9f08446070ab6e0a5347109f868" + integrity sha512-lR0AxK1x/MeKQ/3Pt923kPvwigmGX3OxeU5qNtQ9pj9iucgk4PzhbS3ruUeSpYhUxG50jN4RkIGwUMoev5lguw== + +"@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.0.tgz#bb6cd83a0c259eccef4183796b6329a66cf7ebd9" + integrity sha512-A1he/8gy/JeBD3FKvmI6WUJrGrI5uWJNr5Xb9WdV+DK0F8msuOqpEByLlnTdLkXMwW7nSl3awvLezOs9xBHJEg== + +"@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.0.tgz#9d4bca1cc9a1333fde985675083b0b7d165f6076" + integrity sha512-7x5SXZ9R9H4SluJZZP8XPN+ju7Mx+XeUMWZw7ZAqkdhP5mK19I4vz3x0zIWygmfE8RT7uQ5xMap0/9NPsO+ykw== + +"@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.0.tgz#0db5bfc6aa952bea4098d8d2c8947b4e5c4337ee" + integrity sha512-m7w3xf+hnE774YRXu+2mGV7RiF3QJtUoiYU61FascCkQhX3QMQavh7saH/vzb2jN5D24nT/jwvaHYX/MAM9zUw== + +"@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.0.tgz#2e0f39a2924dcd77db6b419828595e984fabcb33" + integrity sha512-xCuybjY0sLJQnJhupiFAXaek2EqF0AP0eBjgzaalPXSNvCEN6ZYHvUzdA50ENDVeSYFXcUsYf3+FsD3XKaeptA== + +"@nomicfoundation/solidity-analyzer@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.0.tgz#e5ddc43ad5c0aab96e5054520d8e16212e125f50" + integrity sha512-xGWAiVCGOycvGiP/qrlf9f9eOn7fpNbyJygcB0P21a1MDuVPlKt0Srp7rvtBEutYQ48ouYnRXm33zlRnlTOPHg== + optionalDependencies: + "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.0" + "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.0" + "@nomicfoundation/solidity-analyzer-freebsd-x64" "0.1.0" + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.0" + "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.0" + "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.0" + "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.0" + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc" "0.1.0" + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.0" + "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.0" + "@nomiclabs/hardhat-ethers@^2.0.6": version "2.0.6" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.0.6.tgz#1c695263d5b46a375dcda48c248c4fba9dfe2fc2" @@ -1265,7 +1394,7 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@solidity-parser/parser@^0.14.0", "@solidity-parser/parser@^0.14.1": +"@solidity-parser/parser@^0.14.0": version "0.14.2" resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.2.tgz#2d8f2bddb217621df882ceeae7d7b42ae8664db3" integrity sha512-10cr0s+MtRtqjEw0WFJrm2rwULN30xx7btd/v9cmqME2617/2M5MbHDkFIGIGTa7lwNw4bN9mVGfhlLzrYw8pA== @@ -1309,10 +1438,10 @@ dependencies: ethers "^5.0.2" -"@types/abstract-leveldown@*": - version "5.0.1" - resolved "https://registry.yarnpkg.com/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz#3c7750d0186b954c7f2d2f6acc8c3c7ba0c3412e" - integrity sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ== +"@types/async-eventemitter@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz#f8e6280e87e8c60b2b938624b0a3530fb3e24712" + integrity sha512-M2P4Ng26QbAeITiH7w1d7OxtldgfAe0wobpyJzVK/XOb0cUGKU2R4pfAhqcJBXAe2ife5ZOhSv4wk7p+ffURtg== "@types/bn.js@*", "@types/bn.js@^5.1.0": version "5.1.0" @@ -1360,14 +1489,6 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/levelup@^4.3.0": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@types/levelup/-/levelup-4.3.1.tgz#7a53b9fd510716e11b2065332790fdf5f9b950b9" - integrity sha512-n//PeTpbHLjMLTIgW5B/g06W/6iuTBHuvUka2nFL9APMSVMNe2r4enADfu3CIE9IyV9E+uquf9OEQQqrDeg24A== - dependencies: - "@types/abstract-leveldown" "*" - "@types/node" "*" - "@types/lru-cache@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.0.tgz#57f228f2b80c046b4a1bd5cac031f81f207f4f03" @@ -1472,11 +1593,6 @@ "@types/bn.js" "*" "@types/underscore" "*" -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - "@web3-js/scrypt-shim@^0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@web3-js/scrypt-shim/-/scrypt-shim-0.1.0.tgz#0bf7529ab6788311d3e07586f7d89107c3bea2cc" @@ -1518,6 +1634,19 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" +abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" + integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== + dependencies: + buffer "^6.0.3" + catering "^2.1.0" + is-buffer "^2.0.5" + level-supports "^4.0.0" + level-transcoder "^1.0.1" + module-error "^1.0.1" + queue-microtask "^1.2.3" + abstract-leveldown@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz#5cb89f958a44f526779d740d1440e743e0c30a57" @@ -1539,17 +1668,6 @@ abstract-leveldown@^5.0.0, abstract-leveldown@~5.0.0: dependencies: xtend "~4.0.0" -abstract-leveldown@^6.2.1: - version "6.3.0" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" - integrity sha512-TU5nlYgta8YrBMNpc9FwQzRbiXsj49gsALsXadbGHt9CROPzX5fB0rWDR5mtdpOOKa5XqRFpbj1QroPAoPzVjQ== - dependencies: - buffer "^5.5.0" - immediate "^3.2.3" - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - abstract-leveldown@~2.6.0: version "2.6.3" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" @@ -1557,17 +1675,6 @@ abstract-leveldown@~2.6.0: dependencies: xtend "~4.0.0" -abstract-leveldown@~6.2.1: - version "6.2.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz#036543d87e3710f2528e47040bc3261b77a9a8eb" - integrity sha512-BsLm5vFMRUrrLeCcRc+G0t2qOaTzpoJQLOubq2XM72eNpjF5UdU5o/5NvlNhx95XHcAvcl8OMXr4mlg/fRgUXQ== - dependencies: - buffer "^5.5.0" - immediate "^3.2.3" - level-concat-iterator "~2.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -2495,6 +2602,18 @@ bech32@1.1.4: resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== +bigint-crypto-utils@^3.0.23: + version "3.1.7" + resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.1.7.tgz#c4c1b537c7c1ab7aadfaecf3edfd45416bf2c651" + integrity sha512-zpCQpIE2Oy5WIQpjC9iYZf8Uh9QqoS51ZCooAcNvzv1AQ3VWdT52D0ksr1+/faeK8HVIej1bxXcP75YcqH3KPA== + dependencies: + bigint-mod-arith "^3.1.0" + +bigint-mod-arith@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz#658e416bc593a463d97b59766226d0a3021a76b1" + integrity sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ== + bignumber.js@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" @@ -2595,6 +2714,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^1.8.2: version "1.8.5" resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" @@ -2632,6 +2758,16 @@ brorand@^1.0.1, brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= +browser-level@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" + integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.1" + module-error "^1.0.2" + run-parallel-limit "^1.1.0" + browser-stdout@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" @@ -2778,6 +2914,14 @@ buffer@^5.0.5, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + bufferutil@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.3.tgz#66724b756bed23cd7c28c4d306d7994f9943cc6b" @@ -2913,6 +3057,11 @@ caseless@^0.12.0, caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +catering@^2.1.0, catering@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" + integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== + chai@^4.3.6: version "4.3.6" resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" @@ -3102,6 +3251,17 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classic-level@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/classic-level/-/classic-level-1.2.0.tgz#2d52bdec8e7a27f534e67fdeb890abef3e643c27" + integrity sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.0" + module-error "^1.0.1" + napi-macros "~2.0.0" + node-gyp-build "^4.3.0" + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -3528,10 +3688,10 @@ debug@4, debug@^4.1.1: dependencies: ms "2.1.2" -debug@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== +debug@4.3.4, debug@^4.3.2, debug@^4.3.3: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" @@ -3542,13 +3702,6 @@ debug@^3.1.0, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.3.2, debug@^4.3.3: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decamelize@^1.1.1, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -3673,14 +3826,6 @@ deferred-leveldown@~4.0.0: abstract-leveldown "~5.0.0" inherits "^2.0.3" -deferred-leveldown@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" - integrity sha512-a59VOT+oDy7vtAbLRCZwWgxu2BaCfd5Hk7wxJd48ei7I+nsg8Orlb9CLG0PMZienk9BSUKgeAqkO2+Lw+1+Ukw== - dependencies: - abstract-leveldown "~6.2.1" - inherits "^2.0.3" - define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -3923,16 +4068,6 @@ encoding-down@5.0.4, encoding-down@~5.0.0: level-errors "^2.0.0" xtend "^4.0.1" -encoding-down@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/encoding-down/-/encoding-down-6.3.0.tgz#b1c4eb0e1728c146ecaef8e32963c549e76d082b" - integrity sha512-QKrV0iKR6MZVJV08QY0wp1e7vF6QbhnbQhb07bwpEyuz4uZiZgPlEGdkCROuFkUwdxlFaiPIhjyarH1ee/3vhw== - dependencies: - abstract-leveldown "^6.2.1" - inherits "^2.0.3" - level-codec "^9.0.0" - level-errors "^2.0.0" - encoding@^0.1.11: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -4519,7 +4654,7 @@ ethereum-common@^0.0.18: resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" integrity sha1-L9w1dvIykDNYl26znaeDIT/5Uj8= -ethereum-cryptography@^0.1.2, ethereum-cryptography@^0.1.3: +ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== @@ -4727,17 +4862,6 @@ ethereumjs-util@^7.0.3: ethjs-util "0.1.6" rlp "^2.2.4" -ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.4, ethereumjs-util@^7.1.5: - version "7.1.5" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" - integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== - dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - ethereumjs-vm@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-4.2.0.tgz#e885e861424e373dbc556278f7259ff3fca5edab" @@ -5848,20 +5972,25 @@ hardhat-storage-layout@^0.1.6: dependencies: console-table-printer "^2.9.0" -hardhat@^2.9.9: - version "2.9.9" - resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.9.9.tgz#05c1015eb73e0230309534b00deeb080724aace0" - integrity sha512-Qv7SXnRc0zq1kGXruNnSKpP3eFccXMR5Qv6GVX9hBIJ5efN0PflKPq92aQ5Cv3jrjJeRevLznWZVz7bttXhVfw== +hardhat@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.12.0.tgz#51e59f1ff4991bcb66d1a380ea807e6c15fcac34" + integrity sha512-mNJFbVG479HwOzxiaLxobyvED2M1aEAuPPYhEo1+88yicMDSTrU2JIS7vV+V0GSNQKaDoiHCmV6bcKjiljT/dQ== dependencies: - "@ethereumjs/block" "^3.6.2" - "@ethereumjs/blockchain" "^5.5.2" - "@ethereumjs/common" "^2.6.4" - "@ethereumjs/tx" "^3.5.1" - "@ethereumjs/vm" "^5.9.0" "@ethersproject/abi" "^5.1.2" "@metamask/eth-sig-util" "^4.0.0" + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-evm" "^1.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-tx" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@nomicfoundation/ethereumjs-vm" "^6.0.0" + "@nomicfoundation/solidity-analyzer" "^0.1.0" "@sentry/node" "^5.18.1" - "@solidity-parser/parser" "^0.14.1" "@types/bn.js" "^5.1.0" "@types/lru-cache" "^5.1.0" abort-controller "^3.0.0" @@ -5874,29 +6003,26 @@ hardhat@^2.9.9: debug "^4.1.1" enquirer "^2.3.0" env-paths "^2.2.0" - ethereum-cryptography "^0.1.2" + ethereum-cryptography "^1.0.3" ethereumjs-abi "^0.6.8" - ethereumjs-util "^7.1.4" find-up "^2.1.0" fp-ts "1.19.3" fs-extra "^7.0.1" glob "7.2.0" immutable "^4.0.0-rc.12" io-ts "1.10.4" + keccak "^3.0.2" lodash "^4.17.11" - merkle-patricia-tree "^4.2.4" mnemonist "^0.38.0" - mocha "^9.2.0" + mocha "^10.0.0" p-map "^4.0.0" qs "^6.7.0" raw-body "^2.4.1" resolve "1.17.0" semver "^6.3.0" - slash "^3.0.0" solc "0.7.3" source-map-support "^0.5.13" stacktrace-parser "^0.1.10" - "true-case-path" "^2.2.1" tsort "0.0.1" undici "^5.4.0" uuid "^8.3.2" @@ -6181,7 +6307,7 @@ idna-uts46-hx@^2.3.1: dependencies: punycode "2.1.0" -ieee754@^1.1.13: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -6347,7 +6473,7 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@~2.0.3: +is-buffer@^2.0.5, is-buffer@~2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== @@ -6943,6 +7069,15 @@ keccak@3.0.1, keccak@^3.0.0: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" +keccak@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" + integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + keyv@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -7007,11 +7142,6 @@ level-codec@~7.0.0: resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" integrity sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ== -level-concat-iterator@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/level-concat-iterator/-/level-concat-iterator-2.0.1.tgz#1d1009cf108340252cb38c51f9727311193e6263" - integrity sha512-OTKKOqeav2QWcERMJR7IS9CUo1sHnke2C0gkSmcR7QuEtFNLLzHQAvnMw8ykvEcv0Qtkg0p7FOwP1v9e5Smdcw== - level-errors@^1.0.3: version "1.1.2" resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" @@ -7061,15 +7191,6 @@ level-iterator-stream@~3.0.0: readable-stream "^2.3.6" xtend "^4.0.0" -level-iterator-stream@~4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-4.0.2.tgz#7ceba69b713b0d7e22fcc0d1f128ccdc8a24f79c" - integrity sha512-ZSthfEqzGSOMWoUGhTXdX9jv26d32XJuHz/5YnuHZzH6wldfWMOVwI9TBtKcya4BKTyTt3XVA0A3cF3q5CY30Q== - dependencies: - inherits "^2.0.4" - readable-stream "^3.4.0" - xtend "^4.0.2" - level-mem@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-3.0.1.tgz#7ce8cf256eac40f716eb6489654726247f5a89e5" @@ -7078,22 +7199,6 @@ level-mem@^3.0.1: level-packager "~4.0.0" memdown "~3.0.0" -level-mem@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/level-mem/-/level-mem-5.0.1.tgz#c345126b74f5b8aa376dc77d36813a177ef8251d" - integrity sha512-qd+qUJHXsGSFoHTziptAKXoLX87QjR7v2KMbqncDXPxQuCdsQlzmyX+gwrEHhlzn08vkf8TyipYyMmiC6Gobzg== - dependencies: - level-packager "^5.0.3" - memdown "^5.0.0" - -level-packager@^5.0.3: - version "5.1.1" - resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-5.1.1.tgz#323ec842d6babe7336f70299c14df2e329c18939" - integrity sha512-HMwMaQPlTC1IlcwT3+swhqf/NUO+ZhXVz6TY1zZIIZlIR0YSn8GtAAWmIvKjNY16ZkEg/JcpAuQskxsXqC0yOQ== - dependencies: - encoding-down "^6.3.0" - levelup "^4.3.2" - level-packager@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/level-packager/-/level-packager-4.0.1.tgz#7e7d3016af005be0869bc5fa8de93d2a7f56ffe6" @@ -7125,12 +7230,18 @@ level-sublevel@6.6.4: typewiselite "~1.0.0" xtend "~4.0.0" -level-supports@~1.0.0: +level-supports@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" + integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== + +level-transcoder@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/level-supports/-/level-supports-1.0.1.tgz#2f530a596834c7301622521988e2c36bb77d122d" - integrity sha512-rXM7GYnW8gsl1vedTJIbzOrRv85c/2uCMpiiCzO2fndd06U/kUXEEU9evYn4zFggBOg36IsBW8LzqIpETwwQzg== + resolved "https://registry.yarnpkg.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" + integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== dependencies: - xtend "^4.0.2" + buffer "^6.0.3" + module-error "^1.0.1" level-ws@0.0.0: version "0.0.0" @@ -7149,14 +7260,13 @@ level-ws@^1.0.0: readable-stream "^2.2.8" xtend "^4.0.1" -level-ws@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-2.0.0.tgz#207a07bcd0164a0ec5d62c304b4615c54436d339" - integrity sha512-1iv7VXx0G9ec1isqQZ7y5LmoZo/ewAsyDHNA8EFDW5hqH2Kqovm33nSFkSdnLLAK+I5FlT+lo5Cw9itGe+CpQA== +level@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" + integrity sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ== dependencies: - inherits "^2.0.3" - readable-stream "^3.1.0" - xtend "^4.0.1" + browser-level "^1.0.1" + classic-level "^1.2.0" levelup@3.1.1, levelup@^3.0.0: version "3.1.1" @@ -7181,17 +7291,6 @@ levelup@^1.2.1: semver "~5.4.1" xtend "~4.0.0" -levelup@^4.3.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-4.4.0.tgz#f89da3a228c38deb49c48f88a70fb71f01cafed6" - integrity sha512-94++VFO3qN95cM/d6eBXvd894oJE0w3cInq9USsyQzzoJxmiYzPAocNcuGCPGGjoXqDVJcr3C1jzt1TSjyaiLQ== - dependencies: - deferred-leveldown "~5.3.0" - level-errors "~2.0.0" - level-iterator-stream "~4.0.0" - level-supports "~1.0.0" - xtend "~4.0.0" - levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -7441,18 +7540,6 @@ memdown@^1.0.0: ltgt "~2.2.0" safe-buffer "~5.1.1" -memdown@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-5.1.0.tgz#608e91a9f10f37f5b5fe767667a8674129a833cb" - integrity sha512-B3J+UizMRAlEArDjWHTMmadet+UKwHd3UjMgGBkZcKAxAYVPS9o0Yeiha4qvz7iGiL2Sb3igUft6p7nbFWctpw== - dependencies: - abstract-leveldown "~6.2.1" - functional-red-black-tree "~1.0.1" - immediate "~3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.2.0" - memdown@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/memdown/-/memdown-3.0.0.tgz#93aca055d743b20efc37492e9e399784f2958309" @@ -7465,6 +7552,15 @@ memdown@~3.0.0: ltgt "~2.2.0" safe-buffer "~5.1.1" +memory-level@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" + integrity sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og== + dependencies: + abstract-level "^1.0.0" + functional-red-black-tree "^1.0.1" + module-error "^1.0.1" + memorystream@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" @@ -7507,18 +7603,6 @@ merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: rlp "^2.0.0" semaphore ">=1.0.1" -merkle-patricia-tree@^4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-4.2.4.tgz#ff988d045e2bf3dfa2239f7fabe2d59618d57413" - integrity sha512-eHbf/BG6eGNsqqfbLED9rIqbsF4+sykEaBn6OLNs71tjclbMcMOk1tEPmJKcNcNCLkvbpY/lwyOlizWsqPNo8w== - dependencies: - "@types/levelup" "^4.3.0" - ethereumjs-util "^7.1.4" - level-mem "^5.0.1" - level-ws "^2.0.0" - readable-stream "^3.6.0" - semaphore-async-await "^1.5.1" - methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -7629,12 +7713,12 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: dependencies: brace-expansion "^1.1.7" -minimatch@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" @@ -7714,6 +7798,33 @@ mnemonist@^0.38.0: dependencies: obliterator "^1.6.1" +mocha@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.1.0.tgz#dbf1114b7c3f9d0ca5de3133906aea3dfc89ef7a" + integrity sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg== + dependencies: + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + mocha@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" @@ -7760,41 +7871,16 @@ mocha@^7.1.1: yargs-parser "13.1.2" yargs-unparser "1.6.0" -mocha@^9.2.0: - version "9.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" - integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.3" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "4.2.1" - ms "2.1.3" - nanoid "3.3.1" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.2.0" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - mock-fs@^4.1.0: version "4.14.0" resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== +module-error@^1.0.1, module-error@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" + integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -7870,10 +7956,10 @@ nano-json-stream-parser@^0.1.2: resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= -nanoid@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== nanomatch@^1.2.9: version "1.2.13" @@ -7892,6 +7978,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -7982,6 +8073,11 @@ node-gyp-build@^4.2.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.3.tgz#ce6277f853835f718829efb47db20f3e4d9c4739" integrity sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg== +node-gyp-build@^4.3.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" + integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== + nopt@3.x: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -8789,7 +8885,7 @@ querystring@0.2.0: resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -queue-microtask@^1.2.2: +queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== @@ -8906,7 +9002,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.1.0, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.0.6, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -9260,6 +9356,13 @@ rlp@^2.0.0, rlp@^2.2.1, rlp@^2.2.2, rlp@^2.2.3, rlp@^2.2.4: dependencies: bn.js "^4.11.1" +run-parallel-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" + integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== + dependencies: + queue-microtask "^1.2.2" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -9369,11 +9472,6 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" -semaphore-async-await@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/semaphore-async-await/-/semaphore-async-await-1.5.1.tgz#857bef5e3644601ca4b9570b87e9df5ca12974fa" - integrity sha1-hXvvXjZEYBykuVcLh+nfXKEpdPo= - semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" @@ -10380,11 +10478,6 @@ trim-right@^1.0.1: resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= -"true-case-path@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-2.2.1.tgz#c5bf04a5bbec3fd118be4084461b3a27c4d796bf" - integrity sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q== - ts-essentials@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-1.0.4.tgz#ce3b5dade5f5d97cf69889c11bf7d2da8555b15a" @@ -11659,7 +11752,7 @@ which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.1: dependencies: isexe "^2.0.0" -which@2.0.2, which@^2.0.1: +which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== @@ -11688,10 +11781,10 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== wrap-ansi@^2.0.0: version "2.1.0" @@ -11807,7 +11900,7 @@ xmlhttprequest@1.8.0: resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== diff --git a/etc/state-migration-test/Cargo.lock b/etc/state-migration-test/Cargo.lock index 43f8a1762..56b2b9927 100644 --- a/etc/state-migration-test/Cargo.lock +++ b/etc/state-migration-test/Cargo.lock @@ -39,6 +39,7 @@ dependencies = [ "aurora-engine-transactions", "aurora-engine-types", "base64", + "bitflags", "borsh", "byte-slice-cast", "ethabi", @@ -150,6 +151,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6736e2428df2ca2848d846c43e88745121a6654696e349ce0054a420815a7409" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "block-buffer" version = "0.9.0" diff --git a/etc/tests/fibonacci/Cargo.toml b/etc/tests/fibonacci/Cargo.toml new file mode 100644 index 000000000..e0c03bc1f --- /dev/null +++ b/etc/tests/fibonacci/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "fibonacci_on_near" +version = "1.0.0" +authors = ["Aurora "] +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" + +[dependencies] +near-sdk = "4.0.0" +serde = "1" diff --git a/etc/tests/fibonacci/src/lib.rs b/etc/tests/fibonacci/src/lib.rs new file mode 100644 index 000000000..0e4b4a55f --- /dev/null +++ b/etc/tests/fibonacci/src/lib.rs @@ -0,0 +1,86 @@ +use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; +use near_sdk::json_types::U128; +use near_sdk::{env, near_bindgen, Gas, Promise, PromiseError}; + +const FIVE_TGAS: Gas = Gas(5_000_000_000_000); + +#[near_bindgen] +#[derive(Default, BorshDeserialize, BorshSerialize)] +pub struct Fib; + +#[derive(serde::Deserialize, serde::Serialize)] +pub struct FibAcc { + a: U128, + b: U128, +} + +#[near_bindgen] +impl Fib { + /// Seeds the Fibonacci recursion with the starting values (i.e. F[0] and F[1]). + pub fn seed() -> FibAcc { + FibAcc { + a: U128(0), + b: U128(1), + } + } + + /// Performs one step of the Fibonacci recursion. + #[handle_result] + pub fn accumulate( + #[callback_result] acc: Result, + ) -> Result { + match acc { + Ok(acc) => Ok(FibAcc { + a: acc.b, + b: u128_sum(acc.a, acc.b), + }), + Err(_) => Err("Promise failed"), + } + } + + /// Computes the nth Fibonacci number using NEAR cross-contract calls to this contract. + /// It begins with the seed, followed by `n` calls to the `accumulate` function. + pub fn fib(n: u8) -> Promise { + let account = env::current_account_id(); + let mut p = + Promise::new(account.clone()).function_call("seed".into(), Vec::new(), 0, FIVE_TGAS); + let mut n = n; + while n > 0 { + n -= 1; + p = p.then(Promise::new(account.clone()).function_call( + "accumulate".into(), + Vec::new(), + 0, + FIVE_TGAS, + )) + } + p + } + + /// An alternative version of `accumulate`. Rather then performing the recursion + /// with a single input which contains the previous two Fibonacci values, this function + /// takes the previous two terms as separate inputs. This gives an alternate way to compute + /// Fibonacci numbers using this contract: `fib(n - 1).and(fib(n - 2)).then(sum)`. + #[handle_result] + pub fn sum( + #[callback_result] fib_n_minus_1: Result, + #[callback_result] fib_n_minus_2: Result, + ) -> Result { + let FibAcc { + a: fib_n_minus_1, + b: fib_n, + } = fib_n_minus_1.map_err(|e| format!("Promise 1 failed {:?}", e))?; + let FibAcc { + a: fib_n_minus_2, + b: _, + } = fib_n_minus_2.map_err(|e| format!("Promise 2 failed {:?}", e))?; + Ok(FibAcc { + a: u128_sum(fib_n_minus_1, fib_n_minus_2), + b: u128_sum(fib_n_minus_1, fib_n), + }) + } +} + +fn u128_sum(x: U128, y: U128) -> U128 { + U128(x.0 + y.0) +} diff --git a/etc/xcc-router/Cargo.lock b/etc/xcc-router/Cargo.lock index 615e1bbef..65de40ccc 100644 --- a/etc/xcc-router/Cargo.lock +++ b/etc/xcc-router/Cargo.lock @@ -43,7 +43,7 @@ version = "1.0.0" dependencies = [ "borsh", "hex", - "primitive-types 0.11.1", + "primitive-types 0.12.1", ] [[package]] @@ -365,6 +365,15 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "static_assertions", +] + [[package]] name = "funty" version = "1.1.0" @@ -758,18 +767,18 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0", "impl-codec", "uint", ] [[package]] name = "primitive-types" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ - "fixed-hash", + "fixed-hash 0.8.0", "impl-rlp", "uint", ] diff --git a/etc/xcc-router/Cargo.toml b/etc/xcc-router/Cargo.toml index ba56690af..faf1e77f7 100644 --- a/etc/xcc-router/Cargo.toml +++ b/etc/xcc-router/Cargo.toml @@ -17,3 +17,7 @@ panic = "abort" [dependencies] aurora-engine-types = { path = "../../engine-types", default-features = false } near-sdk = "4.0.0" + +[features] +default = [] +all-promise-actions = [] diff --git a/etc/xcc-router/src/lib.rs b/etc/xcc-router/src/lib.rs index 1e6308b98..fd604ea3f 100644 --- a/etc/xcc-router/src/lib.rs +++ b/etc/xcc-router/src/lib.rs @@ -1,4 +1,7 @@ -use aurora_engine_types::parameters::{PromiseArgs, PromiseCreateArgs, PromiseWithCallbackArgs}; +use aurora_engine_types::parameters::{ + NearPromise, PromiseAction, PromiseArgs, PromiseCreateArgs, PromiseWithCallbackArgs, + SimpleNearPromise, +}; use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize}; use near_sdk::collections::{LazyOption, LookupMap}; use near_sdk::json_types::{U128, U64}; @@ -20,9 +23,18 @@ enum StorageKey { const CURRENT_VERSION: u32 = 1; const ERR_ILLEGAL_CALLER: &str = "ERR_ILLEGAL_CALLER"; +/// Gas cost estimated from mainnet data. Cost seems to consistently be 3 Tgas, but we add a +/// little more to be safe. Example: +/// https://explorer.mainnet.near.org/transactions/3U9SKbGKM3MchLa2hLTNuYLdErcEDneJGbGv1cHZXuvE#HsHabUdJ7DRJcseNa4GQTYwm8KtbB4mqsq2AUssJWWv6 const WNEAR_WITHDRAW_GAS: Gas = Gas(5_000_000_000_000); +/// Gas cost estimated from mainnet data. Example: +/// https://explorer.mainnet.near.org/transactions/5NbZ7SfrodNxeLcSkCmLAEdbZfbkk9cjqz3zSDwktKrk#D7un3c3Nxv7Ee3JpQSKiM97LbwCDFPbMo5iLoijGPXPM const WNEAR_REGISTER_GAS: Gas = Gas(5_000_000_000_000); +/// Gas cost estimated from simulation tests. const REFUND_GAS: Gas = Gas(5_000_000_000_000); +/// Registration amount computed from FT token source code, see +/// https://github.com/near/near-sdk-rs/blob/master/near-contract-standards/src/fungible_token/core_impl.rs#L50 +/// https://github.com/near/near-sdk-rs/blob/master/near-contract-standards/src/fungible_token/storage_impl.rs#L101 const WNEAR_REGISTER_AMOUNT: u128 = 1_250_000_000_000_000_000_000; /// Must match arora_engine_precompiles::xcc::state::STORAGE_AMOUNT const REFUND_AMOUNT: u128 = 2_000_000_000_000_000_000_000_000; @@ -188,14 +200,15 @@ impl Router { fn promise_create(promise: PromiseArgs) -> PromiseIndex { match promise { - PromiseArgs::Create(call) => Self::base_promise_create(call), - PromiseArgs::Callback(cb) => Self::cb_promise_create(cb), + PromiseArgs::Create(call) => Self::base_promise_create(&call), + PromiseArgs::Callback(cb) => Self::cb_promise_create(&cb), + PromiseArgs::Recursive(p) => Self::recursive_promise_create(&p), } } - fn cb_promise_create(promise: PromiseWithCallbackArgs) -> PromiseIndex { - let base = Self::base_promise_create(promise.base); - let promise = promise.callback; + fn cb_promise_create(promise: &PromiseWithCallbackArgs) -> PromiseIndex { + let base = Self::base_promise_create(&promise.base); + let promise = &promise.callback; env::promise_then( base, @@ -207,7 +220,7 @@ impl Router { ) } - fn base_promise_create(promise: PromiseCreateArgs) -> PromiseIndex { + fn base_promise_create(promise: &PromiseCreateArgs) -> PromiseIndex { env::promise_create( near_sdk::AccountId::new_unchecked(promise.target_account_id.to_string()), promise.method.as_str(), @@ -216,4 +229,131 @@ impl Router { promise.attached_gas.as_u64().into(), ) } + + fn recursive_promise_create(promise: &NearPromise) -> PromiseIndex { + match promise { + NearPromise::Simple(x) => match x { + SimpleNearPromise::Create(call) => Self::base_promise_create(call), + SimpleNearPromise::Batch(batch) => { + let target = + near_sdk::AccountId::new_unchecked(batch.target_account_id.to_string()); + let id = env::promise_batch_create(&target); + Self::add_batch_actions(id, &batch.actions); + id + } + }, + NearPromise::Then { base, callback } => { + let base_index = Self::recursive_promise_create(base); + match callback { + SimpleNearPromise::Create(call) => env::promise_then( + base_index, + near_sdk::AccountId::new_unchecked(call.target_account_id.to_string()), + call.method.as_str(), + &call.args, + call.attached_balance.as_u128(), + call.attached_gas.as_u64().into(), + ), + SimpleNearPromise::Batch(batch) => { + let target = + near_sdk::AccountId::new_unchecked(batch.target_account_id.to_string()); + let id = env::promise_batch_then(base_index, &target); + Self::add_batch_actions(id, &batch.actions); + id + } + } + } + NearPromise::And(promises) => { + let indices: Vec = promises + .iter() + .map(Self::recursive_promise_create) + .collect(); + env::promise_and(&indices) + } + } + } + + #[cfg(not(feature = "all-promise-actions"))] + fn add_batch_actions(_id: PromiseIndex, _actions: &[PromiseAction]) { + unimplemented!("NEAR batch transactions are not supported. Please file an issue at https://github.com/aurora-is-near/aurora-engine") + } + + #[cfg(feature = "all-promise-actions")] + fn add_batch_actions(id: PromiseIndex, actions: &[PromiseAction]) { + for action in actions.iter() { + match action { + PromiseAction::CreateAccount => env::promise_batch_action_create_account(id), + PromiseAction::Transfer { amount } => { + env::promise_batch_action_transfer(id, amount.as_u128()) + } + PromiseAction::DeployContract { code } => { + env::promise_batch_action_deploy_contract(id, code) + } + PromiseAction::FunctionCall { + name, + args, + attached_yocto, + gas, + } => env::promise_batch_action_function_call( + id, + name, + args, + attached_yocto.as_u128(), + gas.as_u64().into(), + ), + PromiseAction::Stake { amount, public_key } => { + env::promise_batch_action_stake(id, amount.as_u128(), &to_sdk_pk(public_key)) + } + PromiseAction::AddFullAccessKey { public_key, nonce } => { + env::promise_batch_action_add_key_with_full_access( + id, + &to_sdk_pk(public_key), + *nonce, + ) + } + PromiseAction::AddFunctionCallKey { + public_key, + nonce, + allowance, + receiver_id, + function_names, + } => { + let receiver_id = near_sdk::AccountId::new_unchecked(receiver_id.to_string()); + env::promise_batch_action_add_key_with_function_call( + id, + &to_sdk_pk(public_key), + *nonce, + allowance.as_u128(), + &receiver_id, + function_names, + ) + } + PromiseAction::DeleteKey { public_key } => { + env::promise_batch_action_delete_key(id, &to_sdk_pk(public_key)) + } + PromiseAction::DeleteAccount { beneficiary_id } => { + let beneficiary_id = + near_sdk::AccountId::new_unchecked(beneficiary_id.to_string()); + env::promise_batch_action_delete_account(id, &beneficiary_id) + } + } + } + } +} + +#[cfg(feature = "all-promise-actions")] +fn to_sdk_pk(key: &aurora_engine_types::parameters::NearPublicKey) -> near_sdk::PublicKey { + let (curve_type, key_bytes): (near_sdk::CurveType, &[u8]) = match key { + aurora_engine_types::parameters::NearPublicKey::Ed25519(bytes) => { + (near_sdk::CurveType::ED25519, bytes) + } + aurora_engine_types::parameters::NearPublicKey::Secp256k1(bytes) => { + (near_sdk::CurveType::SECP256K1, bytes) + } + }; + let mut data = Vec::with_capacity(1 + key_bytes.len()); + data.push(curve_type as u8); + data.extend_from_slice(key_bytes); + + // Unwrap should be safe because we only encode valid public keys + data.try_into().unwrap() } diff --git a/rust-toolchain b/rust-toolchain index 2a84a09b7..067dff55b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2022-01-26" +channel = "nightly-2022-09-29" components = [] targets = ["wasm32-unknown-unknown"] diff --git a/scripts/docker-entrypoint.sh b/scripts/docker-entrypoint.sh new file mode 100755 index 000000000..ce11f20d6 --- /dev/null +++ b/scripts/docker-entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cargo install --no-default-features --force cargo-make +cargo make --profile "$1" build-docker-inner diff --git a/verify_evm_erc20.sh b/scripts/verify_evm_erc20.sh similarity index 100% rename from verify_evm_erc20.sh rename to scripts/verify_evm_erc20.sh