diff --git a/.github/workflows/coverage.yaml b/.github/workflows/coverage.yaml index 64569f848b2cd..0a08eb2185df2 100644 --- a/.github/workflows/coverage.yaml +++ b/.github/workflows/coverage.yaml @@ -41,6 +41,7 @@ jobs: - run: cargo llvm-cov --ignore-run-fail --workspace --exclude smoke-test --exclude aptos-testcases --lcov --jobs 32 --output-path lcov_unit.info -vv env: INDEXER_DATABASE_URL: postgresql://postgres@localhost/postgres + RUST_MIN_STACK: 33554432 # 32 MB of stack - uses: actions/upload-artifact@v3 with: name: lcov_unit @@ -65,6 +66,7 @@ jobs: - run: cargo llvm-cov --ignore-run-fail --package smoke-test --lcov --output-path lcov_smoke.info -vv env: INDEXER_DATABASE_URL: postgresql://postgres@localhost/postgres + RUST_MIN_STACK: 33554432 - uses: actions/upload-artifact@v3 with: name: lcov_smoke diff --git a/.github/workflows/docker-build-test.yaml b/.github/workflows/docker-build-test.yaml index 1fda1375b42ad..5c35dee1f0cb8 100644 --- a/.github/workflows/docker-build-test.yaml +++ b/.github/workflows/docker-build-test.yaml @@ -300,7 +300,7 @@ jobs: with: GIT_SHA: ${{ needs.determine-docker-build-metadata.outputs.gitSha }} FORGE_TEST_SUITE: compat - IMAGE_TAG: aptos-node-v1.10.1 # test against a previous testnet release + IMAGE_TAG: 01b24e7e3548382dd25440b39a0438a993387f12 #aptos-node-v1.11 with randomness disabled in genesis FORGE_RUNNER_DURATION_SECS: 300 COMMENT_HEADER: forge-compat FORGE_NAMESPACE: forge-compat-${{ needs.determine-docker-build-metadata.outputs.targetCacheId }} @@ -327,7 +327,7 @@ jobs: with: GIT_SHA: ${{ needs.determine-docker-build-metadata.outputs.gitSha }} FORGE_TEST_SUITE: framework_upgrade - IMAGE_TAG: aptos-node-v1.10.1 # This workflow will test the upgradability from the current tip of the release branch to the current main branch. + IMAGE_TAG: 01b24e7e3548382dd25440b39a0438a993387f12 #aptos-node-v1.11 with randomness disabled in genesis FORGE_RUNNER_DURATION_SECS: 3600 COMMENT_HEADER: forge-framework-upgrade FORGE_NAMESPACE: forge-framework-upgrade-${{ needs.determine-docker-build-metadata.outputs.targetCacheId }} diff --git a/.github/workflows/forge-stable.yaml b/.github/workflows/forge-stable.yaml index 2d23c30738395..be622da09acb6 100644 --- a/.github/workflows/forge-stable.yaml +++ b/.github/workflows/forge-stable.yaml @@ -118,19 +118,20 @@ jobs: ### Real-world-network tests. # Run forge framework upgradability test. This is a PR required job. run-forge-framework-upgrade-test: + if: ${{ github.event_name != 'pull_request' }} needs: - determine-test-metadata uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: - IMAGE_TAG: aptos-node-v1.10.1 # This workflow will test the upgradability from the current tip of the release branch to the current main branch. + IMAGE_TAG: 01b24e7e3548382dd25440b39a0438a993387f12 #aptos-node-v1.11 with randomness disabled in genesis FORGE_NAMESPACE: forge-framework-upgrade-${{ needs.determine-test-metadata.outputs.BRANCH_HASH }} FORGE_RUNNER_DURATION_SECS: 7200 # Run for 2 hours FORGE_TEST_SUITE: framework_upgrade POST_TO_SLACK: true run-forge-realistic-env-max-load-long: - if: ${{ github.event_name != 'pull_request' }} + if: ${{ github.event_name != 'pull_request' && always() }} needs: [determine-test-metadata, run-forge-framework-upgrade-test] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit @@ -265,7 +266,7 @@ jobs: FORGE_RUNNER_DURATION_SECS: 300 # Run for 5 minutes # This will upgrade from testnet branch to the latest main FORGE_TEST_SUITE: compat - IMAGE_TAG: testnet + IMAGE_TAG: 01b24e7e3548382dd25440b39a0438a993387f12 #aptos-node-v1.11 with randomness disabled in genesis GIT_SHA: ${{ needs.determine-test-metadata.outputs.IMAGE_TAG }} # this is the git ref to checkout POST_TO_SLACK: true diff --git a/CODEOWNERS b/CODEOWNERS index 7186d39392ecb..00ad990ce20e3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,7 +1,7 @@ # **Please** keep this file ordered alphabetically by directory paths. # Owners for the `.github` directory and all its subdirectories. -/.github/ @aptos-labs/prod-eng @aptos-labs/security +/.github/ @aptos-labs/prod-eng # Owners for the `/api` directory and all its subdirectories. /api/ @banool @gregnazario @0xmaayan diff --git a/Cargo.lock b/Cargo.lock index db6bbf1d1c8d0..9b7d923870300 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ name = "abstract-domain-derive" version = "0.1.0" dependencies = [ "move-stackless-bytecode", - "proc-macro2 1.0.76", - "quote 1.0.35", - "syn 2.0.48", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -92,9 +92,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom 0.2.11", @@ -409,7 +409,7 @@ dependencies = [ "async-trait", "bcs 0.1.4", "bytes", - "fail 0.5.1", + "fail", "futures", "hex", "hyper", @@ -608,7 +608,7 @@ version = "0.1.0" dependencies = [ "bcs 0.1.4", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "serde", "serde_bytes", "serde_json", @@ -637,7 +637,7 @@ dependencies = [ "crossbeam", "dashmap", "derivative", - "fail 0.5.1", + "fail", "itertools 0.12.1", "move-binary-format", "move-core-types", @@ -646,7 +646,7 @@ dependencies = [ "once_cell", "parking_lot 0.12.1", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "rayon", "scopeguard", @@ -702,7 +702,7 @@ dependencies = [ "move-core-types", "once_cell", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", ] [[package]] @@ -870,7 +870,7 @@ dependencies = [ "clap 4.4.14", "dashmap", "enum_dispatch", - "fail 0.5.1", + "fail", "futures", "futures-channel", "hex", @@ -963,6 +963,7 @@ dependencies = [ "ark-bn254", "ark-ec", "ark-ff", + "ark-groth16", "ark-serialize", "ark-std", "base64 0.13.1", @@ -990,7 +991,7 @@ dependencies = [ "p256", "poseidon-ark", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "rand_core 0.5.1", "ring 0.16.20", @@ -1014,8 +1015,8 @@ name = "aptos-crypto-derive" version = "0.0.3" dependencies = [ "anyhow", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -1124,7 +1125,7 @@ dependencies = [ "once_cell", "owo-colors", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "rayon", "serde", @@ -1151,7 +1152,7 @@ dependencies = [ "move-core-types", "move-resource-viewer", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "serde", ] @@ -1250,7 +1251,7 @@ dependencies = [ "async-trait", "bcs 0.1.4", "bytes", - "fail 0.5.1", + "fail", "futures", "futures-channel", "futures-util", @@ -1277,7 +1278,7 @@ name = "aptos-enum-conversion-derive" version = "0.0.3" dependencies = [ "anyhow", - "quote 1.0.35", + "quote", "syn 1.0.109", "trybuild", ] @@ -1317,7 +1318,7 @@ dependencies = [ "claims", "dashmap", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rayon", ] @@ -1350,7 +1351,7 @@ dependencies = [ "bcs 0.1.4", "bytes", "dashmap", - "fail 0.5.1", + "fail", "itertools 0.12.1", "move-core-types", "once_cell", @@ -2240,7 +2241,7 @@ dependencies = [ "num-traits", "once_cell", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "rayon", "serde", @@ -2391,12 +2392,13 @@ dependencies = [ "move-core-types", "move-ir-compiler", "move-model", + "move-vm-runtime", "move-vm-types", "num_cpus", "once_cell", "petgraph 0.5.1", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "rayon", "serde", @@ -2418,8 +2420,8 @@ dependencies = [ name = "aptos-log-derive" version = "0.1.0" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -2489,7 +2491,7 @@ dependencies = [ "aptos-vm-validator", "bcs 0.1.4", "enum_dispatch", - "fail 0.5.1", + "fail", "futures", "itertools 0.12.1", "maplit", @@ -2545,7 +2547,6 @@ dependencies = [ "aptos-crypto", "aptos-gas-meter", "aptos-gas-profiling", - "aptos-gas-schedule", "aptos-logger", "aptos-memory-usage-tracker", "aptos-rest-client", @@ -2556,7 +2557,6 @@ dependencies = [ "aptos-vm-types", "bcs 0.1.4", "clap 4.4.14", - "move-binary-format", "regex", "reqwest", "tokio", @@ -2646,7 +2646,7 @@ dependencies = [ "move-core-types", "move-vm-types", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rayon", "serde", "test-case", @@ -2719,7 +2719,7 @@ dependencies = [ "ordered-float 3.9.2", "pin-project 1.1.3", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "rand 0.8.5", "rand_core 0.5.1", @@ -2905,7 +2905,7 @@ dependencies = [ "bcs 0.1.4", "clap 4.4.14", "either", - "fail 0.5.1", + "fail", "futures", "hex", "jemallocator", @@ -2977,8 +2977,8 @@ dependencies = [ name = "aptos-num-variants" version = "0.1.0" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3109,7 +3109,7 @@ version = "0.1.0" dependencies = [ "crossbeam", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", ] [[package]] @@ -3499,7 +3499,7 @@ dependencies = [ "crossbeam", "parking_lot 0.12.1", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rayon", ] @@ -3571,7 +3571,7 @@ dependencies = [ "once_cell", "parking_lot 0.12.1", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rayon", "rocksdb", "serde", @@ -3930,6 +3930,7 @@ dependencies = [ "move-bytecode-verifier", "move-command-line-common", "move-compiler", + "move-compiler-v2", "move-core-types", "move-model", "move-resource-viewer", @@ -3979,10 +3980,11 @@ dependencies = [ "passkey-client", "passkey-types", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "rayon", "regex", + "reqwest", "ring 0.16.20", "rsa 0.9.6", "serde", @@ -4080,12 +4082,14 @@ dependencies = [ "aptos-utils", "aptos-vm-logging", "aptos-vm-types", + "ark-bn254", + "ark-groth16", "bcs 0.1.4", "bytes", "claims", "crossbeam-channel", "derive_more", - "fail 0.5.1", + "fail", "futures", "hex", "move-binary-format", @@ -4096,7 +4100,7 @@ dependencies = [ "move-vm-types", "num_cpus", "once_cell", - "ouroboros 0.15.6", + "ouroboros", "proptest", "rand 0.7.3", "rand_core 0.5.1", @@ -4133,10 +4137,11 @@ dependencies = [ "bcs 0.1.4", "bytes", "move-core-types", + "move-vm-runtime", "move-vm-types", "once_cell", "proptest", - "proptest-derive 0.4.0", + "proptest-derive", "rand 0.7.3", "serde", ] @@ -4221,7 +4226,7 @@ dependencies = [ "aptos-vm", "aptos-vm-genesis", "aptos-vm-logging", - "fail 0.5.1", + "fail", "move-core-types", "rand 0.7.3", ] @@ -4256,6 +4261,7 @@ dependencies = [ "handlebars", "move-compiler", "move-core-types", + "move-vm-runtime", "move-vm-types", "serde", "tempfile", @@ -4363,7 +4369,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -4375,8 +4381,8 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint 0.4.4", "num-traits", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -4440,8 +4446,8 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -4486,7 +4492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c6368f9ae5c6ec403ca910327ae0c9437b0a85255b6950c90d497e6177f6e5e" dependencies = [ "proc-macro-hack", - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -4717,8 +4723,8 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -4784,8 +4790,8 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -4801,8 +4807,8 @@ version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -4830,20 +4836,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.76", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "auto_impl" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" -dependencies = [ - "proc-macro-error", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -5085,8 +5079,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3deeecb812ca5300b7d3f66f730cc2ebd3511c3d36c691dd79c165d5b19a26e3" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -5126,8 +5120,8 @@ dependencies = [ "lazycell", "peeking_take_while", "prettyplease", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "regex", "rustc-hash", "shlex", @@ -5423,7 +5417,7 @@ dependencies = [ name = "bytecode-verifier-tests" version = "0.1.0" dependencies = [ - "fail 0.4.0", + "fail", "hex", "invalid-mutations", "move-binary-format", @@ -5791,8 +5785,8 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -5803,8 +5797,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -5928,7 +5922,7 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ - "encode_unicode", + "encode_unicode 0.3.6", "lazy_static", "libc", "unicode-width", @@ -6004,9 +5998,9 @@ version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", - "unicode-xid 0.2.4", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] @@ -6440,8 +6434,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -6497,8 +6491,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "strsim 0.10.0", "syn 1.0.109", ] @@ -6511,8 +6505,8 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "strsim 0.10.0", "syn 1.0.109", ] @@ -6525,8 +6519,8 @@ checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "strsim 0.10.0", "syn 2.0.48", ] @@ -6538,7 +6532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core 0.13.4", - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -6549,7 +6543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ "darling_core 0.14.4", - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -6560,7 +6554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", - "quote 1.0.35", + "quote", "syn 2.0.48", ] @@ -6688,8 +6682,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -6699,8 +6693,8 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -6711,8 +6705,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "rustc_version", "syn 1.0.109", ] @@ -6807,8 +6801,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" dependencies = [ "diesel_table_macro_syntax", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -7139,6 +7133,12 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -7155,8 +7155,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" dependencies = [ "once_cell", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -7215,11 +7215,11 @@ dependencies = [ [[package]] name = "ethabi" -version = "17.2.0" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" dependencies = [ - "ethereum-types 0.13.1", + "ethereum-types 0.14.1", "hex", "once_cell", "regex", @@ -7240,20 +7240,7 @@ dependencies = [ "fixed-hash 0.7.0", "impl-codec 0.5.1", "impl-rlp", - "scale-info 1.0.0", - "tiny-keccak", -] - -[[package]] -name = "ethbloom" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" -dependencies = [ - "crunchy", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde", + "scale-info", "tiny-keccak", ] @@ -7265,9 +7252,8 @@ checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", "fixed-hash 0.8.0", - "impl-codec 0.6.0", "impl-rlp", - "scale-info 2.10.0", + "impl-serde 0.4.0", "tiny-keccak", ] @@ -7279,35 +7265,17 @@ checksum = "34c90e0a755da706ce0970ec0fa8cc48aabcc8e8efa1245336acf718dab06ffe" dependencies = [ "bytes", "ethereum-types 0.12.1", - "hash-db 0.15.2", + "hash-db", "hash256-std-hasher", "parity-scale-codec 2.3.1", "rlp", "rlp-derive", - "scale-info 1.0.0", + "scale-info", "serde", "sha3 0.9.1", "triehash", ] -[[package]] -name = "ethereum" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04d24d20b8ff2235cffbf242d5092de3aa45f77c5270ddbfadd2778ca13fea" -dependencies = [ - "bytes", - "ethereum-types 0.14.1", - "hash-db 0.16.0", - "hash256-std-hasher", - "parity-scale-codec 3.6.9", - "rlp", - "scale-info 2.10.0", - "serde", - "sha3 0.10.8", - "trie-root", -] - [[package]] name = "ethereum-types" version = "0.12.1" @@ -7319,21 +7287,7 @@ dependencies = [ "impl-codec 0.5.1", "impl-rlp", "primitive-types 0.10.1", - "scale-info 1.0.0", - "uint", -] - -[[package]] -name = "ethereum-types" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" -dependencies = [ - "ethbloom 0.12.1", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde", - "primitive-types 0.11.1", + "scale-info", "uint", ] @@ -7345,10 +7299,9 @@ checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ "ethbloom 0.13.0", "fixed-hash 0.8.0", - "impl-codec 0.6.0", "impl-rlp", + "impl-serde 0.4.0", "primitive-types 0.12.2", - "scale-info 2.10.0", "uint", ] @@ -7402,42 +7355,21 @@ version = "0.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "408ffdd509e16de15ea9b51f5333748f6086601f29d445d2ba53dd7e95565574" dependencies = [ - "auto_impl 0.5.0", + "auto_impl", "environmental", - "ethereum 0.11.1", - "evm-core 0.33.0", - "evm-gasometer 0.33.0", - "evm-runtime 0.33.0", + "ethereum", + "evm-core", + "evm-gasometer", + "evm-runtime", "log", "parity-scale-codec 2.3.1", "primitive-types 0.10.1", "rlp", - "scale-info 1.0.0", + "scale-info", "serde", "sha3 0.8.2", ] -[[package]] -name = "evm" -version = "0.41.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "767f43e9630cc36cf8ff2777cbb0121b055f0d1fd6eaaa13b46a1808f0d0e7e9" -dependencies = [ - "auto_impl 1.1.0", - "environmental", - "ethereum 0.15.0", - "evm-core 0.41.0", - "evm-gasometer 0.41.0", - "evm-runtime 0.41.0", - "log", - "parity-scale-codec 3.6.9", - "primitive-types 0.12.2", - "rlp", - "scale-info 2.10.0", - "serde", - "sha3 0.10.8", -] - [[package]] name = "evm-core" version = "0.33.0" @@ -7447,19 +7379,7 @@ dependencies = [ "funty 1.1.0", "parity-scale-codec 2.3.1", "primitive-types 0.10.1", - "scale-info 1.0.0", - "serde", -] - -[[package]] -name = "evm-core" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da6cedc5cedb4208e59467106db0d1f50db01b920920589f8e672c02fdc04f" -dependencies = [ - "parity-scale-codec 3.6.9", - "primitive-types 0.12.2", - "scale-info 2.10.0", + "scale-info", "serde", ] @@ -7468,8 +7388,8 @@ name = "evm-exec-utils" version = "0.1.0" dependencies = [ "anyhow", - "evm 0.33.1", - "evm-runtime 0.33.0", + "evm", + "evm-runtime", "hex", "move-command-line-common", "primitive-types 0.10.1", @@ -7484,23 +7404,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c446679607eacac4e8c8738e20c97ea9b3c86eddd8b43666744b05f416037bd9" dependencies = [ "environmental", - "evm-core 0.33.0", - "evm-runtime 0.33.0", + "evm-core", + "evm-runtime", "primitive-types 0.10.1", ] -[[package]] -name = "evm-gasometer" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dc0eb591abc5cd7b05bef6a036c2bb6c66ab6c5e0c5ce94bfe377ab670b1fd7" -dependencies = [ - "environmental", - "evm-core 0.41.0", - "evm-runtime 0.41.0", - "primitive-types 0.12.2", -] - [[package]] name = "evm-runtime" version = "0.33.0" @@ -7508,24 +7416,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "419e8434ac6e850a8a4bc09a19406264582d1940913b2920be2af948f4ffc49b" dependencies = [ "environmental", - "evm-core 0.33.0", + "evm-core", "primitive-types 0.10.1", "sha3 0.8.2", ] -[[package]] -name = "evm-runtime" -version = "0.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84bbe09b64ae13a29514048c1bb6fda6374ac0b4f6a1f15a443348ab88ef42cd" -dependencies = [ - "auto_impl 1.1.0", - "environmental", - "evm-core 0.41.0", - "primitive-types 0.12.2", - "sha3 0.10.8", -] - [[package]] name = "exr" version = "1.71.0" @@ -7543,14 +7438,15 @@ dependencies = [ ] [[package]] -name = "fail" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be3c61c59fdc91f5dbc3ea31ee8623122ce80057058be560654c5d410d181a6" +name = "extract-ethereum-abi" +version = "0.1.0" dependencies = [ - "lazy_static", - "log", - "rand 0.7.3", + "anyhow", + "atty", + "clap 4.4.14", + "codespan-reporting", + "move-to-yul", + "serde_json", ] [[package]] @@ -7635,7 +7531,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1320970ff3b1c1cacc6a38e8cdb1aced955f29627697cd992c5ded82eb646a8" dependencies = [ - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -7798,8 +7694,8 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -7930,8 +7826,8 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -8396,7 +8292,7 @@ version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34e99a7734579b834a076ef11789783c153c6eb5fb3520ed15bc41f483f0f317" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", "camino", "cargo_metadata 0.18.1", "cfg-if", @@ -8495,12 +8391,6 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" -[[package]] -name = "hash-db" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" - [[package]] name = "hash256-std-hasher" version = "0.15.2" @@ -8525,7 +8415,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", ] [[package]] @@ -8534,7 +8424,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", "allocator-api2", ] @@ -9036,14 +8926,23 @@ dependencies = [ "serde", ] +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + [[package]] name = "impl-trait-for-tuples" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -9066,8 +8965,8 @@ checksum = "0a0c890c85da4bab7bce4204c707396bbd3c6c8a681716a51c8814cfc2b682df" dependencies = [ "anyhow", "proc-macro-hack", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -9130,7 +9029,7 @@ version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "321f0f839cd44a4686e9504b0a62b4d69a50b62072144c71c68f5873c167b8d9" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", "clap 4.4.14", "crossbeam-channel", "crossbeam-utils", @@ -9509,8 +9408,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98ff3d647085c6c025083efad0435890867f4bea042fc62d408ab3aeb1cdf66" dependencies = [ "darling 0.13.4", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "serde_json", "syn 1.0.109", ] @@ -9543,7 +9442,7 @@ dependencies = [ "string_cache", "term", "tiny-keccak", - "unicode-xid 0.2.4", + "unicode-xid", ] [[package]] @@ -9569,7 +9468,7 @@ dependencies = [ "aptos-vm", "aptos-vm-genesis", "claims", - "fail 0.5.1", + "fail", "move-binary-format", "move-bytecode-verifier", "move-core-types", @@ -9894,31 +9793,6 @@ dependencies = [ "hashbrown 0.13.2", ] -[[package]] -name = "lsp-server" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c351c75989da23b355226dc188dc2b52538a7f4f218d70fd7393c6b62b110444" -dependencies = [ - "crossbeam-channel", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "lsp-types" -version = "0.90.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f3734ab1d7d157fc0c45110e06b587c31cd82bea2ccfd6b563cbff0aaeeb1d3" -dependencies = [ - "bitflags 1.3.2", - "serde", - "serde_json", - "serde_repr", - "url", -] - [[package]] name = "lz4" version = "1.24.0" @@ -9944,8 +9818,8 @@ name = "macros" version = "0.1.0" source = "git+https://github.com/niroco/diesel_async_migrations?rev=11f331b73c5cfcc894380074f748d8fda710ac12#11f331b73c5cfcc894380074f748d8fda710ac12" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", ] [[package]] @@ -10060,8 +9934,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08" dependencies = [ "migrations_internals", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", ] [[package]] @@ -10151,8 +10025,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -10194,7 +10068,7 @@ dependencies = [ "bcs 0.1.4", "codespan-reporting", "datatest-stable", - "heck 0.3.3", + "heck 0.4.1", "log", "move-binary-format", "move-bytecode-verifier", @@ -10207,29 +10081,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "move-analyzer" -version = "1.0.0" -dependencies = [ - "anyhow", - "clap 4.4.14", - "codespan-reporting", - "crossbeam", - "derivative", - "dunce", - "im", - "lsp-server", - "lsp-types", - "move-command-line-common", - "move-compiler", - "move-ir-types", - "move-package", - "move-symbol-pool", - "serde_json", - "tempfile", - "url", -] - [[package]] name = "move-async-vm" version = "0.1.0" @@ -10238,7 +10089,7 @@ dependencies = [ "better_any", "bytes", "datatest-stable", - "itertools 0.10.5", + "itertools 0.12.1", "move-binary-format", "move-command-line-common", "move-compiler", @@ -10262,7 +10113,7 @@ dependencies = [ "indexmap 1.9.3", "move-core-types", "proptest", - "proptest-derive 0.3.0", + "proptest-derive", "ref-cast", "serde", "serde_json", @@ -10302,7 +10153,7 @@ dependencies = [ name = "move-bytecode-verifier" version = "0.1.0" dependencies = [ - "fail 0.4.0", + "fail", "hex-literal", "invalid-mutations", "move-binary-format", @@ -10380,7 +10231,7 @@ dependencies = [ "dirs-next", "hex", "move-core-types", - "num-bigint 0.4.4", + "num-bigint 0.3.3", "once_cell", "serde", "sha2 0.9.9", @@ -10435,7 +10286,7 @@ dependencies = [ "ethnum", "flexi_logger", "im", - "itertools 0.10.5", + "itertools 0.12.1", "log", "move-binary-format", "move-bytecode-source-map", @@ -10451,7 +10302,7 @@ dependencies = [ "move-symbol-pool", "num 0.4.1", "once_cell", - "petgraph 0.6.4", + "petgraph 0.5.1", "walkdir", ] @@ -10460,7 +10311,7 @@ name = "move-compiler-v2-transactional-tests" version = "0.1.0" dependencies = [ "datatest-stable", - "itertools 0.10.5", + "itertools 0.12.1", "move-command-line-common", "move-compiler-v2", "move-model", @@ -10484,7 +10335,7 @@ dependencies = [ "once_cell", "primitive-types 0.10.1", "proptest", - "proptest-derive 0.3.0", + "proptest-derive", "rand 0.8.5", "ref-cast", "regex", @@ -10537,7 +10388,7 @@ dependencies = [ "codespan", "codespan-reporting", "datatest-stable", - "itertools 0.10.5", + "itertools 0.12.1", "log", "move-compiler", "move-core-types", @@ -10627,7 +10478,7 @@ dependencies = [ "move-ir-to-bytecode-syntax", "move-ir-types", "move-symbol-pool", - "ouroboros 0.9.5", + "ouroboros", ] [[package]] @@ -10663,7 +10514,7 @@ dependencies = [ "codespan-reporting", "datatest-stable", "internment", - "itertools 0.10.5", + "itertools 0.12.1", "log", "move-binary-format", "move-bytecode-source-map", @@ -10691,7 +10542,7 @@ dependencies = [ "datatest-stable", "evm-exec-utils", "hex", - "itertools 0.10.5", + "itertools 0.12.1", "move-abigen", "move-binary-format", "move-bytecode-source-map", @@ -10713,7 +10564,7 @@ dependencies = [ "sha2 0.9.9", "tempfile", "termcolor", - "toml 0.5.11", + "toml 0.7.8", "walkdir", "whoami", ] @@ -10727,7 +10578,7 @@ dependencies = [ "clap 4.4.14", "codespan-reporting", "datatest-stable", - "itertools 0.10.5", + "itertools 0.12.1", "log", "move-abigen", "move-command-line-common", @@ -10745,7 +10596,7 @@ dependencies = [ "shell-words", "simplelog", "tempfile", - "toml 0.5.11", + "toml 0.7.8", "walkdir", ] @@ -10758,7 +10609,7 @@ dependencies = [ "codespan", "codespan-reporting", "futures", - "itertools 0.10.5", + "itertools 0.12.1", "log", "move-binary-format", "move-command-line-common", @@ -10770,7 +10621,7 @@ dependencies = [ "num 0.4.1", "once_cell", "pretty", - "rand 0.8.5", + "rand 0.7.3", "regex", "serde", "tera", @@ -10785,7 +10636,7 @@ dependencies = [ "anyhow", "codespan-reporting", "datatest-stable", - "itertools 0.10.5", + "itertools 0.12.1", "log", "move-binary-format", "move-core-types", @@ -10830,7 +10681,7 @@ dependencies = [ "datatest-stable", "ethnum", "im", - "itertools 0.10.5", + "itertools 0.12.1", "log", "move-binary-format", "move-core-types", @@ -10923,9 +10774,9 @@ dependencies = [ "codespan-reporting", "datatest-stable", "ethnum", - "evm 0.33.1", + "evm", "evm-exec-utils", - "itertools 0.10.5", + "itertools 0.12.1", "maplit", "move-command-line-common", "move-compiler", @@ -10986,9 +10837,9 @@ dependencies = [ "colored", "datatest-stable", "difference", - "evm 0.41.1", + "evm", "evm-exec-utils", - "itertools 0.10.5", + "itertools 0.12.1", "move-binary-format", "move-bytecode-utils", "move-command-line-common", @@ -11023,6 +10874,7 @@ dependencies = [ "move-vm-runtime", "move-vm-test-utils", "move-vm-types", + "smallvec", "tempfile", ] @@ -11031,7 +10883,7 @@ name = "move-vm-paranoid-tests" version = "0.1.0" dependencies = [ "datatest-stable", - "fail 0.4.0", + "fail", "move-transactional-test-runner", ] @@ -11042,7 +10894,7 @@ dependencies = [ "anyhow", "better_any", "bytes", - "fail 0.4.0", + "fail", "hashbrown 0.14.3", "hex", "lazy_static", @@ -11054,7 +10906,7 @@ dependencies = [ "move-ir-compiler", "move-vm-types", "once_cell", - "parking_lot 0.11.2", + "parking_lot 0.12.1", "proptest", "serde", "sha3 0.9.1", @@ -11091,11 +10943,11 @@ dependencies = [ "bcs 0.1.4", "claims", "derivative", - "itertools 0.10.5", + "itertools 0.12.1", "move-binary-format", "move-core-types", "proptest", - "rand 0.8.5", + "rand 0.7.3", "serde", "smallbitvec", "smallvec", @@ -11143,8 +10995,8 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -11267,8 +11119,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be7d33be719c6f4d09e64e27c1ef4e73485dc4cc1f4d22201f89860a7fe22e22" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -11279,8 +11131,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "066b468120587a402f0b47d8f80035c921f6a46f8209efd0632a89a16f5188a4" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -11406,8 +11258,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -11572,8 +11424,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -11625,16 +11477,6 @@ version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" -[[package]] -name = "ouroboros" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeff60e3e37407a80ead3e9458145b456e978c4068cddbfea6afb48572962ca" -dependencies = [ - "ouroboros_macro 0.9.5", - "stable_deref_trait", -] - [[package]] name = "ouroboros" version = "0.15.6" @@ -11642,20 +11484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" dependencies = [ "aliasable", - "ouroboros_macro 0.15.6", -] - -[[package]] -name = "ouroboros_macro" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f2cb802b5bdfdf52f1ffa0b54ce105e4d346e91990dd571f86c91321ad49e2" -dependencies = [ - "Inflector", - "proc-macro-error", - "proc-macro2 1.0.76", - "quote 1.0.35", - "syn 1.0.109", + "ouroboros_macro", ] [[package]] @@ -11666,8 +11495,8 @@ checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" dependencies = [ "Inflector", "proc-macro-error", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -11748,8 +11577,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -11760,8 +11589,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" dependencies = [ "proc-macro-crate 2.0.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -12003,8 +11832,8 @@ checksum = "2a31940305ffc96863a735bef7c7994a00b325a7138fdbc5bda0f1a0476d3275" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -12110,8 +11939,8 @@ version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "851c8d0ce9bebe43790dedfc86614c23494ac9f423dd618d3a61fc693eafe61e" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -12121,8 +11950,8 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -12293,8 +12122,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ddcf4680d8d867e1e375116203846acb088483fa2070244f90589f458bbb31" dependencies = [ "proc-macro-crate 2.0.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -12334,8 +12163,8 @@ dependencies = [ "indexmap 1.9.3", "mime", "proc-macro-crate 1.3.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "regex", "syn 1.0.109", "thiserror", @@ -12398,8 +12227,8 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597c3287a549da151aca6ada2795ecde089c7527bd5093114e8e0e1c3f0e52b1" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -12569,6 +12398,8 @@ checksum = "8ff1fec61082821f8236cf6c0c14e8172b62ce8a72a0eedc30d3b247bb68dc11" dependencies = [ "ansi_term", "pad", + "prettytable-rs", + "structopt", ] [[package]] @@ -12577,10 +12408,24 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ - "proc-macro2 1.0.76", + "proc-macro2", "syn 2.0.48", ] +[[package]] +name = "prettytable-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +dependencies = [ + "csv", + "encode_unicode 1.0.0", + "is-terminal", + "lazy_static", + "term", + "unicode-width", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -12599,21 +12444,8 @@ dependencies = [ "fixed-hash 0.7.0", "impl-codec 0.5.1", "impl-rlp", - "impl-serde", - "scale-info 1.0.0", - "uint", -] - -[[package]] -name = "primitive-types" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" -dependencies = [ - "fixed-hash 0.7.0", - "impl-codec 0.6.0", - "impl-rlp", - "impl-serde", + "impl-serde 0.3.2", + "scale-info", "uint", ] @@ -12626,7 +12458,7 @@ dependencies = [ "fixed-hash 0.8.0", "impl-codec 0.6.0", "impl-rlp", - "scale-info 2.10.0", + "impl-serde 0.4.0", "uint", ] @@ -12657,8 +12489,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", "version_check", ] @@ -12669,8 +12501,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "version_check", ] @@ -12686,15 +12518,6 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - [[package]] name = "proc-macro2" version = "1.0.76" @@ -12709,7 +12532,7 @@ name = "processor" version = "1.0.0" source = "git+https://github.com/aptos-labs/aptos-indexer-processors.git?rev=a11f0b6532349aa6b9a80c9a1d77524f02d8a013#a11f0b6532349aa6b9a80c9a1d77524f02d8a013" dependencies = [ - "ahash 0.8.8", + "ahash 0.8.11", "anyhow", "aptos-moving-average 0.1.0 (git+https://github.com/aptos-labs/aptos-indexer-processors.git?rev=a11f0b6532349aa6b9a80c9a1d77524f02d8a013)", "aptos-protos 1.3.0 (git+https://github.com/aptos-labs/aptos-core.git?tag=aptos-node-v1.10.0)", @@ -12835,25 +12658,14 @@ dependencies = [ "unarray", ] -[[package]] -name = "proptest-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90b46295382dc76166cb7cf2bb4a97952464e4b7ed5a43e6cd34e1fec3349ddc" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "syn 0.15.44", -] - [[package]] name = "proptest-derive" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf16337405ca084e9c78985114633b6827711d22b9e6ef6c6c0d665eb3f0b6e" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -12885,8 +12697,8 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -12898,8 +12710,8 @@ checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", "itertools 0.11.0", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -12954,7 +12766,7 @@ dependencies = [ "chrono", "clap 4.4.14", "codespan-reporting", - "itertools 0.10.5", + "itertools 0.12.1", "log", "move-compiler", "move-model", @@ -13051,22 +12863,13 @@ dependencies = [ "serde", ] -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.76", + "proc-macro2", ] [[package]] @@ -13303,8 +13106,8 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -13529,7 +13332,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", - "rlp-derive", "rustc-hex", ] @@ -13539,8 +13341,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -13641,8 +13443,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5015e68a0685a95ade3eee617ff7101ab6a3fc689203101ca16ebc16f2b89c66" dependencies = [ "cfg-if", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "rustc_version", "syn 1.0.109", ] @@ -13904,20 +13706,7 @@ dependencies = [ "cfg-if", "derive_more", "parity-scale-codec 2.3.1", - "scale-info-derive 1.0.0", -] - -[[package]] -name = "scale-info" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60" -dependencies = [ - "bitvec 1.0.1", - "cfg-if", - "derive_more", - "parity-scale-codec 3.6.9", - "scale-info-derive 2.10.0", + "scale-info-derive", ] [[package]] @@ -13927,20 +13716,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baeb2780690380592f86205aa4ee49815feb2acad8c2f59e6dd207148c3f1fcd" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.76", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "scale-info-derive" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -14192,8 +13969,8 @@ version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -14236,8 +14013,8 @@ version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -14286,8 +14063,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" dependencies = [ "darling 0.20.3", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -14333,7 +14110,7 @@ dependencies = [ "move-binary-format", "move-core-types", "proptest", - "proptest-derive 0.3.0", + "proptest-derive", ] [[package]] @@ -14767,8 +14544,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -14910,8 +14687,8 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -14940,8 +14717,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "rustversion", "syn 1.0.109", ] @@ -14953,8 +14730,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "rustversion", "syn 2.0.48", ] @@ -14994,25 +14771,14 @@ dependencies = [ "symbolic-common", ] -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "unicode-ident", ] @@ -15022,8 +14788,8 @@ version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "unicode-ident", ] @@ -15197,8 +14963,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ "cfg-if", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -15208,8 +14974,8 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", "test-case-core", ] @@ -15222,7 +14988,7 @@ dependencies = [ "crossbeam-channel", "getrandom 0.2.11", "hex", - "itertools 0.10.5", + "itertools 0.12.1", "module-generation", "move-binary-format", "move-bytecode-verifier", @@ -15301,8 +15067,8 @@ version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -15456,8 +15222,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -15885,8 +15651,8 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -15970,22 +15736,13 @@ dependencies = [ "serde_json", ] -[[package]] -name = "trie-root" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" -dependencies = [ - "hash-db 0.16.0", -] - [[package]] name = "triehash" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1631b201eb031b563d2e85ca18ec8092508e262a3196ce9bd10a67ec87b9f5c" dependencies = [ - "hash-db 0.15.2", + "hash-db", "rlp", ] @@ -16082,7 +15839,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc670d0e358428857cc3b4bf504c691e572fccaec9542ff09212d3f13d74b7a9" dependencies = [ - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -16253,12 +16010,6 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unicode-xid" version = "0.2.4" @@ -16385,7 +16136,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae2faf80ac463422992abf4de234731279c058aaf33171ca70277c98406b124" dependencies = [ - "quote 1.0.35", + "quote", "syn 1.0.109", ] @@ -16530,8 +16281,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", "wasm-bindgen-shared", ] @@ -16554,7 +16305,7 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ - "quote 1.0.35", + "quote", "wasm-bindgen-macro-support", ] @@ -16564,8 +16315,8 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -17064,8 +16815,8 @@ version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] @@ -17084,8 +16835,8 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.76", - "quote 1.0.35", + "proc-macro2", + "quote", "syn 2.0.48", ] diff --git a/Cargo.toml b/Cargo.toml index 337f271c1d120..efa9a911232b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -185,10 +185,11 @@ members = [ "testsuite/module-publish", "testsuite/smoke-test", "testsuite/testcases", + "third_party/move/evm/exec-utils", + "third_party/move/evm/extract-ethereum-abi", # third_party/move "third_party/move/extensions/async/move-async-vm", "third_party/move/extensions/move-table-extension", - "third_party/move/move-analyzer", "third_party/move/move-binary-format", "third_party/move/move-binary-format/serializer-tests", "third_party/move/move-borrow-graph", @@ -449,11 +450,13 @@ aptos-cargo-cli = { path = "devtools/aptos-cargo-cli" } # External crate dependencies. # Please do not add any test features here: they should be declared by the individual crate. aes-gcm = "0.10.3" +atty = "0.2.14" nalgebra = "0.32" float-cmp = "0.9.0" again = "0.1.2" anyhow = "1.0.71" anstyle = "1.0.1" +arbitrary = { version = "1.3.2", features = ["derive"] } arc-swap = "1.6.0" arr_macro = "0.2.1" ark-bls12-381 = "0.4.0" @@ -497,14 +500,16 @@ cfg_block = "0.1.1" cfg-if = "1.0.0" ciborium = "0.2" claims = "0.7" -clap = { version = "4.3.9", features = ["derive", "unstable-styles"] } +clap = { version = "4.3.9", features = ["derive", "env", "unstable-styles"] } clap-verbosity-flag = "2.1.1" clap_complete = "4.4.1" cloud-storage = { version = "0.11.1", features = [ "global-client", "rustls-tls", ], default-features = false } +codespan = "0.11.1" codespan-reporting = "0.11.1" +colored = "2.0.0" concurrent-queue = "2.2.0" console-subscriber = "0.1.8" const_format = "0.2.26" @@ -514,6 +519,7 @@ criterion = "0.3.5" criterion-cpu-time = "0.1.0" crossbeam = "0.8.1" crossbeam-channel = "0.5.4" +crossterm = "0.26.1" csv = "1.2.1" curve25519-dalek = "3" curve25519-dalek-ng = "4" @@ -528,9 +534,11 @@ diesel = "2.1" # https://github.com/weiznich/diesel_async/commit/e165e8c96a6c540ebde2d6d7c52df5c5620a4bf1 diesel-async = { git = "https://github.com/weiznich/diesel_async.git", rev = "d02798c67065d763154d7272dd0c09b39757d0f2", features = ["async-connection-wrapper", "postgres", "bb8", "tokio"] } diesel_migrations = { version = "2.1.0", features = ["postgres"] } +difference = "2.0.0" digest = "0.9.0" dir-diff = "0.3.2" dirs = "5.0.1" +dirs-next = "2.0.0" dunce = "1.0.4" ed25519-dalek = { version = "1.0.1", features = ["std", "serde"] } ed25519-dalek-bip32 = "0.2.0" @@ -538,16 +546,23 @@ either = "1.6.1" enum_dispatch = "0.3.12" env_logger = "0.10.0" erased-serde = "0.3.13" +ethabi = "18.0.0" +ethnum = "1.5.0" event-listener = "2.5.3" +evm = { version = "0.33.1", features = ["tracing"] } +evm-runtime = { version = "0.33.0", features = ["tracing"] } fail = "0.5.0" ff = "0.13" field_count = "0.1.1" +file_diff = "1.0.0" fixed = "1.25.1" flate2 = "1.0.24" +flexi_logger = "0.27.4" futures = "0.3.29" futures-channel = "0.3.29" futures-core = "0.3.29" futures-util = "0.3.29" +getrandom = "0.2.2" gcp-bigquery-client = "0.13.0" get_if_addrs = "0.5.3" git2 = "0.16.1" @@ -557,8 +572,10 @@ google-cloud-storage = "0.13.0" group = "0.13" guppy = "0.17.5" handlebars = "4.2.2" +hashbrown = "0.14.3" heck = "0.4.1" hex = { version = "0.4.3", features = ["serde"] } +hex-literal = "0.3.4" hkdf = "0.10.0" hostname = "0.3.1" http = "0.2.9" @@ -566,10 +583,12 @@ httpmock = "0.6.8" hyper = { version = "0.14.18", features = ["full"] } hyper-tls = "0.5.0" image = "0.24.5" +indexmap = "1.9.3" include_dir = { version = "0.7.2", features = ["glob"] } indicatif = "0.15.0" indoc = "1.0.6" inferno = "0.11.14" +internment = { version = "0.5.0", features = ["arc"] } ipnet = "2.5.0" itertools = "0.12" jemallocator = { version = "0.5.0", features = [ @@ -589,13 +608,16 @@ lru = "0.7.5" lz4 = "1.24.0" maplit = "1.0.2" merlin = "3" +memory-stats = "1.0.0" mime = "0.3.16" mini-moka = { version = "0.10.3", features = ["sync"] } mirai-annotations = "1.12.0" mockall = "0.11.4" more-asserts = "0.3.0" +named-lock = "0.2.0" native-tls = "0.2.10" ntest = "0.9.0" +num = "0.4.0" num-bigint = { version = "0.3.2", features = ["rand"] } num_cpus = "1.13.1" num-derive = "0.3.3" @@ -607,6 +629,8 @@ ordered-float = "3.9.1" ouroboros = "0.15.6" owo-colors = "3.5.0" p256 = { version = "0.13.2" } +prettydiff = "0.6.2" +primitive-types = { version = "0.10" } signature = "2.1.0" sec1 = "0.7.0" pairing = "0.23" @@ -618,12 +642,15 @@ passkey-client = { version = "0.2.0" } passkey-types = { version = "0.2.0" } pbjson = "0.5.1" percent-encoding = "2.1.0" +petgraph = "0.5.1" pin-project = "1.0.10" +plotters = { version = "0.3.5", default-features = false } poem = { version = "=1.3.59", features = ["anyhow", "rustls"] } poem-openapi = { version = "=2.0.11", features = ["swagger-ui", "url"] } poem-openapi-derive = "=2.0.11" poseidon-ark = { git = "https://github.com/arnaucube/poseidon-ark.git", rev = "6d2487aa1308d9d3860a2b724c485d73095c1c68" } pprof = { version = "0.11", features = ["flamegraph", "protobuf-codec"] } +pretty = "0.10.0" pretty_assertions = "1.2.1" procfs = "0.14.1" proc-macro2 = "1.0.38" @@ -647,6 +674,7 @@ redis = { version = "0.22.3", features = [ "connection-manager", ] } redis-test = { version = "0.1.1", features = ["aio"] } +ref-cast = "1.0.6" regex = "1.9.3" reqwest = { version = "0.11.11", features = [ "blocking", @@ -670,6 +698,7 @@ sha2 = "0.9.3" sha256 = "1.4.0" sha2_0_10_6 = { package = "sha2", version = "0.10.6" } sha3 = "0.9.1" +shell-words = "1.0.0" siphasher = "0.3.10" serde = { version = "1.0.193", features = ["derive", "rc"] } serde-big-array = "0.5.1" @@ -686,6 +715,8 @@ serde-reflection = { git = "https://github.com/aptos-labs/serde-reflection", rev serde_with = "3.4.0" serde_yaml = "0.8.24" shadow-rs = "0.16.2" +simplelog = "0.9.0" +smallbitvec = "2.5.1" smallvec = "1.8.0" static_assertions = "1.1.0" stats_alloc = "0.1.8" @@ -696,6 +727,7 @@ syn = { version = "1.0.92", features = ["derive", "extra-traits"] } sysinfo = "0.28.4" tar = "0.4.40" tempfile = "3.3.0" +tera = "1.16.0" termcolor = "1.1.2" test-case = "3.1.0" textwrap = "0.15.0" @@ -705,6 +737,7 @@ thread_local = "1.1.7" time = { version = "0.3.24", features = ["serde"] } tiny-bip39 = "0.8.2" tiny-keccak = { version = "2.0.2", features = ["keccak", "sha3"] } +toml_edit = "0.14.3" tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["json", "env-filter"] } trybuild = "1.0.80" @@ -726,17 +759,24 @@ tonic = { version = "0.11.0", features = [ "zstd", ] } tonic-reflection = "0.11.0" +triomphe = "0.1.9" +tui = "0.19.0" +typed-arena = "2.0.2" +uint = "0.9.4" ureq = { version = "1.5.4", features = [ "json", "native-tls", ], default_features = false } url = { version = "2.4.0", features = ["serde"] } uuid = { version = "1.0.0", features = ["v4", "serde"] } +variant_count = "1.1.0" walkdir = "2.3.3" warp = { version = "0.3.5", features = ["tls"] } warp-reverse-proxy = "1.0.0" which = "4.2.5" +whoami = "1.5.0" x25519-dalek = "1.2.0" +z3tracer = "0.8.0" # MOVE DEPENDENCIES move-abigen = { path = "third_party/move/move-prover/move-abigen" } diff --git a/api/goldens/aptos_api__tests__transactions_test__test_get_transactions_output_user_transaction_with_entry_function_payload.json b/api/goldens/aptos_api__tests__transactions_test__test_get_transactions_output_user_transaction_with_entry_function_payload.json index 40c597d4f5b87..5e0af2551d313 100644 --- a/api/goldens/aptos_api__tests__transactions_test__test_get_transactions_output_user_transaction_with_entry_function_payload.json +++ b/api/goldens/aptos_api__tests__transactions_test__test_get_transactions_output_user_transaction_with_entry_function_payload.json @@ -338,7 +338,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" diff --git a/api/goldens/aptos_api__tests__transactions_test__test_get_transactions_returns_last_page_when_start_version_is_not_specified.json b/api/goldens/aptos_api__tests__transactions_test__test_get_transactions_returns_last_page_when_start_version_is_not_specified.json index 428b21def2d19..0e912e6286856 100644 --- a/api/goldens/aptos_api__tests__transactions_test__test_get_transactions_returns_last_page_when_start_version_is_not_specified.json +++ b/api/goldens/aptos_api__tests__transactions_test__test_get_transactions_returns_last_page_when_start_version_is_not_specified.json @@ -343,7 +343,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" @@ -697,7 +697,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" @@ -1051,7 +1051,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" @@ -1405,7 +1405,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" @@ -1759,7 +1759,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" @@ -2113,7 +2113,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" @@ -2467,7 +2467,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" @@ -2821,7 +2821,7 @@ "type": "0x1::transaction_fee::FeeStatement", "data": { "execution_gas_units": "4", - "io_gas_units": "1", + "io_gas_units": "2", "storage_fee_octas": "0", "storage_fee_refund_octas": "0", "total_charge_gas_units": "5" diff --git a/api/src/accounts.rs b/api/src/accounts.rs index 4cfa4bc398de8..0b97c701f472f 100644 --- a/api/src/accounts.rs +++ b/api/src/accounts.rs @@ -19,7 +19,6 @@ use aptos_api_types::{ MoveModuleId, MoveResource, MoveStructTag, StateKeyWrapper, U64, }; use aptos_types::{ - access_path::AccessPath, account_config::{AccountResource, ObjectGroupResource}, event::{EventHandle, EventKey}, state_store::state_key::StateKey, @@ -258,16 +257,14 @@ impl Account { } pub fn get_account_resource(&self) -> Result, BasicErrorWith404> { - let state_key = StateKey::access_path( - AccessPath::resource_access_path(self.address.into(), AccountResource::struct_tag()) - .map_err(|e| { - BasicErrorWith404::internal_with_code( - e, - AptosErrorCode::InternalError, - &self.latest_ledger_info, - ) - })?, - ); + let state_key = + StateKey::resource_typed::(self.address.inner()).map_err(|e| { + BasicErrorWith404::internal_with_code( + e, + AptosErrorCode::InternalError, + &self.latest_ledger_info, + ) + })?; let state_value = self.context.get_state_value_poem( &state_key, @@ -287,10 +284,8 @@ impl Account { return Ok(()); } - let state_key = StateKey::access_path(AccessPath::resource_group_access_path( - self.address.into(), - ObjectGroupResource::struct_tag(), - )); + let state_key = + StateKey::resource_group(&self.address.into(), &ObjectGroupResource::struct_tag()); let state_value = self.context.get_state_value_poem( &state_key, diff --git a/api/src/context.rs b/api/src/context.rs index 2c7215e9cae2f..9ad51730de378 100644 --- a/api/src/context.rs +++ b/api/src/context.rs @@ -37,8 +37,7 @@ use aptos_types::{ ledger_info::LedgerInfoWithSignatures, on_chain_config::{GasSchedule, GasScheduleV2, OnChainConfig, OnChainExecutionConfig}, state_store::{ - state_key::{StateKey, StateKeyInner}, - state_key_prefix::StateKeyPrefix, + state_key::{inner::StateKeyInner, prefix::StateKeyPrefix, StateKey}, state_value::StateValue, TStateView, }, @@ -306,8 +305,7 @@ impl Context { address: AccountAddress, version: Version, ) -> Result> { - let access_path = AccessPath::resource_access_path(address, T::struct_tag())?; - let bytes_opt = self.get_state_value(&StateKey::access_path(access_path), version)?; + let bytes_opt = self.get_state_value(&StateKey::resource_typed::(&address)?, version)?; bytes_opt .map(|bytes| bcs::from_bytes(&bytes)) .transpose() @@ -460,10 +458,7 @@ impl Context { .collect(); let next_key = if let Some((struct_tag, _v)) = resource_iter.next().transpose()? { - Some(StateKey::access_path(AccessPath::new( - address, - AccessPath::resource_path_vec(struct_tag)?, - ))) + Some(StateKey::resource(&address, &struct_tag)?) } else { None }; @@ -504,12 +499,10 @@ impl Context { .by_ref() .take(limit as usize) .collect::>()?; - let next_key = module_iter.next().transpose()?.map(|(module_id, _v)| { - StateKey::access_path(AccessPath::new( - address, - AccessPath::code_path_vec(module_id), - )) - }); + let next_key = module_iter + .next() + .transpose()? + .map(|(module_id, _v)| StateKey::module_id(&module_id)); Ok((kvs, next_key)) } diff --git a/api/src/state.rs b/api/src/state.rs index 34c74b44d4a58..3a2ca487519b2 100644 --- a/api/src/state.rs +++ b/api/src/state.rs @@ -18,15 +18,9 @@ use aptos_api_types::{ MoveModuleBytecode, MoveResource, MoveStructTag, MoveValue, RawStateValueRequest, RawTableItemRequest, TableItemRequest, VerifyInput, VerifyInputWithRecursion, U64, }; -use aptos_types::{ - access_path::AccessPath, - state_store::{state_key::StateKey, table::TableHandle, TStateView}, -}; +use aptos_types::state_store::{state_key::StateKey, table::TableHandle, TStateView}; use aptos_vm::data_cache::AsMoveResolver; -use move_core_types::{ - language_storage::{ModuleId, StructTag}, - resolver::MoveResolver, -}; +use move_core_types::{language_storage::StructTag, resolver::MoveResolver}; use poem_openapi::{ param::{Path, Query}, payload::Json, @@ -350,9 +344,7 @@ impl StateApi { name: IdentifierWrapper, ledger_version: Option, ) -> BasicResultWith404 { - let module_id = ModuleId::new(address.into(), name.into()); - let access_path = AccessPath::code_access_path(module_id.clone()); - let state_key = StateKey::access_path(access_path); + let state_key = StateKey::module(address.inner(), &name); let (ledger_info, ledger_version, state_view) = self .context .state_view(ledger_version.map(|inner| inner.0))?; @@ -366,9 +358,7 @@ impl StateApi { &ledger_info, ) })? - .ok_or_else(|| { - module_not_found(address, module_id.name(), ledger_version, &ledger_info) - })?; + .ok_or_else(|| module_not_found(address, &name, ledger_version, &ledger_info))?; match accept_type { AcceptType::Json => { @@ -448,7 +438,7 @@ impl StateApi { })?; // Retrieve value from the state key - let state_key = StateKey::table_item(TableHandle(table_handle.into()), raw_key); + let state_key = StateKey::table_item(&TableHandle(table_handle.into()), &raw_key); let bytes = state_view .get_state_value_bytes(&state_key) .context(format!( @@ -502,10 +492,8 @@ impl StateApi { .context .state_view(ledger_version.map(|inner| inner.0))?; - let state_key = StateKey::table_item( - TableHandle(table_handle.into()), - table_item_request.key.0.clone(), - ); + let state_key = + StateKey::table_item(&TableHandle(table_handle.into()), &table_item_request.key.0); let bytes = state_view .get_state_value_bytes(&state_key) .context(format!( diff --git a/api/src/tests/events_test.rs b/api/src/tests/events_test.rs index 69bba6196d48a..acf517b61a04c 100644 --- a/api/src/tests/events_test.rs +++ b/api/src/tests/events_test.rs @@ -172,12 +172,21 @@ async fn test_module_events() { .get(format!("/transactions/by_hash/{}", txn["hash"].as_str().unwrap()).as_str()) .await; - let events = resp["events"].as_array().unwrap(); + let events = resp["events"] + .as_array() + .unwrap() + .iter() + .filter(|e| { + e.get("guid") + .unwrap() + .get("account_address") + .unwrap() + .as_str() + .unwrap() + == "0x0" + }) + .collect::>(); assert_eq!(events.len(), 8); - // All events are module events - assert!(events.iter().all(|c| c.get("guid").map_or(false, |d| d - .get("account_address") - .map_or(false, |t| t.as_str().unwrap() == "0x0")))); } // until we have generics in the genesis @@ -193,7 +202,7 @@ async fn test_get_events_by_struct_type_has_generic_type_parameter() { "/accounts/0x1/events/{}/coin", utf8_percent_encode( "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>", - NON_ALPHANUMERIC + NON_ALPHANUMERIC, ) ); let resp = context.expect_status_code(404).get(path.as_str()).await; diff --git a/api/test-context/src/test_context.rs b/api/test-context/src/test_context.rs index 8b755a3e0baf5..f161f72c09cf9 100644 --- a/api/test-context/src/test_context.rs +++ b/api/test-context/src/test_context.rs @@ -26,8 +26,8 @@ use aptos_sdk::{ bcs, transaction_builder::TransactionFactory, types::{ - account_config::aptos_test_root_address, transaction::SignedTransaction, AccountKey, - LocalAccount, + account_config::aptos_test_root_address, get_apt_primary_store_address, + transaction::SignedTransaction, AccountKey, LocalAccount, }, }; use aptos_storage_interface::{state_view::DbStateView, DbReaderWriter}; @@ -657,19 +657,42 @@ impl TestContext { } pub async fn get_apt_balance(&self, account: AccountAddress) -> u64 { - let coin_balance = self - .api_get_account_resource( + let coin_balance_option = self + .try_api_get_account_resource( account, "0x1", "coin", "CoinStore<0x1::aptos_coin::AptosCoin>", ) .await; - coin_balance["data"]["coin"]["value"] - .as_str() - .unwrap() - .parse::() - .unwrap() + let coin = coin_balance_option.map(|x| { + x["data"]["coin"]["value"] + .as_str() + .unwrap() + .parse::() + .unwrap() + }); + if let Some(v) = coin { + v + } else { + let fungible_store_option = self + .try_api_get_account_resource( + get_apt_primary_store_address(account), + "0x1", + "fungible_asset", + "FungibleStore", + ) + .await; + fungible_store_option + .map(|x| { + x["data"]["balance"] + .as_str() + .unwrap() + .parse::() + .unwrap() + }) + .unwrap_or(0) + } } pub async fn gen_events_by_handle( @@ -717,15 +740,27 @@ impl TestContext { } // TODO: Add support for generic_type_params if necessary. - pub async fn api_get_account_resource( + pub async fn try_api_get_account_resource( &self, account: AccountAddress, resource_account_address: &str, module: &str, name: &str, - ) -> serde_json::Value { + ) -> Option { let resource = format!("{}::{}::{}", resource_account_address, module, name); - self.gen_resource(&account, &resource).await.unwrap() + self.gen_resource(&account, &resource).await + } + + pub async fn api_get_account_resource( + &self, + account: AccountAddress, + resource_account_address: &str, + module: &str, + name: &str, + ) -> Value { + self.try_api_get_account_resource(account, resource_account_address, module, name) + .await + .unwrap() } // TODO: remove the helper function since we don't publish module directly anymore diff --git a/api/types/src/convert.rs b/api/types/src/convert.rs index 85ef22f5a85a2..7e32448c6915f 100644 --- a/api/types/src/convert.rs +++ b/api/types/src/convert.rs @@ -24,7 +24,7 @@ use aptos_types::{ chain_id::ChainId, contract_event::{ContractEvent, EventWithVersion}, state_store::{ - state_key::{StateKey, StateKeyInner}, + state_key::{inner::StateKeyInner, StateKey}, table::{TableHandle, TableInfo}, }, transaction::{ @@ -317,13 +317,13 @@ impl<'a, R: ModuleResolver + ?Sized> MoveConverter<'a, R> { op: WriteOp, ) -> Result> { let hash = state_key.hash().to_hex_literal(); - let state_key = state_key.into_inner(); + let state_key = state_key.inner(); match state_key { StateKeyInner::AccessPath(access_path) => { self.try_access_path_into_write_set_changes(hash, access_path, op) }, StateKeyInner::TableItem { handle, key } => { - vec![self.try_table_item_into_write_set_change(hash, handle, key, op)] + vec![self.try_table_item_into_write_set_change(hash, *handle, key.to_owned(), op)] .into_iter() .collect() }, @@ -337,7 +337,7 @@ impl<'a, R: ModuleResolver + ?Sized> MoveConverter<'a, R> { pub fn try_access_path_into_write_set_changes( &self, state_key_hash: String, - access_path: AccessPath, + access_path: &AccessPath, op: WriteOp, ) -> Result> { let ret = match op.bytes() { diff --git a/aptos-move/aptos-aggregator/src/aggregator_v1_extension.rs b/aptos-move/aptos-aggregator/src/aggregator_v1_extension.rs index c8feb5bd25883..4c4b3573ff2d5 100644 --- a/aptos-move/aptos-aggregator/src/aggregator_v1_extension.rs +++ b/aptos-move/aptos-aggregator/src/aggregator_v1_extension.rs @@ -26,7 +26,7 @@ pub struct AggregatorID(pub StateKey); impl AggregatorID { pub fn new(handle: TableHandle, key: PeerId) -> Self { - let state_key = StateKey::table_item(handle, key.to_vec()); + let state_key = StateKey::table_item(&handle, key.as_ref()); AggregatorID(state_key) } diff --git a/aptos-move/aptos-aggregator/src/delta_change_set.rs b/aptos-move/aptos-aggregator/src/delta_change_set.rs index c44628c4f37eb..06422fb82ef79 100644 --- a/aptos-move/aptos-aggregator/src/delta_change_set.rs +++ b/aptos-move/aptos-aggregator/src/delta_change_set.rs @@ -476,7 +476,7 @@ mod test { assert_eq!(b.update, Negative(1)); } - static KEY: Lazy = Lazy::new(|| StateKey::raw(String::from("test-key").into_bytes())); + static KEY: Lazy = Lazy::new(|| StateKey::raw(b"test-key")); #[test] fn test_failed_write_op_conversion_because_of_empty_storage() { diff --git a/aptos-move/aptos-aggregator/src/tests/types.rs b/aptos-move/aptos-aggregator/src/tests/types.rs index f16c6bdc4cb3b..c923f4871d4f2 100644 --- a/aptos-move/aptos-aggregator/src/tests/types.rs +++ b/aptos-move/aptos-aggregator/src/tests/types.rs @@ -31,7 +31,7 @@ pub fn aggregator_v1_id_for_test(key: u128) -> AggregatorID { } pub fn aggregator_v1_state_key_for_test(key: u128) -> StateKey { - StateKey::raw(key.to_le_bytes().to_vec()) + StateKey::raw(&key.to_le_bytes()) } pub const FAKE_AGGREGATOR_VIEW_GEN_ID_START: u32 = 87654321; diff --git a/aptos-move/aptos-debugger/Cargo.toml b/aptos-move/aptos-debugger/Cargo.toml index 96a9dcef7b06b..073d84a92ce11 100644 --- a/aptos-move/aptos-debugger/Cargo.toml +++ b/aptos-move/aptos-debugger/Cargo.toml @@ -18,7 +18,6 @@ aptos-consensus = { workspace = true } aptos-crypto = { workspace = true } aptos-gas-meter = { workspace = true } aptos-gas-profiling = { workspace = true } -aptos-gas-schedule = { workspace = true } aptos-logger = { workspace = true } aptos-memory-usage-tracker = { workspace = true } aptos-rest-client = { workspace = true } @@ -29,7 +28,6 @@ aptos-vm-logging = { workspace = true } aptos-vm-types = { workspace = true } bcs = { workspace = true } clap = { workspace = true } -move-binary-format = { workspace = true } regex = { workspace = true } reqwest = { workspace = true } tokio = { workspace = true } diff --git a/aptos-move/aptos-debugger/src/aptos_debugger.rs b/aptos-move/aptos-debugger/src/aptos_debugger.rs index c7a923ae2fb6d..d7f2bda25c145 100644 --- a/aptos-move/aptos-debugger/src/aptos_debugger.rs +++ b/aptos-move/aptos-debugger/src/aptos_debugger.rs @@ -4,13 +4,10 @@ use anyhow::{bail, format_err, Result}; use aptos_gas_meter::{StandardGasAlgebra, StandardGasMeter}; use aptos_gas_profiling::{GasProfiler, TransactionGasLog}; -use aptos_gas_schedule::{MiscGasParameters, NativeGasParameters, LATEST_GAS_FEATURE_VERSION}; use aptos_memory_usage_tracker::MemoryTrackedGasMeter; use aptos_rest_client::Client; use aptos_types::{ account_address::AccountAddress, - chain_id::ChainId, - on_chain_config::{Features, OnChainConfig, TimedFeaturesBuilder}, state_store::TStateView, transaction::{ signature_verified_transaction::SignatureVerifiedTransaction, SignedTransaction, @@ -21,16 +18,9 @@ use aptos_types::{ use aptos_validator_interface::{ AptosValidatorInterface, DBDebuggerInterface, DebuggerStateView, RestDebuggerInterface, }; -use aptos_vm::{ - data_cache::AsMoveResolver, - move_vm_ext::{MoveVmExt, SessionExt, SessionId}, - AptosVM, VMExecutor, -}; +use aptos_vm::{data_cache::AsMoveResolver, AptosVM, VMExecutor}; use aptos_vm_logging::log_schema::AdapterLogSchema; -use aptos_vm_types::{ - change_set::VMChangeSet, output::VMOutput, storage::change_set_configs::ChangeSetConfigs, -}; -use move_binary_format::errors::VMResult; +use aptos_vm_types::output::VMOutput; use std::{path::Path, sync::Arc}; pub struct AptosDebugger { @@ -262,34 +252,6 @@ impl AptosDebugger { pub fn state_view_at_version(&self, version: Version) -> DebuggerStateView { DebuggerStateView::new(self.debugger.clone(), version) } - - pub fn run_session_at_version(&self, version: Version, f: F) -> Result - where - F: FnOnce(&mut SessionExt) -> VMResult<()>, - { - let state_view = DebuggerStateView::new(self.debugger.clone(), version); - let state_view_storage = state_view.as_move_resolver(); - let features = Features::fetch_config(&state_view_storage).unwrap_or_default(); - let move_vm = MoveVmExt::new( - NativeGasParameters::zeros(), - MiscGasParameters::zeros(), - LATEST_GAS_FEATURE_VERSION, - ChainId::test().id(), - features, - TimedFeaturesBuilder::enable_all().build(), - &state_view_storage, - /*aggregator_v2_type_tagging*/ false, - ) - .unwrap(); - let mut session = move_vm.new_session(&state_view_storage, SessionId::Void); - f(&mut session).map_err(|err| format_err!("Unexpected VM Error: {:?}", err))?; - let change_set = session - .finish(&ChangeSetConfigs::unlimited_at_gas_feature_version( - LATEST_GAS_FEATURE_VERSION, - )) - .map_err(|err| format_err!("Unexpected VM Error: {:?}", err))?; - Ok(change_set) - } } fn is_reconfiguration(vm_output: &TransactionOutput) -> bool { diff --git a/aptos-move/aptos-gas-meter/src/meter.rs b/aptos-move/aptos-gas-meter/src/meter.rs index 2db1d96f87c50..725bfe8295ed9 100644 --- a/aptos-move/aptos-gas-meter/src/meter.rs +++ b/aptos-move/aptos-gas-meter/src/meter.rs @@ -554,4 +554,10 @@ where .charge_execution(MIN_TRANSACTION_GAS_UNITS + INTRINSIC_GAS_PER_BYTE * excess) .map_err(|e| e.finish(Location::Undefined)) } + + fn charge_keyless(&mut self) -> VMResult<()> { + self.algebra + .charge_execution(KEYLESS_BASE_COST) + .map_err(|e| e.finish(Location::Undefined)) + } } diff --git a/aptos-move/aptos-gas-meter/src/traits.rs b/aptos-move/aptos-gas-meter/src/traits.rs index 66b3b608f755b..13efaa69f2f43 100644 --- a/aptos-move/aptos-gas-meter/src/traits.rs +++ b/aptos-move/aptos-gas-meter/src/traits.rs @@ -110,9 +110,14 @@ pub trait AptosGasMeter: MoveGasMeter { /// Charges an intrinsic cost for executing the transaction. /// /// The cost stays constant for transactions below a certain size, but will grow proportionally - /// for bigger ones. + /// for bigger ones. THe multiplier can be used to increase the unit cost for exceptional + /// transactions like keyless. fn charge_intrinsic_gas_for_transaction(&mut self, txn_size: NumBytes) -> VMResult<()>; + /// Charges an additional cost for keyless transactions to compensate for the + /// expensive computation required. + fn charge_keyless(&mut self) -> VMResult<()>; + /// Charges IO gas for the transaction itself. fn charge_io_gas_for_transaction(&mut self, txn_size: NumBytes) -> VMResult<()>; diff --git a/aptos-move/aptos-gas-profiling/src/aggregate.rs b/aptos-move/aptos-gas-profiling/src/aggregate.rs index 3c3edcb9c1290..ee1aab3891f8b 100644 --- a/aptos-move/aptos-gas-profiling/src/aggregate.rs +++ b/aptos-move/aptos-gas-profiling/src/aggregate.rs @@ -6,11 +6,7 @@ use crate::{ render::{Render, TableKey}, }; use aptos_gas_algebra::{GasQuantity, GasScalingFactor, InternalGas}; -use aptos_types::state_store::state_key::StateKeyInner; -use std::{ - collections::{btree_map, BTreeMap}, - ops::Deref, -}; +use std::collections::{btree_map, BTreeMap}; /// Represents an aggregation of execution gas events, including the count and total gas costs for each type of event. /// @@ -116,9 +112,9 @@ impl ExecutionAndIOCosts { } for write in &self.write_set_transient { - use StateKeyInner::*; + use aptos_types::state_store::state_key::inner::StateKeyInner::*; - let key = match write.key.deref() { + let key = match write.key.inner() { AccessPath(ap) => format!("{}", Render(&ap.get_path())), TableItem { handle, key } => { format!("table_item<{},{}>", Render(handle), TableKey { bytes: key },) diff --git a/aptos-move/aptos-gas-profiling/src/erased.rs b/aptos-move/aptos-gas-profiling/src/erased.rs index b59547af47bea..febdee5874026 100644 --- a/aptos-move/aptos-gas-profiling/src/erased.rs +++ b/aptos-move/aptos-gas-profiling/src/erased.rs @@ -217,6 +217,8 @@ impl ExecutionAndIOCosts { nodes.push(Node::new("intrinsic", self.intrinsic_cost)); + nodes.push(Node::new("keyless", self.keyless_cost)); + if !self.dependencies.is_empty() { let deps = Node::new_with_children( "dependencies", diff --git a/aptos-move/aptos-gas-profiling/src/flamegraph.rs b/aptos-move/aptos-gas-profiling/src/flamegraph.rs index c7e3fb6c7e99c..1c08054d73a2c 100644 --- a/aptos-move/aptos-gas-profiling/src/flamegraph.rs +++ b/aptos-move/aptos-gas-profiling/src/flamegraph.rs @@ -101,6 +101,8 @@ impl ExecutionAndIOCosts { lines.push("intrinsic", self.intrinsic_cost); + lines.push("keyless", self.keyless_cost); + let mut path = vec![]; struct Rec<'a> { diff --git a/aptos-move/aptos-gas-profiling/src/log.rs b/aptos-move/aptos-gas-profiling/src/log.rs index f3f4c585d64b7..ae7e36f37e82b 100644 --- a/aptos-move/aptos-gas-profiling/src/log.rs +++ b/aptos-move/aptos-gas-profiling/src/log.rs @@ -117,6 +117,7 @@ pub struct ExecutionAndIOCosts { pub total: InternalGas, pub intrinsic_cost: InternalGas, + pub keyless_cost: InternalGas, pub dependencies: Vec, pub call_graph: CallFrame, pub transaction_transient: Option, @@ -238,6 +239,7 @@ impl ExecutionAndIOCosts { let mut total = InternalGas::zero(); total += self.intrinsic_cost; + total += self.keyless_cost; for dep in &self.dependencies { total += dep.cost; diff --git a/aptos-move/aptos-gas-profiling/src/profiler.rs b/aptos-move/aptos-gas-profiling/src/profiler.rs index 1136f831d47bd..89ba8fa72e0b5 100644 --- a/aptos-move/aptos-gas-profiling/src/profiler.rs +++ b/aptos-move/aptos-gas-profiling/src/profiler.rs @@ -34,6 +34,7 @@ pub struct GasProfiler { base: G, intrinsic_cost: Option, + keyless_cost: Option, dependencies: Vec, frames: Vec, transaction_transient: Option, @@ -90,6 +91,7 @@ impl GasProfiler { base, intrinsic_cost: None, + keyless_cost: None, dependencies: vec![], frames: vec![CallFrame::new_script()], transaction_transient: None, @@ -109,6 +111,7 @@ impl GasProfiler { base, intrinsic_cost: None, + keyless_cost: None, dependencies: vec![], frames: vec![CallFrame::new_function(module_id, func_name, ty_args)], transaction_transient: None, @@ -650,6 +653,14 @@ where res } + + fn charge_keyless(&mut self) -> VMResult<()> { + let (_cost, res) = self.delegate_charge(|base| base.charge_keyless()); + + // TODO: add keyless + + res + } } impl GasProfiler @@ -667,6 +678,7 @@ where gas_scaling_factor: self.base.gas_unit_scaling_factor(), total: self.algebra().execution_gas_used() + self.algebra().io_gas_used(), intrinsic_cost: self.intrinsic_cost.unwrap_or_else(|| 0.into()), + keyless_cost: self.keyless_cost.unwrap_or_else(|| 0.into()), dependencies: self.dependencies, call_graph: self.frames.pop().expect("frame must exist"), transaction_transient: self.transaction_transient, diff --git a/aptos-move/aptos-gas-profiling/src/render.rs b/aptos-move/aptos-gas-profiling/src/render.rs index e712299cc752c..c0bb7729e7e4b 100644 --- a/aptos-move/aptos-gas-profiling/src/render.rs +++ b/aptos-move/aptos-gas-profiling/src/render.rs @@ -4,20 +4,14 @@ use crate::log::{FrameName, WriteOpType}; use aptos_types::{ access_path::Path, - state_store::{ - state_key::{StateKey, StateKeyInner}, - table::TableHandle, - }, + state_store::{state_key::StateKey, table::TableHandle}, }; use move_core_types::{ account_address::AccountAddress, identifier::IdentStr, language_storage::{ModuleId, TypeTag}, }; -use std::{ - fmt::{self, Display}, - ops::Deref, -}; +use std::fmt::{self, Display}; /// Wrapper to help render the underlying data in human readable formats that are /// desirable for textual outputs and flamegraphs. @@ -106,9 +100,9 @@ impl<'a> Display for TableKey<'a> { impl<'a> Display for Render<'a, StateKey> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use StateKeyInner::*; + use aptos_types::state_store::state_key::inner::StateKeyInner::*; - match self.0.deref() { + match self.0.inner() { AccessPath(ap) => { write!(f, "{}::{}", Render(&ap.address), Render(&ap.get_path())) }, diff --git a/aptos-move/aptos-gas-profiling/src/report.rs b/aptos-move/aptos-gas-profiling/src/report.rs index 60ccf1934c97b..fc2aa9c25c3b1 100644 --- a/aptos-move/aptos-gas-profiling/src/report.rs +++ b/aptos-move/aptos-gas-profiling/src/report.rs @@ -109,6 +109,20 @@ impl TransactionGasLog { data.insert("intrinsic-percentage".to_string(), json!(percentage)); } + // Keyless cost + if !self.exec_io.keyless_cost.is_zero() { + let cost_scaled = format!( + "{:.8}", + (u64::from(self.exec_io.keyless_cost) as f64 / scaling_factor) + ); + let percentage = format!( + "{:.2}%", + u64::from(self.exec_io.keyless_cost) as f64 / total_exec_io * 100.0 + ); + data.insert("keyless".to_string(), json!(cost_scaled)); + data.insert("keyless-percentage".to_string(), json!(percentage)); + } + let mut deps = self.exec_io.dependencies.clone(); deps.sort_by(|lhs, rhs| rhs.cost.cmp(&lhs.cost)); data.insert( diff --git a/aptos-move/aptos-gas-profiling/templates/index.html b/aptos-move/aptos-gas-profiling/templates/index.html index 7b98da7ec0831..683bde34d065b 100644 --- a/aptos-move/aptos-gas-profiling/templates/index.html +++ b/aptos-move/aptos-gas-profiling/templates/index.html @@ -82,6 +82,12 @@

Intrinsic Cost

{{#if intrinsic-percentage}} , {{intrinsic-percentage}} of the total cost for execution & IO. {{/if}} + + {{#if keyless}} +

Keyless Cost

+ {{keyless}} gas units, {{keyless-percentage}} of the total cost for execution & IO. + {{/if}} +

Dependencies

{{#if deps}} @@ -147,60 +153,60 @@

State Reads

{{/if}}

Ledger Writes

Transaction Itself
-
- - - - - {{#with transaction_write}} - - - - - {{/with}} -
Cost in Gas UnitsPercentage
{{cost}}{{percentage}}
+ + + + + + {{#with transaction_write}} + + + + + {{/with}} +
Cost in Gas UnitsPercentage
{{cost}}{{percentage}}
Events
- {{#if event_writes}} - - - - - - - - {{#each event_writes}} - - - - - - - {{/each}} -
Event TypeNumber of HitsCost in Gas UnitsPercentage
{{name}}{{hits}}{{cost}}{{percentage}}
- {{else}} - (No writes to show.) - {{/if}} + {{#if event_writes}} + + + + + + + + {{#each event_writes}} + + + + + + + {{/each}} +
Event TypeNumber of HitsCost in Gas UnitsPercentage
{{name}}{{hits}}{{cost}}{{percentage}}
+ {{else}} + (No writes to show.) + {{/if}}
State Write Ops
- {{#if writes}} - - - - - - - - {{#each writes}} - - - - - - - {{/each}} -
Resource NameNumber of HitsCost in Gas UnitsPercentage
{{name}}{{hits}}{{cost}}{{percentage}}
- {{else}} - (No writes to show.) - {{/if}} + {{#if writes}} + + + + + + + + {{#each writes}} + + + + + + + {{/each}} +
Resource NameNumber of HitsCost in Gas UnitsPercentage
{{name}}{{hits}}{{cost}}{{percentage}}
+ {{else}} + (No writes to show.) + {{/if}}

Storage

The storage fees cover the extended-term storage of states and events and are assessed at a fixed price in APT. diff --git a/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs b/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs index 9a91aaf953329..f5fe106bf2b75 100644 --- a/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs +++ b/aptos-move/aptos-gas-schedule/src/gas_schedule/aptos_framework.rs @@ -3,7 +3,7 @@ //! This module defines the gas parameters for Aptos Framework & Stdlib. -use crate::gas_schedule::NativeGasParameters; +use crate::{gas_schedule::NativeGasParameters, ver::gas_feature_versions::RELEASE_V1_12}; use aptos_gas_algebra::{ InternalGas, InternalGasPerAbstractValueUnit, InternalGasPerArg, InternalGasPerByte, }; @@ -241,6 +241,13 @@ crate::gas_schedule::macros::define_gas_parameters!( [type_info_type_name_per_byte_in_str: InternalGasPerByte, "type_info.type_name.per_abstract_memory_unit", 18], [type_info_chain_id_base: InternalGas, { 4.. => "type_info.chain_id.base" }, 551], + // TODO(Gas): Fix my cost + [function_info_check_is_identifier_base: InternalGas, { RELEASE_V1_12.. => "function_info.is_identifier.base" }, 551], + [function_info_check_is_identifier_per_byte: InternalGasPerByte, { RELEASE_V1_12.. => "function_info.is_identifier.per_byte" }, 3], + [function_info_check_dispatch_type_compatibility_impl_base: InternalGas, { RELEASE_V1_12.. => "function_info.check_dispatch_type_compatibility_impl.base" }, 1002], + [function_info_load_function_base: InternalGas, { RELEASE_V1_12.. => "function_info.load_function.base" }, 551], + [dispatchable_fungible_asset_dispatch_base: InternalGas, { RELEASE_V1_12.. => "dispatchable_fungible_asset.dispatch.base" }, 551], + // Reusing SHA2-512's cost from Ristretto [hash_sha2_512_base: InternalGas, { 4.. => "hash.sha2_512.base" }, 11910], // 3_240 * 20 [hash_sha2_512_per_byte: InternalGasPerByte, { 4.. => "hash.sha2_512.per_byte" }, 220], // 60 * 20 @@ -260,6 +267,17 @@ crate::gas_schedule::macros::define_gas_parameters!( [transaction_context_get_script_hash_base: InternalGas, "transaction_context.get_script_hash.base", 735], // Based on SHA3-256's cost [transaction_context_generate_unique_address_base: InternalGas, { 10.. => "transaction_context.generate_unique_address.base" }, 14704], + [transaction_context_sender_base: InternalGas, {RELEASE_V1_12.. => "transaction_context.sender.base"}, 735], + [transaction_context_secondary_signers_base: InternalGas, {RELEASE_V1_12.. => "transaction_context.secondary_signers.base"}, 735], + [transaction_context_secondary_signers_per_signer: InternalGasPerArg, {RELEASE_V1_12.. => "transaction_context.secondary_signers.per_signer"}, 576], // 18 * 32 + [transaction_context_fee_payer_base: InternalGas, {RELEASE_V1_12.. => "transaction_context.fee_payer.base"}, 735], + [transaction_context_max_gas_amount_base: InternalGas, {RELEASE_V1_12.. => "transaction_context.max_gas_amount.base"}, 735], + [transaction_context_gas_unit_price_base: InternalGas, {RELEASE_V1_12.. => "transaction_context.gas_unit_price.base"}, 735], + [transaction_context_chain_id_base: InternalGas, {RELEASE_V1_12.. => "transaction_context.chain_id.base"}, 735], + [transaction_context_entry_function_payload_base: InternalGas, {RELEASE_V1_12.. => "transaction_context.entry_function_payload.base"}, 735], + [transaction_context_entry_function_payload_per_byte_in_str: InternalGasPerByte, {RELEASE_V1_12.. => "transaction_context.entry_function_payload.per_abstract_memory_unit"}, 18], + [transaction_context_multisig_payload_base: InternalGas, {RELEASE_V1_12.. => "transaction_context.multisig_payload.base"}, 735], + [transaction_context_multisig_payload_per_byte_in_str: InternalGasPerByte, {RELEASE_V1_12.. => "transaction_context.multisig_payload.per_abstract_memory_unit"}, 18], [code_request_publish_base: InternalGas, "code.request_publish.base", 1838], [code_request_publish_per_byte: InternalGasPerByte, "code.request_publish.per_byte", 7], @@ -290,6 +308,9 @@ crate::gas_schedule::macros::define_gas_parameters!( [aggregator_v2_string_concat_per_byte: InternalGasPerByte, { 12.. =>"aggregator_v2.string_concat.per_byte" }, 3], [object_exists_at_base: InternalGas, { 7.. => "object.exists_at.base" }, 919], + // Based on SHA3-256's cost + [object_user_derived_address_base: InternalGas, { RELEASE_V1_12.. => "object.user_derived_address.base" }, 14704], + // These are dummy value, they copied from storage gas in aptos-core/aptos-vm/src/aptos_vm_impl.rs [object_exists_at_per_byte_loaded: InternalGasPerByte, { 7.. => "object.exists_at.per_byte_loaded" }, 183], [object_exists_at_per_item_loaded: InternalGas, { 7.. => "object.exists_at.per_item_loaded" }, 1470], diff --git a/aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs b/aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs index fe5d9c6b44594..b26871ec4e1eb 100644 --- a/aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs +++ b/aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs @@ -4,7 +4,10 @@ //! This module defines all the gas parameters for transactions, along with their initial values //! in the genesis and a mapping between the Rust representation and the on-chain gas schedule. -use crate::gas_schedule::VMGasParameters; +use crate::{ + gas_schedule::VMGasParameters, + ver::gas_feature_versions::{RELEASE_V1_11, RELEASE_V1_12}, +}; use aptos_gas_algebra::{ AbstractValueSize, Fee, FeePerByte, FeePerGasUnit, FeePerSlot, Gas, GasExpression, GasScalingFactor, GasUnit, NumModules, NumSlots, @@ -22,6 +25,7 @@ crate::gas_schedule::macros::define_gas_parameters!( [ // The flat minimum amount of gas required for any transaction. // Charged at the start of execution. + // It is variable to charge more for more expensive authenticators, e.g., keyless [ min_transaction_gas_units: InternalGas, "min_transaction_gas_units", @@ -119,13 +123,13 @@ crate::gas_schedule::macros::define_gas_parameters!( ], [ storage_io_per_event_byte_write: InternalGasPerByte, - { 16.. => "storage_io_per_event_byte_write" }, - 0, + { RELEASE_V1_11.. => "storage_io_per_event_byte_write" }, + 89, ], [ storage_io_per_transaction_byte_write: InternalGasPerByte, - { 16.. => "storage_io_per_transaction_byte_write" }, - 0, + { RELEASE_V1_11.. => "storage_io_per_transaction_byte_write" }, + 89, ], [memory_quota: AbstractValueSize, { 1.. => "memory_quota" }, 10_000_000], [ @@ -230,6 +234,11 @@ crate::gas_schedule::macros::define_gas_parameters!( { 15.. => "max_total_dependency_size" }, 1024 * 1024 * 12 / 10, // 1.2 MB ], + [ + keyless_base_cost: InternalGas, + { RELEASE_V1_12.. => "keyless.base" }, + 414_000_000, + ] ] ); diff --git a/aptos-move/aptos-gas-schedule/src/ver.rs b/aptos-move/aptos-gas-schedule/src/ver.rs index 846ed6190b243..d83434cb0cca5 100644 --- a/aptos-move/aptos-gas-schedule/src/ver.rs +++ b/aptos-move/aptos-gas-schedule/src/ver.rs @@ -8,13 +8,14 @@ /// - Changing how gas is calculated in any way /// /// Change log: +/// - V17 +/// - Gas for keyless /// - V16 /// - IO Gas for the transaction itself and events in the transaction output /// - V15 /// - Gas & limits for dependencies /// - V14 /// - Gas for type creation -/// - V13 /// - Storage Fee: Make state bytes refundable and remove the per slot free quota, gated by flag REFUNDABLE_BYTES /// - V13 /// (skipped due to testnet mis-operation) @@ -55,4 +56,11 @@ /// global operations. /// - V1 /// - TBA -pub const LATEST_GAS_FEATURE_VERSION: u64 = 16; +pub const LATEST_GAS_FEATURE_VERSION: u64 = 17; + +#[allow(dead_code)] +pub(crate) mod gas_feature_versions { + pub(crate) const RELEASE_V1_11: u64 = 16; + pub(crate) const RELEASE_V1_12: u64 = 17; + pub(crate) const RELEASE_V1_13: u64 = 18; +} diff --git a/aptos-move/aptos-memory-usage-tracker/src/lib.rs b/aptos-move/aptos-memory-usage-tracker/src/lib.rs index 702559e8ac23b..0db7ca683a008 100644 --- a/aptos-move/aptos-memory-usage-tracker/src/lib.rs +++ b/aptos-move/aptos-memory-usage-tracker/src/lib.rs @@ -489,5 +489,7 @@ where ) -> PartialVMResult<()>; fn charge_intrinsic_gas_for_transaction(&mut self, txn_size: NumBytes) -> VMResult<()>; + + fn charge_keyless(&mut self) -> VMResult<()>; } } diff --git a/aptos-move/aptos-native-interface/src/builder.rs b/aptos-move/aptos-native-interface/src/builder.rs index 8a83b966f5582..6df3a3a40a9cc 100644 --- a/aptos-move/aptos-native-interface/src/builder.rs +++ b/aptos-move/aptos-native-interface/src/builder.rs @@ -143,6 +143,20 @@ impl SafeNativeBuilder { OutOfGas => Ok(NativeResult::out_of_gas(context.gas_used)), // TODO(Gas): Check if err is indeed an invariant violation. InvariantViolation(err) => Err(err), + FunctionDispatch { + cost, + module_name, + func_name, + ty_args, + args, + } => Ok(NativeResult::CallFunction { + cost, + module_name, + func_name, + ty_args, + args, + }), + LoadModule { module_name } => Ok(NativeResult::LoadModule { module_name }), }, } }; diff --git a/aptos-move/aptos-native-interface/src/errors.rs b/aptos-move/aptos-native-interface/src/errors.rs index e4ce92cbc7717..d78df9e332c3b 100644 --- a/aptos-move/aptos-native-interface/src/errors.rs +++ b/aptos-move/aptos-native-interface/src/errors.rs @@ -2,6 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 use move_binary_format::errors::PartialVMError; +use move_core_types::{ + gas_algebra::InternalGas, identifier::Identifier, language_storage::ModuleId, +}; +use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use smallvec::SmallVec; /// Saner representation of a native function error. #[allow(unused)] @@ -23,6 +28,27 @@ pub enum SafeNativeError { /// Indicating that the native function ran into some internal errors that shall not normally /// be triggerable by user inputs. InvariantViolation(PartialVMError), + + /// Indicating the native function will result in a switch in control flow. + /// + /// Please refer to the implementation in aptos_framework::natives::dispatchable_fungible_asset::native_dispatch + /// for reference implementation and avoid having an alternative implementation. + /// + /// It is important to make sure the args are in the exact same order as passed in from the native argument input + /// as the MoveVM relies on this ordering to perform paranoid mode stack transition. + FunctionDispatch { + cost: InternalGas, + module_name: ModuleId, + func_name: Identifier, + ty_args: Vec, + args: SmallVec<[Value; 1]>, + }, + + /// Load up a module and charge the module accordingly. + /// + /// It is critical to invoke this function before calling FunctionDispatch to make sure the module loading + /// is charged properly, otherwise it would be a potential gas issue. + LoadModule { module_name: ModuleId }, } // Allows us to keep using the `?` operator on function calls that return `PartialVMResult` inside safe natives. diff --git a/aptos-move/aptos-release-builder/data/release.yaml b/aptos-move/aptos-release-builder/data/release.yaml index 84ff32b2de7db..a34ef65f76446 100644 --- a/aptos-move/aptos-release-builder/data/release.yaml +++ b/aptos-move/aptos-release-builder/data/release.yaml @@ -1,6 +1,6 @@ --- remote_endpoint: ~ -name: "v1.11" +name: "v1.12" proposals: - name: step_1_increase_max_txn_gas metadata: @@ -8,40 +8,19 @@ proposals: description: "Increase max txn gas temporarily for framework upgrade" execution_mode: MultiStep update_sequence: - - DefaultGasWithOverrideOld: + - DefaultGasWithOverride: + feature_version: 16 overrides: - name: "txn.max_execution_gas" value: 3676000000 - name: step_2_upgrade_framework metadata: - title: "Multi-step proposal to upgrade mainnet framework to v1.11" - description: "This includes changes in https://github.com/aptos-labs/aptos-core/commits/aptos-release-v1.11" + title: "Multi-step proposal to upgrade mainnet framework to v1.12" + description: "This includes changes in https://github.com/aptos-labs/aptos-core/commits/aptos-release-v1.12" execution_mode: MultiStep update_sequence: - Framework: bytecode_version: 6 git_hash: ~ - - RawScript: aptos-move/aptos-release-builder/data/proposals/randomness_framework_initialization.move - - DefaultGas - - name: step_3_enable_checking_unstable_bytecode - metadata: - title: "Enable the check to reject unstable bytecode to be published to mainnet" - description: "Reject unstable bytecode to be published to mainnet" - discussion_url: "https://github.com/aptos-labs/aptos-core/pull/12814" - execution_mode: MultiStep - update_sequence: - - FeatureFlag: - enabled: - - reject_unstable_bytecode - - name: step_4_enable_randomness - metadata: - title: "Enable randomness with fast path optimization." - description: "Enable randomness with fast path optimization." - discussion_url: "https://github.com/aptos-labs/aptos-core/pull/TBD" - execution_mode: MultiStep - update_sequence: - - Randomness: - V2: - secrecy_threshold_in_percentage: 50 - reconstruct_threshold_in_percentage: 66 - fast_path_secrecy_threshold_in_percentage: 67 + - DefaultGasWithOverride: + feature_version: 17 diff --git a/aptos-move/aptos-release-builder/src/components/feature_flags.rs b/aptos-move/aptos-release-builder/src/components/feature_flags.rs index ba53434648cae..b155abc4ce941 100644 --- a/aptos-move/aptos-release-builder/src/components/feature_flags.rs +++ b/aptos-move/aptos-release-builder/src/components/feature_flags.rs @@ -109,6 +109,11 @@ pub enum FeatureFlag { DelegationPoolAllowlisting, ModuleEventMigration, RejectUnstableBytecode, + TransactionContextExtension, + CoinToFungibleAssetMigration, + PrimaryAPTFungibleStoreAtUserAddress, + ObjectNativeDerivedAddress, + DispatchableFungibleAsset, } fn generate_features_blob(writer: &CodeWriter, data: &[u64]) { @@ -274,6 +279,19 @@ impl From for AptosFeatureFlag { }, FeatureFlag::ModuleEventMigration => AptosFeatureFlag::MODULE_EVENT_MIGRATION, FeatureFlag::RejectUnstableBytecode => AptosFeatureFlag::REJECT_UNSTABLE_BYTECODE, + FeatureFlag::TransactionContextExtension => { + AptosFeatureFlag::TRANSACTION_CONTEXT_EXTENSION + }, + FeatureFlag::CoinToFungibleAssetMigration => { + AptosFeatureFlag::COIN_TO_FUNGIBLE_ASSET_MIGRATION + }, + FeatureFlag::PrimaryAPTFungibleStoreAtUserAddress => { + AptosFeatureFlag::PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS + }, + FeatureFlag::ObjectNativeDerivedAddress => { + AptosFeatureFlag::OBJECT_NATIVE_DERIVED_ADDRESS + }, + FeatureFlag::DispatchableFungibleAsset => AptosFeatureFlag::DISPATCHABLE_FUNGIBLE_ASSET, } } } @@ -368,6 +386,19 @@ impl From for FeatureFlag { }, AptosFeatureFlag::MODULE_EVENT_MIGRATION => FeatureFlag::ModuleEventMigration, AptosFeatureFlag::REJECT_UNSTABLE_BYTECODE => FeatureFlag::RejectUnstableBytecode, + AptosFeatureFlag::TRANSACTION_CONTEXT_EXTENSION => { + FeatureFlag::TransactionContextExtension + }, + AptosFeatureFlag::COIN_TO_FUNGIBLE_ASSET_MIGRATION => { + FeatureFlag::CoinToFungibleAssetMigration + }, + AptosFeatureFlag::PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS => { + FeatureFlag::PrimaryAPTFungibleStoreAtUserAddress + }, + AptosFeatureFlag::OBJECT_NATIVE_DERIVED_ADDRESS => { + FeatureFlag::ObjectNativeDerivedAddress + }, + AptosFeatureFlag::DISPATCHABLE_FUNGIBLE_ASSET => FeatureFlag::DispatchableFungibleAsset, } } } diff --git a/aptos-move/aptos-transactional-test-harness/Cargo.toml b/aptos-move/aptos-transactional-test-harness/Cargo.toml index 407e8a41d6a4f..5b4b1e8373b3a 100644 --- a/aptos-move/aptos-transactional-test-harness/Cargo.toml +++ b/aptos-move/aptos-transactional-test-harness/Cargo.toml @@ -31,6 +31,7 @@ move-binary-format = { workspace = true, features = ["fuzzing"] } move-bytecode-verifier = { workspace = true } move-command-line-common = { workspace = true } move-compiler = { workspace = true } +move-compiler-v2 = { workspace = true } move-core-types = { workspace = true, features = ["fuzzing"] } move-model = { workspace = true } move-resource-viewer = { workspace = true } diff --git a/aptos-move/aptos-transactional-test-harness/src/aptos_test_harness.rs b/aptos-move/aptos-transactional-test-harness/src/aptos_test_harness.rs index 66809227225a3..fa331fc81db29 100644 --- a/aptos-move/aptos-transactional-test-harness/src/aptos_test_harness.rs +++ b/aptos-move/aptos-transactional-test-harness/src/aptos_test_harness.rs @@ -12,7 +12,6 @@ use aptos_crypto::{ use aptos_gas_schedule::{InitialGasSchedule, TransactionGasParameters}; use aptos_language_e2e_tests::data_store::{FakeDataStore, GENESIS_CHANGE_SET_HEAD}; use aptos_types::{ - access_path::AccessPath, account_config::{aptos_test_root_address, AccountResource, CoinStoreResource}, block_executor::config::BlockExecutorConfigFromOnchain, block_metadata::BlockMetadata, @@ -32,7 +31,9 @@ use clap::Parser; use move_binary_format::file_format::{CompiledModule, CompiledScript}; use move_bytecode_verifier::verify_module; use move_command_line_common::{ - address::ParsedAddress, files::verify_and_create_named_address_mapping, + address::ParsedAddress, + env::{get_move_compiler_block_v1_from_env, get_move_compiler_v2_from_env}, + files::verify_and_create_named_address_mapping, }; use move_compiler::{self, shared::PackagePaths, FullyCompiledProgram}; use move_core_types::{ @@ -44,11 +45,12 @@ use move_core_types::{ transaction_argument::{convert_txn_args, TransactionArgument}, value::{MoveTypeLayout, MoveValue}, }; +use move_model::metadata::LanguageVersion; use move_resource_viewer::{AnnotatedMoveValue, MoveValueAnnotator}; use move_transactional_test_runner::{ framework::{run_test_impl, CompiledState, MoveTestAdapter}, tasks::{InitCommand, SyntaxChoice, TaskInput}, - vm_test_harness::{view_resource_in_move_storage, TestRunConfig}, + vm_test_harness::{view_resource_in_move_storage, PrecompiledFilesModules, TestRunConfig}, }; use move_vm_runtime::session::SerializedReturnValues; use once_cell::sync::Lazy; @@ -287,7 +289,10 @@ fn panic_missing_private_key(cmd_name: &str) -> ! { ) } -static PRECOMPILED_APTOS_FRAMEWORK: Lazy = Lazy::new(|| { +static PRECOMPILED_APTOS_FRAMEWORK_V1: Lazy> = Lazy::new(|| { + if get_move_compiler_block_v1_from_env() { + return None; + } let deps = vec![PackagePaths { name: None, paths: aptos_cached_packages::head_release_bundle() @@ -303,7 +308,7 @@ static PRECOMPILED_APTOS_FRAMEWORK: Lazy = Lazy::new(|| { ) .unwrap(); match program_res { - Ok(af) => af, + Ok(af) => Some(af), Err((files, errors)) => { eprintln!("!!!Aptos Framework failed to compile!!!"); move_compiler::diagnostics::report_diagnostics(&files, errors) @@ -311,6 +316,34 @@ static PRECOMPILED_APTOS_FRAMEWORK: Lazy = Lazy::new(|| { } }); +static APTOS_FRAMEWORK_FILES: Lazy> = Lazy::new(|| { + aptos_cached_packages::head_release_bundle() + .files() + .unwrap() +}); + +static PRECOMPILED_APTOS_FRAMEWORK_V2: Lazy = Lazy::new(|| { + let named_address_mapping_strings: Vec = aptos_framework::named_addresses() + .iter() + .map(|(string, num_addr)| format!("{}={}", string, num_addr)) + .collect(); + + let options = move_compiler_v2::Options { + sources: aptos_cached_packages::head_release_bundle() + .files() + .unwrap(), + dependencies: vec![], + named_address_mapping: named_address_mapping_strings, + known_attributes: aptos_framework::extended_checks::get_all_attribute_names().clone(), + language_version: None, + ..move_compiler_v2::Options::default() + }; + + let (_global_env, modules) = move_compiler_v2::run_move_compiler_to_stderr(options) + .expect("stdlib compilation succeeds"); + PrecompiledFilesModules::new(APTOS_FRAMEWORK_FILES.clone(), modules) +}); + /** * Test Adapter Implementation */ @@ -372,12 +405,9 @@ impl<'a> AptosTestAdapter<'a> { /// Obtain a Rust representation of the account resource from storage, which is used to derive /// a few default transaction parameters. fn fetch_account_resource(&self, signer_addr: &AccountAddress) -> Result { - let account_access_path = - AccessPath::resource_access_path(*signer_addr, AccountResource::struct_tag()) - .expect("access path in test"); let account_blob = self .storage - .get_state_value_bytes(&StateKey::access_path(account_access_path)) + .get_state_value_bytes(&StateKey::resource_typed::(signer_addr)?) .unwrap() .ok_or_else(|| { format_err!( @@ -392,13 +422,9 @@ impl<'a> AptosTestAdapter<'a> { fn fetch_account_balance(&self, signer_addr: &AccountAddress) -> Result { let aptos_coin_tag = CoinStoreResource::struct_tag(); - let coin_access_path = - AccessPath::resource_access_path(*signer_addr, aptos_coin_tag.clone()) - .expect("access path in test"); - let balance_blob = self .storage - .get_state_value_bytes(&StateKey::access_path(coin_access_path)) + .get_state_value_bytes(&StateKey::resource(signer_addr, &aptos_coin_tag)?) .unwrap() .ok_or_else(|| { format_err!( @@ -574,7 +600,8 @@ impl<'a> MoveTestAdapter<'a> for AptosTestAdapter<'a> { default_syntax: SyntaxChoice, comparison_mode: bool, run_config: TestRunConfig, - pre_compiled_deps: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v1: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v2: Option<&'a PrecompiledFilesModules>, task_opt: Option>, ) -> (Self, Option) { // Named address mapping @@ -631,7 +658,12 @@ impl<'a> MoveTestAdapter<'a> for AptosTestAdapter<'a> { } let mut adapter = Self { - compiled_state: CompiledState::new(named_address_mapping, pre_compiled_deps, None), + compiled_state: CompiledState::new( + named_address_mapping, + pre_compiled_deps_v1, + pre_compiled_deps_v2, + None, + ), default_syntax, storage, private_key_mapping, @@ -900,7 +932,7 @@ impl<'a> MoveTestAdapter<'a> for AptosTestAdapter<'a> { let raw_key = vm_key.undecorate().simple_serialize().unwrap(); let state_key = - StateKey::table_item(TableHandle(view_table_cmd.table_handle), raw_key); + StateKey::table_item(&TableHandle(view_table_cmd.table_handle), &raw_key); let bytes = self .storage @@ -960,6 +992,26 @@ fn render_events(events: &[ContractEvent]) -> Option { } } +fn precompiled_v1_stdlib_if_needed( + config: &TestRunConfig, +) -> Option<&'static FullyCompiledProgram> { + match config { + TestRunConfig::CompilerV1 { .. } => PRECOMPILED_APTOS_FRAMEWORK_V1.as_ref(), + TestRunConfig::ComparisonV1V2 { .. } => PRECOMPILED_APTOS_FRAMEWORK_V1.as_ref(), + TestRunConfig::CompilerV2 { .. } => None, + } +} + +fn precompiled_v2_stdlib_if_needed( + config: &TestRunConfig, +) -> Option<&'static PrecompiledFilesModules> { + match config { + TestRunConfig::CompilerV1 { .. } => None, + TestRunConfig::ComparisonV1V2 { .. } => Some(&*PRECOMPILED_APTOS_FRAMEWORK_V2), + TestRunConfig::CompilerV2 { .. } => Some(&*PRECOMPILED_APTOS_FRAMEWORK_V2), + } +} + pub fn run_aptos_test(path: &Path) -> Result<(), Box> { run_aptos_test_with_config(path, TestRunConfig::CompilerV1) } @@ -968,5 +1020,16 @@ pub fn run_aptos_test_with_config( path: &Path, config: TestRunConfig, ) -> Result<(), Box> { - run_test_impl::(config, path, Some(&*PRECOMPILED_APTOS_FRAMEWORK), &None) + let config = + if get_move_compiler_v2_from_env() && !matches!(config, TestRunConfig::CompilerV2 { .. }) { + TestRunConfig::CompilerV2 { + language_version: LanguageVersion::default(), + v2_experiments: vec![], + } + } else { + config + }; + let v1_lib = precompiled_v1_stdlib_if_needed(&config); + let v2_lib = precompiled_v2_stdlib_if_needed(&config); + run_test_impl::(config, path, v1_lib, v2_lib, &None) } diff --git a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs index 937214c4d6b5b..795ddb2d2854c 100644 --- a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs +++ b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs @@ -11,7 +11,8 @@ use move_binary_format::CompiledModule; use move_core_types::{account_address::AccountAddress, ident_str, identifier::Identifier}; use move_ir_compiler::Compiler; use move_vm_runtime::{ - move_vm::MoveVM, native_extensions::NativeContextExtensions, native_functions::NativeFunction, + module_traversal::*, move_vm::MoveVM, native_extensions::NativeContextExtensions, + native_functions::NativeFunction, }; use move_vm_test_utils::InMemoryStorage; use move_vm_types::{ @@ -163,11 +164,18 @@ fn main() -> Result<()> { extensions.add(NativeTableContext::new([0; 32], &storage)); let mut sess = vm.new_session_with_extensions(&storage, extensions); + let traversal_storage = TraversalStorage::new(); let src = fs::read_to_string(&args[1])?; if let Ok(script_blob) = Compiler::new(test_modules.iter().collect()).into_script_blob(&src) { let args: Vec> = vec![]; - sess.execute_script(script_blob, vec![], args, &mut UnmeteredGasMeter)?; + sess.execute_script( + script_blob, + vec![], + args, + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + )?; } else { let module = Compiler::new(test_modules.iter().collect()).into_compiled_module(&src)?; let mut module_blob = vec![]; @@ -185,6 +193,7 @@ fn main() -> Result<()> { vec![], args, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), )?; println!("{:?}", res); } diff --git a/aptos-move/aptos-vm-types/src/change_set.rs b/aptos-move/aptos-vm-types/src/change_set.rs index b0475cbe7664e..f44a15b584d98 100644 --- a/aptos-move/aptos-vm-types/src/change_set.rs +++ b/aptos-move/aptos-vm-types/src/change_set.rs @@ -19,7 +19,7 @@ use aptos_types::{ contract_event::ContractEvent, delayed_fields::PanicError, state_store::{ - state_key::{StateKey, StateKeyInner}, + state_key::{inner::StateKeyInner, StateKey}, state_value::StateValueMetadata, }, transaction::ChangeSet as StorageChangeSet, diff --git a/aptos-move/aptos-vm-types/src/resource_group_adapter.rs b/aptos-move/aptos-vm-types/src/resource_group_adapter.rs index 8ff9cdce4148a..bbac0b1c7a6a5 100644 --- a/aptos-move/aptos-vm-types/src/resource_group_adapter.rs +++ b/aptos-move/aptos-vm-types/src/resource_group_adapter.rs @@ -321,8 +321,8 @@ mod tests { fn new() -> Self { let mut group = HashMap::new(); - let key_0 = StateKey::raw(vec![0]); - let key_1 = StateKey::raw(vec![1]); + let key_0 = StateKey::raw(&[0]); + let key_1 = StateKey::raw(&[1]); // for testing purposes, o.w. state view should never contain an empty map. group.insert(key_0, MockGroup::new(BTreeMap::new())); @@ -442,7 +442,7 @@ mod tests { let adapter = ResourceGroupAdapter::new(None, &state_view, 3, false); assert_eq!(adapter.group_size_kind, GroupSizeKind::None); - let key_1 = StateKey::raw(vec![1]); + let key_1 = StateKey::raw(&[1]); let tag_0 = mock_tag_0(); assert_ok_eq!(adapter.load_to_cache(&key_1), false); @@ -456,9 +456,9 @@ mod tests { let adapter = ResourceGroupAdapter::new(None, &state_view, 5, false); assert_eq!(adapter.group_size_kind, GroupSizeKind::None); - let key_0 = StateKey::raw(vec![0]); - let key_1 = StateKey::raw(vec![1]); - let key_2 = StateKey::raw(vec![2]); + let key_0 = StateKey::raw(&[0]); + let key_1 = StateKey::raw(&[1]); + let key_2 = StateKey::raw(&[2]); let tag_0 = mock_tag_0(); let tag_1 = mock_tag_1(); let tag_2 = mock_tag_2(); @@ -522,9 +522,9 @@ mod tests { ); assert_eq!(adapter.group_size_kind, GroupSizeKind::AsBlob); - let key_0 = StateKey::raw(vec![0]); - let key_1 = StateKey::raw(vec![1]); - let key_2 = StateKey::raw(vec![2]); + let key_0 = StateKey::raw(&[0]); + let key_1 = StateKey::raw(&[1]); + let key_2 = StateKey::raw(&[2]); let key_0_blob_len = ResourceGroupSize::Concrete(state_view.group.get(&key_0).unwrap().blob.len() as u64); @@ -568,9 +568,9 @@ mod tests { let adapter = ResourceGroupAdapter::new(Some(&state_view), &state_view, 12, true); assert_eq!(adapter.group_size_kind, GroupSizeKind::AsSum); - let key_0 = StateKey::raw(vec![0]); - let key_1 = StateKey::raw(vec![1]); - let key_2 = StateKey::raw(vec![2]); + let key_0 = StateKey::raw(&[0]); + let key_1 = StateKey::raw(&[1]); + let key_2 = StateKey::raw(&[2]); let key_0_size_as_sum = state_view.group.get(&key_0).unwrap().size_as_sum; let key_1_size_as_sum = state_view.group.get(&key_1).unwrap().size_as_sum; @@ -608,9 +608,9 @@ mod tests { let adapter = ResourceGroupAdapter::new(None, &state_view, 8, false); assert_eq!(adapter.group_size_kind, GroupSizeKind::None); - let key_0 = StateKey::raw(vec![0]); - let key_1 = StateKey::raw(vec![1]); - let key_2 = StateKey::raw(vec![2]); + let key_0 = StateKey::raw(&[0]); + let key_1 = StateKey::raw(&[1]); + let key_2 = StateKey::raw(&[2]); assert_ok_eq!( adapter.resource_group_size(&key_1), @@ -644,9 +644,9 @@ mod tests { let adapter = ResourceGroupAdapter::new(None, &state_view, 0, false); assert_eq!(adapter.group_size_kind, GroupSizeKind::None); - let key_0 = StateKey::raw(vec![0]); - let key_1 = StateKey::raw(vec![1]); - let key_2 = StateKey::raw(vec![2]); + let key_0 = StateKey::raw(&[0]); + let key_1 = StateKey::raw(&[1]); + let key_2 = StateKey::raw(&[2]); let tag_0 = mock_tag_0(); let tag_1 = mock_tag_1(); let tag_2 = mock_tag_2(); @@ -675,9 +675,9 @@ mod tests { let adapter = ResourceGroupAdapter::new(None, &state_view, 3, false); assert_eq!(adapter.group_size_kind, GroupSizeKind::None); - let key_0 = StateKey::raw(vec![0]); - let key_1 = StateKey::raw(vec![1]); - let key_2 = StateKey::raw(vec![2]); + let key_0 = StateKey::raw(&[0]); + let key_1 = StateKey::raw(&[1]); + let key_2 = StateKey::raw(&[2]); let tag_0 = mock_tag_0(); let tag_1 = mock_tag_1(); let tag_2 = mock_tag_2(); diff --git a/aptos-move/aptos-vm-types/src/storage/space_pricing.rs b/aptos-move/aptos-vm-types/src/storage/space_pricing.rs index 4f88c1b2a8781..8ae986047ed0b 100644 --- a/aptos-move/aptos-vm-types/src/storage/space_pricing.rs +++ b/aptos-move/aptos-vm-types/src/storage/space_pricing.rs @@ -263,7 +263,7 @@ mod tests { let mut params = TransactionGasParameters::random(); params.storage_fee_per_state_byte = 5.into(); params.storage_fee_per_state_slot = 1000.into(); - let key = StateKey::raw(vec![1, 2, 3]); + let key = StateKey::raw(&[1, 2, 3]); assert_eq!(key.size(), 3); // to make sure our assumptions on the numbers in the assertions below are correct let ts = CurrentTimeMicroseconds { microseconds: 0 }; let mut meta = StateValueMetadata::new(0, 0, &ts); diff --git a/aptos-move/aptos-vm-types/src/tests/test_change_set.rs b/aptos-move/aptos-vm-types/src/tests/test_change_set.rs index cf4b8686ff165..478eaa3ff91b9 100644 --- a/aptos-move/aptos-vm-types/src/tests/test_change_set.rs +++ b/aptos-move/aptos-vm-types/src/tests/test_change_set.rs @@ -18,7 +18,6 @@ use aptos_aggregator::{ delta_change_set::DeltaWithMax, }; use aptos_types::{ - access_path::AccessPath, delayed_fields::{PanicError, SnapshotToStringFormula}, state_store::{state_key::StateKey, state_value::StateValueMetadata}, transaction::ChangeSet as StorageChangeSet, @@ -376,10 +375,8 @@ fn test_roundtrip_to_storage_change_set() { }; let test_module_id = ModuleId::new(AccountAddress::ONE, ident_str!("bar").into()); - let resource_key = StateKey::access_path( - AccessPath::resource_access_path(AccountAddress::ONE, test_struct_tag).unwrap(), - ); - let module_key = StateKey::access_path(AccessPath::code_access_path(test_module_id)); + let resource_key = StateKey::resource(&AccountAddress::ONE, &test_struct_tag).unwrap(); + let module_key = StateKey::module_id(&test_module_id); let write_set = WriteSetMut::new(vec![ (resource_key, WriteOp::legacy_deletion()), (module_key, WriteOp::legacy_deletion()), @@ -825,8 +822,8 @@ mod tests { #[test] fn test_squash_groups_one_empty() { - let key_1 = StateKey::raw(vec![1]); - let key_2 = StateKey::raw(vec![2]); + let key_1 = StateKey::raw(&[1]); + let key_2 = StateKey::raw(&[2]); let mut base_update = BTreeMap::new(); base_update.insert( @@ -864,7 +861,7 @@ mod tests { #[test_case(1, 2)] // modify, delete #[test_case(2, 0)] // delete, create fn test_squash_groups_mergeable_metadata(base_type_idx: u8, additional_type_idx: u8) { - let key = StateKey::raw(vec![0]); + let key = StateKey::raw(&[0]); let mut base_update = BTreeMap::new(); let mut additional_update = BTreeMap::new(); @@ -902,7 +899,7 @@ mod tests { #[test_case(2, 1)] // delete, modify #[test_case(2, 2)] // delete, delete fn test_squash_groups_error(base_type_idx: u8, additional_type_idx: u8) { - let key = StateKey::raw(vec![0]); + let key = StateKey::raw(&[0]); let mut base_update = BTreeMap::new(); let mut additional_update = BTreeMap::new(); @@ -928,7 +925,7 @@ mod tests { #[test] fn test_squash_groups_noop() { - let key = StateKey::raw(vec![0]); + let key = StateKey::raw(&[0]); let mut base_update = BTreeMap::new(); let mut additional_update = BTreeMap::new(); @@ -960,8 +957,8 @@ mod tests { #[test] fn test_inner_ops() { - let key_1 = StateKey::raw(vec![1]); - let key_2 = StateKey::raw(vec![2]); + let key_1 = StateKey::raw(&[1]); + let key_2 = StateKey::raw(&[2]); let mut base_update = BTreeMap::new(); let mut additional_update = BTreeMap::new(); diff --git a/aptos-move/aptos-vm-types/src/tests/utils.rs b/aptos-move/aptos-vm-types/src/tests/utils.rs index 1cbe151592cdd..d40128b602552 100644 --- a/aptos-move/aptos-vm-types/src/tests/utils.rs +++ b/aptos-move/aptos-vm-types/src/tests/utils.rs @@ -38,10 +38,10 @@ impl CheckChangeSet for MockChangeSetChecker { macro_rules! as_state_key { ($k:ident) => { - StateKey::raw($k.to_string().into_bytes()) + StateKey::raw($k.to_string().as_bytes()) }; ($k:expr) => { - StateKey::raw($k.to_string().into_bytes()) + StateKey::raw($k.to_string().as_bytes()) }; } pub(crate) use as_state_key; diff --git a/aptos-move/aptos-vm/Cargo.toml b/aptos-move/aptos-vm/Cargo.toml index 99e1fbe1f7bdb..88c9f06409540 100644 --- a/aptos-move/aptos-vm/Cargo.toml +++ b/aptos-move/aptos-vm/Cargo.toml @@ -36,6 +36,8 @@ aptos-types = { workspace = true } aptos-utils = { workspace = true } aptos-vm-logging = { workspace = true } aptos-vm-types = { workspace = true } +ark-bn254 = { workspace = true } +ark-groth16 = { workspace = true } bcs = { workspace = true } bytes = { workspace = true } claims = { workspace = true } diff --git a/aptos-move/aptos-vm/src/aptos_vm.rs b/aptos-move/aptos-vm/src/aptos_vm.rs index c7ced543850b4..35ccdcabf0798 100644 --- a/aptos-move/aptos-vm/src/aptos_vm.rs +++ b/aptos-move/aptos-vm/src/aptos_vm.rs @@ -15,7 +15,7 @@ use crate::{ abort_hook::AbortHookSession, epilogue::EpilogueSession, prologue::PrologueSession, user::UserSession, }, - AptosMoveResolver, MoveVmExt, SessionExt, SessionId, + AptosMoveResolver, MoveVmExt, SessionExt, SessionId, UserTransactionContext, }, sharded_block_executor::{executor_client::ExecutorClient, ShardedBlockExecutor}, system_module_names::*, @@ -50,11 +50,12 @@ use aptos_types::{ block_metadata_ext::{BlockMetadataExt, BlockMetadataWithRandomness}, chain_id::ChainId, fee_statement::FeeStatement, + invalid_signature, move_utils::as_move_value::AsMoveValue, on_chain_config::{ - new_epoch_event_key, ConfigurationResource, FeatureFlag, Features, OnChainConfig, - OnChainConsensusConfig, OnChainRandomnessConfig, RandomnessConfigMoveStruct, - TimedFeatureOverride, TimedFeatures, TimedFeaturesBuilder, + new_epoch_event_key, randomness_api_v0_config::RequiredGasDeposit, ConfigurationResource, + FeatureFlag, Features, OnChainConfig, TimedFeatureOverride, TimedFeatures, + TimedFeaturesBuilder, }, randomness::Randomness, state_store::{StateView, TStateView}, @@ -76,6 +77,8 @@ use aptos_vm_types::{ resolver::{ExecutorView, ResourceGroupView}, storage::{change_set_configs::ChangeSetConfigs, StorageGasParameters}, }; +use ark_bn254::Bn254; +use ark_groth16::PreparedVerifyingKey; use claims::assert_err; use fail::fail_point; use move_binary_format::{ @@ -201,7 +204,9 @@ pub struct AptosVM { gas_params: Result, pub(crate) storage_gas_params: Result, timed_features: TimedFeatures, - randomness_enabled: bool, + /// For a new chain, or even mainnet, the VK might not necessarily be set. + pvk: Option>, + randomness_api_v0_required_deposit: RequiredGasDeposit, } impl AptosVM { @@ -210,7 +215,8 @@ impl AptosVM { override_is_delayed_field_optimization_capable: Option, ) -> Self { let _timer = TIMER.timer_with(&["AptosVM::new"]); - + let randomness_api_v0_required_deposit = RequiredGasDeposit::fetch_config(resolver) + .unwrap_or_else(RequiredGasDeposit::default_if_missing); let features = Features::fetch_config(resolver).unwrap_or_default(); let ( gas_params, @@ -241,12 +247,6 @@ impl AptosVM { let aggregator_v2_type_tagging = override_is_delayed_field_optimization_capable && features.is_aggregator_v2_delayed_fields_enabled(); - let consensus_config = OnChainConsensusConfig::fetch_config(resolver).unwrap_or_default(); - let randomness_config = RandomnessConfigMoveStruct::fetch_config(resolver) - .and_then(|x| OnChainRandomnessConfig::try_from(x).ok()) - .unwrap_or_else(OnChainRandomnessConfig::default_if_missing); - let randomness_enabled = - consensus_config.is_vtxn_enabled() && randomness_config.randomness_enabled(); let move_vm = MoveVmExt::new( native_gas_params, misc_gas_params, @@ -259,6 +259,15 @@ impl AptosVM { ) .expect("should be able to create Move VM; check if there are duplicated natives"); + // We use an `Option` to handle the VK not being set on-chain, or an incorrect VK being set + // via governance (although, currently, we do check for that in `keyless_account.move`). + let pvk = keyless_validation::get_groth16_vk_onchain(resolver) + .ok() + .and_then(|vk| { + // println!("[aptos-vm][groth16] PVK cached in VM: {}", vk.hash()); + vk.try_into().ok() + }); + Self { is_simulation: false, move_vm, @@ -266,7 +275,8 @@ impl AptosVM { gas_params, storage_gas_params, timed_features, - randomness_enabled, + pvk, + randomness_api_v0_required_deposit, } } @@ -274,8 +284,10 @@ impl AptosVM { &self, resolver: &'r S, session_id: SessionId, + user_transaction_context_opt: Option, ) -> SessionExt<'r, '_> { - self.move_vm.new_session(resolver, session_id) + self.move_vm + .new_session(resolver, session_id, user_transaction_context_opt) } #[inline(always)] @@ -437,6 +449,7 @@ impl AptosVM { resolver: &impl AptosMoveResolver, log_context: &AdapterLogSchema, change_set_configs: &ChangeSetConfigs, + traversal_context: &mut TraversalContext, ) -> (VMStatus, VMOutput) { if self.gas_feature_version >= 12 { // Check if the gas meter's internal counters are consistent. @@ -482,6 +495,7 @@ impl AptosVM { status, log_context, change_set_configs, + traversal_context, ) { Ok((change_set, fee_statement, status)) => VMOutput::new( change_set, @@ -530,6 +544,7 @@ impl AptosVM { status: ExecutionStatus, log_context: &AdapterLogSchema, change_set_configs: &ChangeSetConfigs, + traversal_context: &mut TraversalContext, ) -> Result<(VMChangeSet, FeeStatement, ExecutionStatus), VMStatus> { // Storage refund is zero since no slots are deleted in aborted transactions. const ZERO_STORAGE_REFUND: u64 = 0; @@ -544,24 +559,30 @@ impl AptosVM { let status = self.inject_abort_info_if_available(status); abort_hook_session.execute(|session| { - create_account_if_does_not_exist(session, gas_meter, txn_data.sender()) - // if this fails, it is likely due to out of gas, so we try again without metering - // and then validate below that we charged sufficiently. - .or_else(|_err| { - create_account_if_does_not_exist( - session, - &mut UnmeteredGasMeter, - txn_data.sender(), - ) - }) - .map_err(expect_no_verification_errors) - .or_else(|err| { - expect_only_successful_execution( - err, - &format!("{:?}::{}", ACCOUNT_MODULE, CREATE_ACCOUNT_IF_DOES_NOT_EXIST), - log_context, - ) - }) + create_account_if_does_not_exist( + session, + gas_meter, + txn_data.sender(), + traversal_context, + ) + // if this fails, it is likely due to out of gas, so we try again without metering + // and then validate below that we charged sufficiently. + .or_else(|_err| { + create_account_if_does_not_exist( + session, + &mut UnmeteredGasMeter, + txn_data.sender(), + traversal_context, + ) + }) + .map_err(expect_no_verification_errors) + .or_else(|err| { + expect_only_successful_execution( + err, + &format!("{:?}::{}", ACCOUNT_MODULE, CREATE_ACCOUNT_IF_DOES_NOT_EXIST), + log_context, + ) + }) })?; let mut change_set = abort_hook_session.finish(change_set_configs)?; @@ -618,6 +639,7 @@ impl AptosVM { self.features(), txn_data, log_context, + traversal_context, ) })?; epilogue_session @@ -644,6 +666,7 @@ impl AptosVM { self.features(), txn_data, log_context, + traversal_context, ) })?; epilogue_session @@ -659,6 +682,7 @@ impl AptosVM { txn_data: &TransactionMetadata, log_context: &AdapterLogSchema, change_set_configs: &ChangeSetConfigs, + traversal_context: &mut TraversalContext, ) -> Result<(VMStatus, VMOutput), VMStatus> { if self.gas_feature_version >= 12 { // Check if the gas meter's internal counters are consistent. @@ -688,6 +712,7 @@ impl AptosVM { self.features(), txn_data, log_context, + traversal_context, ) })?; let change_set = epilogue_session.finish(change_set_configs)?; @@ -738,18 +763,25 @@ impl AptosVM { self.features().is_enabled(FeatureFlag::STRUCT_CONSTRUCTORS), )?; - session.execute_script(script.code(), script.ty_args().to_vec(), args, gas_meter)?; + session.execute_script( + script.code(), + script.ty_args().to_vec(), + args, + gas_meter, + traversal_context, + )?; Ok(()) } fn validate_and_execute_entry_function( &self, + resolver: &impl AptosMoveResolver, session: &mut SessionExt, gas_meter: &mut impl AptosGasMeter, traversal_context: &mut TraversalContext, senders: Vec, entry_fn: &EntryFunction, - txn_data: &TransactionMetadata, + _txn_data: &TransactionMetadata, ) -> Result<(), VMStatus> { // Note: Feature gating is needed here because the traversal of the dependencies could // result in shallow-loading of the modules and therefore subtle changes in @@ -770,7 +802,8 @@ impl AptosVM { entry_fn.ty_args(), )?; - if is_friend_or_private && txn_data.required_deposit.is_some() { + // The `has_randomness_attribute()` should have been feature-gated in 1.11... + if is_friend_or_private && has_randomness_attribute(resolver, session, entry_fn)? { let txn_context = session .get_native_extensions() .get_mut::(); @@ -792,6 +825,7 @@ impl AptosVM { entry_fn.ty_args().to_vec(), args, gas_meter, + traversal_context, )?; Ok(()) } @@ -817,6 +851,9 @@ impl AptosVM { }); gas_meter.charge_intrinsic_gas_for_transaction(txn_data.transaction_size())?; + if txn_data.is_keyless() { + gas_meter.charge_keyless()?; + } match payload { TransactionPayload::Script(script) => { @@ -833,6 +870,7 @@ impl AptosVM { TransactionPayload::EntryFunction(entry_fn) => { session.execute(|session| { self.validate_and_execute_entry_function( + resolver, session, gas_meter, traversal_context, @@ -871,6 +909,7 @@ impl AptosVM { txn_data, log_context, change_set_configs, + traversal_context, ) } @@ -939,6 +978,7 @@ impl AptosVM { aptos_try!({ return_on_failure!(session.execute(|session| self .execute_multisig_entry_function( + resolver, session, gas_meter, traversal_context, @@ -965,6 +1005,7 @@ impl AptosVM { txn_data, log_context, change_set_configs, + traversal_context, ) }) }, @@ -1001,6 +1042,9 @@ impl AptosVM { }); gas_meter.charge_intrinsic_gas_for_transaction(txn_data.transaction_size())?; + if txn_data.is_keyless() { + gas_meter.charge_keyless()?; + } // Step 1: Obtain the payload. If any errors happen here, the entire transaction should fail let invariant_violation_error = || { @@ -1026,6 +1070,7 @@ impl AptosVM { MoveValue::vector_u8(provided_payload), ]), gas_meter, + traversal_context, ) })? .return_values @@ -1061,6 +1106,7 @@ impl AptosVM { MultisigTransactionPayload::EntryFunction(entry_function) => { session.execute(|session| { self.execute_multisig_entry_function( + resolver, session, gas_meter, traversal_context, @@ -1097,6 +1143,7 @@ impl AptosVM { execution_error, txn_data, cleanup_args, + traversal_context, )? } else { self.success_multisig_payload_cleanup( @@ -1106,6 +1153,7 @@ impl AptosVM { txn_data, cleanup_args, change_set_configs, + traversal_context, )? }; @@ -1116,6 +1164,7 @@ impl AptosVM { txn_data, log_context, change_set_configs, + traversal_context, ) } @@ -1162,6 +1211,7 @@ impl AptosVM { fn execute_multisig_entry_function( &self, + resolver: &impl AptosMoveResolver, session: &mut SessionExt, gas_meter: &mut impl AptosGasMeter, traversal_context: &mut TraversalContext, @@ -1173,6 +1223,7 @@ impl AptosVM { // If txn args are not valid, we'd still consider the transaction as executed but // failed. This is primarily because it's unrecoverable at this point. self.validate_and_execute_entry_function( + resolver, session, gas_meter, traversal_context, @@ -1200,6 +1251,7 @@ impl AptosVM { txn_data: &'l TransactionMetadata, cleanup_args: Vec>, change_set_configs: &ChangeSetConfigs, + traversal_context: &mut TraversalContext, ) -> Result, VMStatus> { // Charge gas for write set before we do cleanup. This ensures we don't charge gas for // cleanup write set changes, which is consistent with outer-level success cleanup @@ -1219,6 +1271,7 @@ impl AptosVM { vec![], cleanup_args, &mut UnmeteredGasMeter, + traversal_context, ) .map_err(|e| e.into_vm_status()) })?; @@ -1232,6 +1285,7 @@ impl AptosVM { execution_error: VMStatus, txn_data: &'l TransactionMetadata, mut cleanup_args: Vec>, + traversal_context: &mut TraversalContext, ) -> Result, VMStatus> { // Start a fresh session for running cleanup that does not contain any changes from // the inner function call earlier (since it failed). @@ -1258,6 +1312,7 @@ impl AptosVM { vec![], cleanup_args, &mut UnmeteredGasMeter, + traversal_context, ) .map_err(|e| e.into_vm_status()) })?; @@ -1273,6 +1328,7 @@ impl AptosVM { exists: BTreeSet, senders: &[AccountAddress], new_published_modules_loaded: &mut bool, + traversal_context: &mut TraversalContext, ) -> VMResult<()> { let init_func_name = ident_str!("init_module"); for module in modules { @@ -1299,6 +1355,7 @@ impl AptosVM { vec![], args, gas_meter, + traversal_context, )?; } else { return Err(PartialVMError::new(StatusCode::CONSTRAINT_NOT_SATISFIED) @@ -1439,6 +1496,7 @@ impl AptosVM { exists, &[destination], new_published_modules_loaded, + traversal_context, ) } else { Ok(()) @@ -1551,6 +1609,7 @@ impl AptosVM { transaction: &SignedTransaction, transaction_data: &TransactionMetadata, log_context: &AdapterLogSchema, + traversal_context: &mut TraversalContext, ) -> Result<(), VMStatus> { // Check transaction format. if transaction.contains_duplicate_signers() { @@ -1560,14 +1619,24 @@ impl AptosVM { )); } - let authenticators = aptos_types::keyless::get_authenticators(transaction) + let keyless_authenticators = aptos_types::keyless::get_authenticators(transaction) .map_err(|_| VMStatus::error(StatusCode::INVALID_SIGNATURE, None))?; // If there are keyless TXN authenticators, validate them all. - if !authenticators.is_empty() { + if !keyless_authenticators.is_empty() { + // This should only happen if we incorrectly enable the feature without setting the VK. + // Or, if we spawn a network without initializing the VK in genesis. Either way, it must + // be handled here. + if self.pvk.is_none() { + // println!("[aptos-vm][groth16] PVK has not been set on-chain"); + return Err(invalid_signature!("Groth16 VK has not been set on-chain")); + } + keyless_validation::validate_authenticators( - &authenticators, + self.pvk.as_ref().unwrap(), + &keyless_authenticators, self.features(), + self.gas_feature_version, resolver, )?; } @@ -1581,6 +1650,7 @@ impl AptosVM { transaction.payload(), transaction_data, log_context, + traversal_context, ) } @@ -1596,6 +1666,7 @@ impl AptosVM { gas_meter: &mut impl AptosGasMeter, change_set_configs: &ChangeSetConfigs, new_published_modules_loaded: bool, + traversal_context: &mut TraversalContext, ) -> (VMStatus, VMOutput) { // Invalidate the loader cache in case there was a new module loaded from a module // publish request that failed. @@ -1614,6 +1685,7 @@ impl AptosVM { resolver, log_context, change_set_configs, + traversal_context, ) } @@ -1637,11 +1709,17 @@ impl AptosVM { &gas_meter.vm_gas_params().txn, &txn_data, txn.payload(), - ); + )?; txn_data.set_required_deposit(required_deposit); - self.validate_signed_transaction(session, resolver, txn, &txn_data, log_context) + self.validate_signed_transaction( + session, + resolver, + txn, + &txn_data, + log_context, + traversal_context, + ) })); - let storage_gas_params = unwrap_or_discard!(get_or_vm_startup_failure( &self.storage_gas_params, log_context @@ -1664,7 +1742,8 @@ impl AptosVM { user_session.execute(|session| create_account_if_does_not_exist( session, gas_meter, - txn.sender() + txn.sender(), + traversal_context, )) ); } @@ -1723,6 +1802,7 @@ impl AptosVM { gas_meter, change_set_configs, new_published_modules_loaded, + traversal_context, ) }) } @@ -1817,7 +1897,7 @@ impl AptosVM { Ok(change) }, WriteSetPayload::Script { script, execute_as } => { - let mut tmp_session = self.new_session(resolver, session_id); + let mut tmp_session = self.new_session(resolver, session_id, None); let senders = match txn_sender { None => vec![*execute_as], Some(sender) => vec![sender, *execute_as], @@ -1941,11 +2021,13 @@ impl AptosVM { }); let mut gas_meter = UnmeteredGasMeter; - let mut session = self.new_session(resolver, SessionId::block_meta(&block_metadata)); + let mut session = self.new_session(resolver, SessionId::block_meta(&block_metadata), None); let args = serialize_values( &block_metadata.get_prologue_move_args(account_config::reserved_vm_address()), ); + + let storage = TraversalStorage::new(); session .execute_function_bypass_visibility( &BLOCK_MODULE, @@ -1953,6 +2035,7 @@ impl AptosVM { vec![], args, &mut gas_meter, + &mut TraversalContext::new(&storage), ) .map(|_return_vals| ()) .or_else(|e| { @@ -1983,8 +2066,11 @@ impl AptosVM { }); let mut gas_meter = UnmeteredGasMeter; - let mut session = - self.new_session(resolver, SessionId::block_meta_ext(&block_metadata_ext)); + let mut session = self.new_session( + resolver, + SessionId::block_meta_ext(&block_metadata_ext), + None, + ); let block_metadata_with_randomness = match block_metadata_ext { BlockMetadataExt::V0(_) => unreachable!(), @@ -2021,6 +2107,8 @@ impl AptosVM { .as_move_value(), ]; + let storage = TraversalStorage::new(); + session .execute_function_bypass_visibility( &BLOCK_MODULE, @@ -2028,6 +2116,7 @@ impl AptosVM { vec![], serialize_values(&args), &mut gas_meter, + &mut TraversalContext::new(&storage), ) .map(|_return_vals| ()) .or_else(|e| { @@ -2071,7 +2160,7 @@ impl AptosVM { Err(e) => return ViewFunctionOutput::new(Err(anyhow::Error::msg(format!("{}", e))), 0), }; - let mut session = vm.new_session(&resolver, SessionId::Void); + let mut session = vm.new_session(&resolver, SessionId::Void, None); let execution_result = Self::execute_view_function_in_vm( &mut session, &vm, @@ -2115,6 +2204,8 @@ impl AptosVM { vm.features().is_enabled(FeatureFlag::STRUCT_CONSTRUCTORS), )?; + let storage = TraversalStorage::new(); + Ok(session .execute_function_bypass_visibility( &module_id, @@ -2122,6 +2213,7 @@ impl AptosVM { type_args, arguments, gas_meter, + &mut TraversalContext::new(&storage), ) .map_err(|err| anyhow!("Failed to execute function: {:?}", err))? .return_values @@ -2137,6 +2229,7 @@ impl AptosVM { payload: &TransactionPayload, txn_data: &TransactionMetadata, log_context: &AdapterLogSchema, + traversal_context: &mut TraversalContext, ) -> Result<(), VMStatus> { check_gas( get_or_vm_startup_failure(&self.gas_params, log_context)?, @@ -2149,13 +2242,23 @@ impl AptosVM { match payload { TransactionPayload::Script(_) | TransactionPayload::EntryFunction(_) => { - transaction_validation::run_script_prologue(session, txn_data, log_context) + transaction_validation::run_script_prologue( + session, + txn_data, + log_context, + traversal_context, + ) }, TransactionPayload::Multisig(multisig_payload) => { // Still run script prologue for multisig transaction to ensure the same tx // validations are still run for this multisig execution tx, which is submitted by // one of the owners. - transaction_validation::run_script_prologue(session, txn_data, log_context)?; + transaction_validation::run_script_prologue( + session, + txn_data, + log_context, + traversal_context, + )?; // Skip validation if this is part of tx simulation. // This allows simulating multisig txs without having to first create the multisig // tx. @@ -2165,6 +2268,7 @@ impl AptosVM { txn_data, multisig_payload, log_context, + traversal_context, ) } else { Ok(()) @@ -2312,38 +2416,38 @@ impl AptosVM { }) } + #[allow(clippy::manual_filter)] pub fn get_required_deposit( &self, session: &mut SessionExt, resolver: &impl AptosMoveResolver, - txn_gas_params: &TransactionGasParameters, + _txn_gas_params: &TransactionGasParameters, txn_metadata: &TransactionMetadata, payload: &TransactionPayload, - ) -> Option { + ) -> Result, VMStatus> { match payload { TransactionPayload::EntryFunction(entry_func) => { - if self.randomness_enabled - && has_randomness_attribute(resolver, session, entry_func).unwrap_or(false) - { - let max_execution_gas: Gas = txn_gas_params - .max_execution_gas - .to_unit_round_up_with_params(txn_gas_params); - let max_io_gas: Gas = txn_gas_params - .max_io_gas - .to_unit_round_up_with_params(txn_gas_params); - let cand_0 = txn_metadata.gas_unit_price * (max_execution_gas + max_io_gas) - + txn_gas_params.max_storage_fee; - let cand_1 = - txn_metadata.gas_unit_price * txn_gas_params.maximum_number_of_gas_units; - let required_fee_deposit = min(cand_0, cand_1); - Some(u64::from(required_fee_deposit)) + if let Some(gas_amount) = self.randomness_api_v0_required_deposit.gas_amount { + if has_randomness_attribute(resolver, session, entry_func).unwrap_or(false) { + if gas_amount != u64::from(txn_metadata.max_gas_amount) { + return Err(VMStatus::error( + StatusCode::REQUIRED_DEPOSIT_INCONSISTENT_WITH_TXN_MAX_GAS, + None, + )); + } + let octa_amount = + u64::from(txn_metadata.max_gas_amount * txn_metadata.gas_unit_price); + Ok(Some(octa_amount)) + } else { + Ok(None) + } } else { - None + Ok(None) } }, TransactionPayload::Script(_) | TransactionPayload::ModuleBundle(_) - | TransactionPayload::Multisig(_) => None, + | TransactionPayload::Multisig(_) => Ok(None), } } } @@ -2480,21 +2584,33 @@ impl VMValidator for AptosVM { let mut txn_data = TransactionMetadata::new(&txn); let resolver = self.as_move_resolver(&state_view); - let mut session = self.new_session(&resolver, SessionId::prologue_meta(&txn_data)); + let mut session = self.new_session( + &resolver, + SessionId::prologue_meta(&txn_data), + Some(txn_data.as_user_transaction_context()), + ); let required_deposit = if let Ok(gas_params) = &self.gas_params { - self.get_required_deposit( + let maybe_required_deposit = self.get_required_deposit( &mut session, &resolver, &gas_params.vm.txn, &txn_data, txn.payload(), - ) + ); + match maybe_required_deposit { + Ok(required_deposit) => required_deposit, + Err(vm_status) => { + return VMValidatorResult::error(vm_status.status_code()); + }, + } } else { return VMValidatorResult::error(StatusCode::GAS_PARAMS_MISSING); }; txn_data.set_required_deposit(required_deposit); + let storage = TraversalStorage::new(); + // Increment the counter for transactions verified. let (counter_label, result) = match self.validate_signed_transaction( &mut session, @@ -2502,6 +2618,7 @@ impl VMValidator for AptosVM { &txn, &txn_data, &log_context, + &mut TraversalContext::new(&storage), ) { Err(err) if err.status_code() != StatusCode::SEQUENCE_NUMBER_TOO_NEW => ( "failure", @@ -2563,6 +2680,7 @@ fn create_account_if_does_not_exist( session: &mut SessionExt, gas_meter: &mut impl GasMeter, account: AccountAddress, + traversal_context: &mut TraversalContext, ) -> VMResult<()> { session .execute_function_bypass_visibility( @@ -2571,6 +2689,7 @@ fn create_account_if_does_not_exist( vec![], serialize_values(&vec![MoveValue::Address(account)]), gas_meter, + traversal_context, ) .map(|_return_vals| ()) } diff --git a/aptos-move/aptos-vm/src/data_cache.rs b/aptos-move/aptos-vm/src/data_cache.rs index 59855d9c05449..44eb668a9efcc 100644 --- a/aptos-move/aptos-vm/src/data_cache.rs +++ b/aptos-move/aptos-vm/src/data_cache.rs @@ -17,7 +17,6 @@ use aptos_aggregator::{ }; use aptos_table_natives::{TableHandle, TableResolver}; use aptos_types::{ - access_path::AccessPath, delayed_fields::PanicError, on_chain_config::{ConfigStorage, Features, OnChainConfig}, state_store::{ @@ -124,10 +123,7 @@ impl<'e, E: ExecutorView> StorageAdapter<'e, E> { ) -> PartialVMResult<(Option, usize)> { let resource_group = get_resource_group_from_metadata(struct_tag, metadata); if let Some(resource_group) = resource_group { - let key = StateKey::access_path(AccessPath::resource_group_access_path( - *address, - resource_group.clone(), - )); + let key = StateKey::resource_group(address, &resource_group); let buf = self.resource_group_view .get_resource_from_group(&key, struct_tag, maybe_layout)?; @@ -142,7 +138,7 @@ impl<'e, E: ExecutorView> StorageAdapter<'e, E> { let buf_size = resource_size(&buf); Ok((buf, buf_size + group_size as usize)) } else { - let state_key = resource_state_key(*address, struct_tag.clone())?; + let state_key = resource_state_key(address, struct_tag)?; let buf = self .executor_view .get_resource_bytes(&state_key, maybe_layout)?; @@ -216,9 +212,8 @@ impl<'e, E: ExecutorView> ModuleResolver for StorageAdapter<'e, E> { } fn get_module(&self, module_id: &ModuleId) -> Result, Self::Error> { - let access_path = AccessPath::from(module_id); self.executor_view - .get_module_bytes(&StateKey::access_path(access_path)) + .get_module_bytes(&StateKey::module_id(module_id)) } } @@ -229,7 +224,7 @@ impl<'e, E: ExecutorView> TableResolver for StorageAdapter<'e, E> { key: &[u8], maybe_layout: Option<&MoveTypeLayout>, ) -> Result, PartialVMError> { - let state_key = StateKey::table_item((*handle).into(), key.to_vec()); + let state_key = StateKey::table_item(&(*handle).into(), key); self.executor_view .get_resource_bytes(&state_key, maybe_layout) } diff --git a/aptos-move/aptos-vm/src/gas.rs b/aptos-move/aptos-vm/src/gas.rs index 0c0ef735816b9..e1496a14523e5 100644 --- a/aptos-move/aptos-vm/src/gas.rs +++ b/aptos-move/aptos-vm/src/gas.rs @@ -2,9 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{move_vm_ext::AptosMoveResolver, transaction_metadata::TransactionMetadata}; -use aptos_gas_algebra::GasExpression; +use aptos_gas_algebra::{Gas, GasExpression, InternalGas}; use aptos_gas_schedule::{ - AptosGasParameters, FromOnChainGasSchedule, MiscGasParameters, NativeGasParameters, + gas_params::txn::KEYLESS_BASE_COST, AptosGasParameters, FromOnChainGasSchedule, + MiscGasParameters, NativeGasParameters, }; use aptos_logger::{enabled, Level}; use aptos_types::on_chain_config::{ @@ -186,17 +187,22 @@ pub(crate) fn check_gas( // The submitted transactions max gas units needs to be at least enough to cover the // intrinsic cost of the transaction as calculated against the size of the // underlying `RawTransaction`. + let keyless = if txn_metadata.is_keyless() { + KEYLESS_BASE_COST.evaluate(gas_feature_version, &gas_params.vm) + } else { + InternalGas::zero() + }; let intrinsic_gas = txn_gas_params .calculate_intrinsic_gas(raw_bytes_len) - .evaluate(gas_feature_version, &gas_params.vm) - .to_unit_round_up_with_params(txn_gas_params); + .evaluate(gas_feature_version, &gas_params.vm); + let total_rounded: Gas = (intrinsic_gas + keyless).to_unit_round_up_with_params(txn_gas_params); - if txn_metadata.max_gas_amount() < intrinsic_gas { + if txn_metadata.max_gas_amount() < total_rounded { speculative_warn!( log_context, format!( "[VM] Gas unit error; min {}, submitted {}", - intrinsic_gas, + total_rounded, txn_metadata.max_gas_amount() ), ); diff --git a/aptos-move/aptos-vm/src/keyless_validation.rs b/aptos-move/aptos-vm/src/keyless_validation.rs index 51d5626f23738..b23f53c6ad048 100644 --- a/aptos-move/aptos-vm/src/keyless_validation.rs +++ b/aptos-move/aptos-vm/src/keyless_validation.rs @@ -8,13 +8,15 @@ use aptos_types::{ invalid_signature, jwks::{jwk::JWK, PatchedJWKs}, keyless::{ - get_public_inputs_hash, Configuration, EphemeralCertificate, Groth16VerificationKey, - KeylessPublicKey, KeylessSignature, ZKP, + get_public_inputs_hash, Configuration, EphemeralCertificate, Groth16ProofAndStatement, + Groth16VerificationKey, KeylessPublicKey, KeylessSignature, ZKP, }, on_chain_config::{CurrentTimeMicroseconds, Features, OnChainConfig}, transaction::authenticator::{EphemeralPublicKey, EphemeralSignature}, vm_status::{StatusCode, VMStatus}, }; +use ark_bn254::Bn254; +use ark_groth16::PreparedVerifyingKey; use move_binary_format::errors::Location; use move_core_types::{language_storage::CORE_CODE_ADDRESS, move_resource::MoveStructType}; use serde::Deserialize; @@ -66,7 +68,7 @@ fn get_jwks_onchain(resolver: &impl AptosMoveResolver) -> anyhow::Result anyhow::Result { get_resource_on_chain::(resolver) @@ -119,25 +121,27 @@ fn get_jwk_for_authenticator( /// Ensures that **all** keyless authenticators in the transaction are valid. pub(crate) fn validate_authenticators( + pvk: &PreparedVerifyingKey, authenticators: &Vec<(KeylessPublicKey, KeylessSignature)>, features: &Features, + gas_feature_version: u64, resolver: &impl AptosMoveResolver, ) -> Result<(), VMStatus> { for (_, sig) in authenticators { // Feature-gating for keyless TXNs (whether ZK or ZKless, whether passkey-based or not) if matches!(sig.cert, EphemeralCertificate::ZeroKnowledgeSig { .. }) - && !features.is_zk_keyless_enabled() + && !(features.is_zk_keyless_enabled() && gas_feature_version >= 17) { return Err(VMStatus::error(StatusCode::FEATURE_UNDER_GATING, None)); } if matches!(sig.cert, EphemeralCertificate::OpenIdSig { .. }) - && !features.is_zkless_keyless_enabled() + && !(features.is_zkless_keyless_enabled() && gas_feature_version >= 17) { return Err(VMStatus::error(StatusCode::FEATURE_UNDER_GATING, None)); } if matches!(sig.ephemeral_signature, EphemeralSignature::WebAuthn { .. }) - && !features.is_keyless_with_passkeys_enabled() + && !(features.is_keyless_with_passkeys_enabled() && gas_feature_version >= 17) { return Err(VMStatus::error(StatusCode::FEATURE_UNDER_GATING, None)); } @@ -145,25 +149,30 @@ pub(crate) fn validate_authenticators( let config = &get_configs_onchain(resolver)?; if authenticators.len() > config.max_signatures_per_txn as usize { + // println!("[aptos-vm][groth16] Too many keyless authenticators"); return Err(invalid_signature!("Too many keyless authenticators")); } let onchain_timestamp_obj = get_current_time_onchain(resolver)?; // Check the expiry timestamp on all authenticators first to fail fast for (_, sig) in authenticators { - sig.verify_expiry(&onchain_timestamp_obj) - .map_err(|_| invalid_signature!("The ephemeral keypair has expired"))?; + sig.verify_expiry(&onchain_timestamp_obj).map_err(|_| { + // println!("[aptos-vm][groth16] ZKP expired"); + + invalid_signature!("The ephemeral keypair has expired") + })?; } let patched_jwks = get_jwks_onchain(resolver)?; - let pvk = &get_groth16_vk_onchain(resolver)? - .try_into() - .map_err(|_| invalid_signature!("Could not deserialize on-chain Groth16 VK"))?; let training_wheels_pk = match &config.training_wheels_pubkey { None => None, + // This takes ~4.4 microseconds, so we are not too concerned about speed here. + // (Run `cargo bench -- ed25519/pk_deserialize` in `crates/aptos-crypto`.) Some(bytes) => Some(EphemeralPublicKey::ed25519( Ed25519PublicKey::try_from(bytes.as_slice()).map_err(|_| { + // println!("[aptos-vm][groth16] On chain TW PK is invalid"); + invalid_signature!("The training wheels PK set on chain is not a valid PK") })?, )), @@ -176,6 +185,7 @@ pub(crate) fn validate_authenticators( EphemeralCertificate::ZeroKnowledgeSig(zksig) => match jwk { JWK::RSA(rsa_jwk) => { if zksig.exp_horizon_secs > config.max_exp_horizon_secs { + // println!("[aptos-vm][groth16] Expiration horizon is too long"); return Err(invalid_signature!("The expiration horizon is too long")); } @@ -185,30 +195,62 @@ pub(crate) fn validate_authenticators( config.is_allowed_override_aud(zksig.override_aud_val.as_ref().unwrap())?; } - match zksig.proof { - ZKP::Groth16(_) => { - let public_inputs_hash = - get_public_inputs_hash(sig, pk, &rsa_jwk, config).map_err( - |_| invalid_signature!("Could not compute public inputs hash"), - )?; + match &zksig.proof { + ZKP::Groth16(groth16proof) => { + // let start = std::time::Instant::now(); + let public_inputs_hash = get_public_inputs_hash( + sig, pk, &rsa_jwk, config, + ) + .map_err(|_| { + // println!("[aptos-vm][groth16] PIH computation failed"); + invalid_signature!("Could not compute public inputs hash") + })?; + // println!("Public inputs hash time: {:?}", start.elapsed()); + + let groth16_and_stmt = + Groth16ProofAndStatement::new(*groth16proof, public_inputs_hash); // The training wheels signature is only checked if a training wheels PK is set on chain if training_wheels_pk.is_some() { - zksig - .verify_training_wheels_sig( - training_wheels_pk.as_ref().unwrap(), - &public_inputs_hash, - ) - .map_err(|_| { - invalid_signature!( - "Could not verify training wheels signature" - ) - })?; + match &zksig.training_wheels_signature { + Some(training_wheels_sig) => { + training_wheels_sig + .verify( + &groth16_and_stmt, + training_wheels_pk.as_ref().unwrap(), + ) + .map_err(|_| { + // println!("[aptos-vm][groth16] TW sig verification failed"); + invalid_signature!( + "Could not verify training wheels signature" + ) + })?; + }, + None => { + // println!("[aptos-vm][groth16] Expected TW sig to be set"); + return Err(invalid_signature!( + "Training wheels signature expected but it is missing" + )); + }, + } } - zksig - .verify_groth16_proof(public_inputs_hash, pvk) - .map_err(|_| invalid_signature!("Proof verification failed"))?; + let result = zksig.verify_groth16_proof(public_inputs_hash, pvk); + + result.map_err(|_| { + // println!("[aptos-vm][groth16] ZKP verification failed"); + // println!("[aptos-vm][groth16] PIH: {}", public_inputs_hash); + // match zksig.proof { + // ZKP::Groth16(proof) => { + // println!("[aptos-vm][groth16] ZKP: {}", proof.hash()); + // }, + // } + // println!( + // "[aptos-vm][groth16] PVK: {}", + // Groth16VerificationKey::from(pvk).hash() + // ); + invalid_signature!("Proof verification failed") + })?; }, } }, diff --git a/aptos-move/aptos-vm/src/lib.rs b/aptos-move/aptos-vm/src/lib.rs index 7709bf9e21e6f..d5f3dd442cefb 100644 --- a/aptos-move/aptos-vm/src/lib.rs +++ b/aptos-move/aptos-vm/src/lib.rs @@ -109,7 +109,10 @@ pub mod aptos_vm; pub mod block_executor; mod errors; pub mod gas; +#[cfg(not(feature = "testing"))] mod keyless_validation; +#[cfg(feature = "testing")] +pub mod keyless_validation; pub mod move_vm_ext; pub mod natives; pub mod sharded_block_executor; diff --git a/aptos-move/aptos-vm/src/move_vm_ext/mod.rs b/aptos-move/aptos-vm/src/move_vm_ext/mod.rs index cb4e6596eade9..342999328bf4c 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/mod.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/mod.rs @@ -14,7 +14,8 @@ pub use crate::move_vm_ext::{ session::SessionExt, vm::{get_max_binary_format_version, get_max_identifier_size, verifier_config, MoveVmExt}, }; -use aptos_types::{access_path::AccessPath, state_store::state_key::StateKey}; +use aptos_types::state_store::state_key::StateKey; +pub use aptos_types::transaction::user_transaction_context::UserTransactionContext; use move_binary_format::errors::{PartialVMError, PartialVMResult}; use move_core_types::{ account_address::AccountAddress, language_storage::StructTag, vm_status::StatusCode, @@ -22,12 +23,11 @@ use move_core_types::{ pub use session::session_id::SessionId; pub(crate) fn resource_state_key( - address: AccountAddress, - tag: StructTag, + address: &AccountAddress, + tag: &StructTag, ) -> PartialVMResult { - let access_path = AccessPath::resource_access_path(address, tag).map_err(|e| { + StateKey::resource(address, tag).map_err(|e| { PartialVMError::new(StatusCode::VALUE_SERIALIZATION_ERROR) .with_message(format!("Failed to serialize struct tag: {}", e)) - })?; - Ok(StateKey::access_path(access_path)) + }) } diff --git a/aptos-move/aptos-vm/src/move_vm_ext/session/mod.rs b/aptos-move/aptos-vm/src/move_vm_ext/session/mod.rs index c873a7f1eca3a..fd146c0d872d1 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/session/mod.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/session/mod.rs @@ -11,15 +11,13 @@ use aptos_framework::natives::{ event::NativeEventContext, }; use aptos_table_natives::{NativeTableContext, TableChangeSet}; -use aptos_types::{ - access_path::AccessPath, contract_event::ContractEvent, state_store::state_key::StateKey, -}; +use aptos_types::{contract_event::ContractEvent, state_store::state_key::StateKey}; use aptos_vm_types::{change_set::VMChangeSet, storage::change_set_configs::ChangeSetConfigs}; use bytes::Bytes; use move_binary_format::errors::{Location, PartialVMError, PartialVMResult, VMResult}; use move_core_types::{ effects::{AccountChanges, Changes, Op as MoveStorageOp}, - language_storage::{ModuleId, StructTag}, + language_storage::StructTag, value::MoveTypeLayout, vm_status::StatusCode, }; @@ -265,10 +263,7 @@ impl<'r, 'l> SessionExt<'r, 'l> { .map_err(|_| common_error())?; for (resource_group_tag, resources) in resource_groups { - let state_key = StateKey::access_path(AccessPath::resource_group_access_path( - addr, - resource_group_tag, - )); + let state_key = StateKey::resource_group(&addr, &resource_group_tag); match &mut resource_group_change_set { ResourceGroupChangeSet::V0(v0_changes) => { let source_data = maybe_resource_group_cache @@ -321,7 +316,7 @@ impl<'r, 'l> SessionExt<'r, 'l> { for (addr, account_changeset) in change_set.into_inner() { let (modules, resources) = account_changeset.into_inner(); for (struct_tag, blob_and_layout_op) in resources { - let state_key = resource_state_key(addr, struct_tag)?; + let state_key = resource_state_key(&addr, &struct_tag)?; let op = woc.convert_resource( &state_key, blob_and_layout_op, @@ -332,7 +327,7 @@ impl<'r, 'l> SessionExt<'r, 'l> { } for (name, blob_op) in modules { - let state_key = StateKey::access_path(AccessPath::from(&ModuleId::new(addr, name))); + let state_key = StateKey::module(&addr, &name); let op = woc.convert_module(&state_key, blob_op, false)?; module_write_set.insert(state_key, op); } @@ -355,7 +350,7 @@ impl<'r, 'l> SessionExt<'r, 'l> { for (handle, change) in table_change_set.changes { for (key, value_op) in change.entries { - let state_key = StateKey::table_item(handle.into(), key); + let state_key = StateKey::table_item(&handle.into(), &key); let op = woc.convert_resource(&state_key, value_op, false)?; resource_write_set.insert(state_key, op); } diff --git a/aptos-move/aptos-vm/src/move_vm_ext/session/respawned_session.rs b/aptos-move/aptos-vm/src/move_vm_ext/session/respawned_session.rs index ebd655dde9858..d8853dd0a9df6 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/session/respawned_session.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/session/respawned_session.rs @@ -9,6 +9,7 @@ use crate::{ }, AptosVM, }; +use aptos_types::transaction::user_transaction_context::UserTransactionContext; use aptos_vm_types::{change_set::VMChangeSet, storage::change_set_configs::ChangeSetConfigs}; use move_core_types::vm_status::{err_msg, StatusCode, VMStatus}; @@ -38,6 +39,7 @@ impl<'r, 'l> RespawnedSession<'r, 'l> { session_id: SessionId, base: &'r impl AptosMoveResolver, previous_session_change_set: VMChangeSet, + user_transaction_context_opt: Option, ) -> Result { let executor_view = ExecutorViewWithChangeSet::new( base.as_executor_view(), @@ -48,7 +50,9 @@ impl<'r, 'l> RespawnedSession<'r, 'l> { Ok(RespawnedSessionBuilder { executor_view, resolver_builder: |executor_view| vm.as_move_resolver_with_group_view(executor_view), - session_builder: |resolver| Some(vm.new_session(resolver, session_id)), + session_builder: |resolver| { + Some(vm.new_session(resolver, session_id, user_transaction_context_opt)) + }, } .build()) } diff --git a/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/abort_hook.rs b/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/abort_hook.rs index 7c8554adc3054..05581040ef17e 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/abort_hook.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/abort_hook.rs @@ -26,7 +26,13 @@ impl<'r, 'l> AbortHookSession<'r, 'l> { ) -> Result { let session_id = SessionId::run_on_abort(txn_meta); - let session = RespawnedSession::spawn(vm, session_id, resolver, prologue_change_set)?; + let session = RespawnedSession::spawn( + vm, + session_id, + resolver, + prologue_change_set, + Some(txn_meta.as_user_transaction_context()), + )?; Ok(Self { session }) } diff --git a/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/epilogue.rs b/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/epilogue.rs index d39e43a58e42f..b6a217eb6d46d 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/epilogue.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/epilogue.rs @@ -28,8 +28,13 @@ impl<'r, 'l> EpilogueSession<'r, 'l> { storage_refund: Fee, ) -> Result { let session_id = SessionId::epilogue_meta(txn_meta); - let session = - RespawnedSession::spawn(vm, session_id, resolver, previous_session_change_set)?; + let session = RespawnedSession::spawn( + vm, + session_id, + resolver, + previous_session_change_set, + Some(txn_meta.as_user_transaction_context()), + )?; Ok(Self { session, diff --git a/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/prologue.rs b/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/prologue.rs index 673466368a3e2..0a3b9467173c1 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/prologue.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/prologue.rs @@ -29,7 +29,13 @@ impl<'r, 'l> PrologueSession<'r, 'l> { resolver: &'r impl AptosMoveResolver, ) -> Result { let session_id = SessionId::prologue_meta(txn_meta); - let session = RespawnedSession::spawn(vm, session_id, resolver, VMChangeSet::empty())?; + let session = RespawnedSession::spawn( + vm, + session_id, + resolver, + VMChangeSet::empty(), + Some(txn_meta.as_user_transaction_context()), + )?; Ok(Self { session }) } diff --git a/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/user.rs b/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/user.rs index e92911a19f6fc..edccd9bde9ed0 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/user.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/session/user_transaction_sessions/user.rs @@ -26,7 +26,13 @@ impl<'r, 'l> UserSession<'r, 'l> { ) -> Result { let session_id = SessionId::txn_meta(txn_meta); - let session = RespawnedSession::spawn(vm, session_id, resolver, prologue_change_set)?; + let session = RespawnedSession::spawn( + vm, + session_id, + resolver, + prologue_change_set, + Some(txn_meta.as_user_transaction_context()), + )?; Ok(Self { session }) } diff --git a/aptos-move/aptos-vm/src/move_vm_ext/session/view_with_change_set.rs b/aptos-move/aptos-vm/src/move_vm_ext/session/view_with_change_set.rs index e5e2069724ba1..0f3f8b99faa4b 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/session/view_with_change_set.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/session/view_with_change_set.rs @@ -364,7 +364,7 @@ mod test { } fn key(s: impl ToString) -> StateKey { - StateKey::raw(s.to_string().into_bytes()) + StateKey::raw(s.to_string().as_bytes()) } fn write(v: u128) -> WriteOp { diff --git a/aptos-move/aptos-vm/src/move_vm_ext/vm.rs b/aptos-move/aptos-vm/src/move_vm_ext/vm.rs index eb082b2bf3caf..768a9cc346e9b 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/vm.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/vm.rs @@ -7,6 +7,7 @@ use aptos_framework::natives::{ code::NativeCodeContext, cryptography::{algebra::AlgebraContext, ristretto255_point::NativeRistrettoPointContext}, event::NativeEventContext, + object::NativeObjectContext, randomness::RandomnessContext, state_storage::NativeStateStorageContext, transaction_context::NativeTransactionContext, @@ -18,6 +19,7 @@ use aptos_table_natives::NativeTableContext; use aptos_types::{ chain_id::ChainId, on_chain_config::{FeatureFlag, Features, TimedFeatureFlag, TimedFeatures}, + transaction::user_transaction_context::UserTransactionContext, }; use move_binary_format::{ deserializer::DeserializerConfig, @@ -196,6 +198,7 @@ impl MoveVmExt { &self, resolver: &'r S, session_id: SessionId, + user_transaction_context_opt: Option, ) -> SessionExt<'r, '_> { let mut extensions = NativeContextExtensions::default(); let txn_hash: [u8; 32] = session_id @@ -213,10 +216,12 @@ impl MoveVmExt { txn_hash.to_vec(), session_id.into_script_hash(), self.chain_id, + user_transaction_context_opt, )); extensions.add(NativeCodeContext::default()); extensions.add(NativeStateStorageContext::new(resolver)); extensions.add(NativeEventContext::default()); + extensions.add(NativeObjectContext::default()); // The VM code loader has bugs around module upgrade. After a module upgrade, the internal // cache needs to be flushed to work around those bugs. diff --git a/aptos-move/aptos-vm/src/move_vm_ext/warm_vm_cache.rs b/aptos-move/aptos-vm/src/move_vm_ext/warm_vm_cache.rs index 76130501eadb5..3d6736999849b 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/warm_vm_cache.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/warm_vm_cache.rs @@ -137,7 +137,13 @@ impl WarmVmId { fn core_packages_id_bytes(resolver: &impl AptosMoveResolver) -> VMResult> { let bytes = { let _timer = TIMER.timer_with(&["fetch_pkgreg"]); - resolver.fetch_config_bytes(&StateKey::on_chain_config::()) + resolver.fetch_config_bytes(&StateKey::on_chain_config::().map_err( + |err| { + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + .with_message(format!("failed to create StateKey: {}", err)) + .finish(Location::Undefined) + }, + )?) }; let core_package_registry = { diff --git a/aptos-move/aptos-vm/src/move_vm_ext/write_op_converter.rs b/aptos-move/aptos-vm/src/move_vm_ext/write_op_converter.rs index 54755914d2fa8..71089741d61d4 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/write_op_converter.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/write_op_converter.rs @@ -422,7 +422,7 @@ mod tests { (mock_tag_2(), vec![3, 3, 3].into()), ]); let metadata = raw_metadata(100); - let key = StateKey::raw(vec![0]); + let key = StateKey::raw(&[0]); let data = BTreeMap::from([( key.clone(), @@ -478,7 +478,7 @@ mod tests { (mock_tag_1(), vec![2, 2].into()), ]); let metadata = raw_metadata(100); - let key = StateKey::raw(vec![0]); + let key = StateKey::raw(&[0]); let data = BTreeMap::from([( key.clone(), @@ -520,7 +520,7 @@ mod tests { // TODO[agg_v2](test): Layout hardcoded to None. Test with layout = Some(..) let group_changes = BTreeMap::from([(mock_tag_1(), MoveStorageOp::New((vec![2, 2].into(), None)))]); - let key = StateKey::raw(vec![0]); + let key = StateKey::raw(&[0]); let converter = WriteOpConverter::new(&resolver, true); let group_write = converter .convert_resource_group_v1(&key, group_changes) @@ -545,7 +545,7 @@ mod tests { (mock_tag_1(), vec![2, 2].into()), ]); let metadata = raw_metadata(100); - let key = StateKey::raw(vec![0]); + let key = StateKey::raw(&[0]); let data = BTreeMap::from([( key.clone(), diff --git a/aptos-move/aptos-vm/src/natives.rs b/aptos-move/aptos-vm/src/natives.rs index 2f14254876634..63ec675443b88 100644 --- a/aptos-move/aptos-vm/src/natives.rs +++ b/aptos-move/aptos-vm/src/natives.rs @@ -223,6 +223,7 @@ pub fn configure_for_unit_test() { #[cfg(feature = "testing")] fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) { + use aptos_framework::natives::object::NativeObjectContext; use aptos_table_natives::NativeTableContext; exts.add(NativeTableContext::new([0u8; 32], &*DUMMY_RESOLVER)); @@ -231,6 +232,7 @@ fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) { vec![1], vec![1], ChainId::test().id(), + None, )); exts.add(NativeAggregatorContext::new( [0; 32], @@ -240,6 +242,7 @@ fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) { exts.add(NativeRistrettoPointContext::new()); exts.add(AlgebraContext::new()); exts.add(NativeEventContext::default()); + exts.add(NativeObjectContext::default()); let mut randomness_ctx = RandomnessContext::new(); randomness_ctx.mark_unbiasable(); diff --git a/aptos-move/aptos-vm/src/sharded_block_executor/cross_shard_state_view.rs b/aptos-move/aptos-vm/src/sharded_block_executor/cross_shard_state_view.rs index b60bfb65d3e3d..dfc7e6342641a 100644 --- a/aptos-move/aptos-vm/src/sharded_block_executor/cross_shard_state_view.rs +++ b/aptos-move/aptos-vm/src/sharded_block_executor/cross_shard_state_view.rs @@ -106,7 +106,7 @@ mod tests { #[test] fn test_cross_shard_state_view_get_state_value() { - let state_key = StateKey::raw("key1".as_bytes().to_owned()); + let state_key = StateKey::raw(b"key1"); let state_value = StateValue::from("value1".as_bytes().to_owned()); let state_value_clone = state_value.clone(); let state_key_clone = state_key.clone(); diff --git a/aptos-move/aptos-vm/src/testing.rs b/aptos-move/aptos-vm/src/testing.rs index 205ec3c0b822d..563bbae2b0017 100644 --- a/aptos-move/aptos-vm/src/testing.rs +++ b/aptos-move/aptos-vm/src/testing.rs @@ -71,6 +71,8 @@ impl AptosVM { state_view: &impl StateView, gas_meter_balance: u64, ) -> (VMStatus, VMOutput) { + use move_vm_runtime::module_traversal::{TraversalContext, TraversalStorage}; + let txn_data = TransactionMetadata::new(txn); let log_context = AdapterLogSchema::new(state_view.id(), 0); @@ -82,6 +84,7 @@ impl AptosVM { .change_set_configs; let resolver = state_view.as_move_resolver(); + let storage = TraversalStorage::new(); self.failed_transaction_cleanup( VMChangeSet::empty(), error_vm_status, @@ -90,6 +93,7 @@ impl AptosVM { &resolver, &log_context, change_set_configs, + &mut TraversalContext::new(&storage), ) } } diff --git a/aptos-move/aptos-vm/src/transaction_metadata.rs b/aptos-move/aptos-vm/src/transaction_metadata.rs index e6533b74607a1..41a3501b46b56 100644 --- a/aptos-move/aptos-vm/src/transaction_metadata.rs +++ b/aptos-move/aptos-vm/src/transaction_metadata.rs @@ -7,7 +7,10 @@ use aptos_gas_algebra::{FeePerGasUnit, Gas, NumBytes}; use aptos_types::{ account_address::AccountAddress, chain_id::ChainId, - transaction::{SignedTransaction, TransactionPayload}, + transaction::{ + user_transaction_context::UserTransactionContext, EntryFunction, Multisig, + SignedTransaction, TransactionPayload, + }, }; pub struct TransactionMetadata { @@ -26,6 +29,9 @@ pub struct TransactionMetadata { pub script_hash: Vec, pub script_size: NumBytes, pub required_deposit: Option, + pub is_keyless: bool, + pub entry_function_payload: Option, + pub multisig_payload: Option, } impl TransactionMetadata { @@ -65,6 +71,17 @@ impl TransactionMetadata { _ => NumBytes::zero(), }, required_deposit: None, + is_keyless: aptos_types::keyless::get_authenticators(txn) + .map(|res| !res.is_empty()) + .unwrap_or(false), + entry_function_payload: match txn.payload() { + TransactionPayload::EntryFunction(e) => Some(e.clone()), + _ => None, + }, + multisig_payload: match txn.payload() { + TransactionPayload::Multisig(m) => Some(m.clone()), + _ => None, + }, } } @@ -125,4 +142,31 @@ impl TransactionMetadata { pub fn set_required_deposit(&mut self, required_deposit: Option) { self.required_deposit = required_deposit; } + + pub fn is_keyless(&self) -> bool { + self.is_keyless + } + + pub fn entry_function_payload(&self) -> Option { + self.entry_function_payload.clone() + } + + pub fn multisig_payload(&self) -> Option { + self.multisig_payload.clone() + } + + pub fn as_user_transaction_context(&self) -> UserTransactionContext { + UserTransactionContext::new( + self.sender, + self.secondary_signers.clone(), + self.fee_payer.unwrap_or(self.sender), + self.max_gas_amount.into(), + self.gas_unit_price.into(), + self.chain_id.id(), + self.entry_function_payload() + .map(|entry_func| entry_func.as_entry_function_payload()), + self.multisig_payload() + .map(|multisig| multisig.as_multisig_payload()), + ) + } } diff --git a/aptos-move/aptos-vm/src/transaction_validation.rs b/aptos-move/aptos-vm/src/transaction_validation.rs index ea306c9dbffc2..a45a45d757087 100644 --- a/aptos-move/aptos-vm/src/transaction_validation.rs +++ b/aptos-move/aptos-vm/src/transaction_validation.rs @@ -27,7 +27,7 @@ use move_core_types::{ value::{serialize_values, MoveValue}, vm_status::{AbortLocation, StatusCode, VMStatus}, }; -use move_vm_runtime::logging::expect_no_verification_errors; +use move_vm_runtime::{logging::expect_no_verification_errors, module_traversal::TraversalContext}; use move_vm_types::gas::UnmeteredGasMeter; use once_cell::sync::Lazy; @@ -88,6 +88,7 @@ pub(crate) fn run_script_prologue( session: &mut SessionExt, txn_data: &TransactionMetadata, log_context: &AdapterLogSchema, + traversal_context: &mut TraversalContext, ) -> Result<(), VMStatus> { let txn_sequence_number = txn_data.sequence_number(); let txn_authentication_key = txn_data.authentication_key().to_vec(); @@ -171,6 +172,7 @@ pub(crate) fn run_script_prologue( vec![], serialize_values(&args), &mut gas_meter, + traversal_context, ) .map(|_return_vals| ()) .map_err(expect_no_verification_errors) @@ -187,6 +189,7 @@ pub(crate) fn run_multisig_prologue( txn_data: &TransactionMetadata, payload: &Multisig, log_context: &AdapterLogSchema, + traversal_context: &mut TraversalContext, ) -> Result<(), VMStatus> { let unreachable_error = VMStatus::error(StatusCode::UNREACHABLE, None); let provided_payload = if let Some(payload) = &payload.transaction_payload { @@ -207,6 +210,7 @@ pub(crate) fn run_multisig_prologue( MoveValue::vector_u8(provided_payload), ]), &mut UnmeteredGasMeter, + traversal_context, ) .map(|_return_vals| ()) .map_err(expect_no_verification_errors) @@ -219,6 +223,7 @@ fn run_epilogue( fee_statement: FeeStatement, txn_data: &TransactionMetadata, features: &Features, + traversal_context: &mut TraversalContext, ) -> VMResult<()> { let txn_gas_price = txn_data.gas_unit_price(); let txn_max_gas_units = txn_data.max_gas_amount(); @@ -254,6 +259,7 @@ fn run_epilogue( vec![], serialize_values(&args), &mut UnmeteredGasMeter, + traversal_context, ) } else { // Regular tx, run the normal epilogue @@ -281,6 +287,7 @@ fn run_epilogue( vec![], serialize_values(&args), &mut UnmeteredGasMeter, + traversal_context, ) } .map(|_return_vals| ()) @@ -288,7 +295,7 @@ fn run_epilogue( // Emit the FeeStatement event if features.is_emit_fee_statement_enabled() { - emit_fee_statement(session, fee_statement)?; + emit_fee_statement(session, fee_statement, traversal_context)?; } maybe_raise_injected_error(InjectedError::EndOfRunEpilogue)?; @@ -296,7 +303,11 @@ fn run_epilogue( Ok(()) } -fn emit_fee_statement(session: &mut SessionExt, fee_statement: FeeStatement) -> VMResult<()> { +fn emit_fee_statement( + session: &mut SessionExt, + fee_statement: FeeStatement, + traversal_context: &mut TraversalContext, +) -> VMResult<()> { session .execute_function_bypass_visibility( &TRANSACTION_FEE_MODULE, @@ -304,6 +315,7 @@ fn emit_fee_statement(session: &mut SessionExt, fee_statement: FeeStatement) -> vec![], vec![bcs::to_bytes(&fee_statement).expect("Failed to serialize fee statement")], &mut UnmeteredGasMeter, + traversal_context, ) .map(|_return_vals| ()) } @@ -317,6 +329,7 @@ pub(crate) fn run_success_epilogue( features: &Features, txn_data: &TransactionMetadata, log_context: &AdapterLogSchema, + traversal_context: &mut TraversalContext, ) -> Result<(), VMStatus> { fail_point!("move_adapter::run_success_epilogue", |_| { Err(VMStatus::error( @@ -325,8 +338,15 @@ pub(crate) fn run_success_epilogue( )) }); - run_epilogue(session, gas_remaining, fee_statement, txn_data, features) - .or_else(|err| convert_epilogue_error(err, log_context)) + run_epilogue( + session, + gas_remaining, + fee_statement, + txn_data, + features, + traversal_context, + ) + .or_else(|err| convert_epilogue_error(err, log_context)) } /// Run the failure epilogue of a transaction by calling into `USER_EPILOGUE_NAME` function @@ -338,8 +358,17 @@ pub(crate) fn run_failure_epilogue( features: &Features, txn_data: &TransactionMetadata, log_context: &AdapterLogSchema, + traversal_context: &mut TraversalContext, ) -> Result<(), VMStatus> { - run_epilogue(session, gas_remaining, fee_statement, txn_data, features).or_else(|e| { + run_epilogue( + session, + gas_remaining, + fee_statement, + txn_data, + features, + traversal_context, + ) + .or_else(|e| { expect_only_successful_execution( e, APTOS_TRANSACTION_VALIDATION.user_epilogue_name.as_str(), diff --git a/aptos-move/aptos-vm/src/validator_txns/dkg.rs b/aptos-move/aptos-vm/src/validator_txns/dkg.rs index d843366786909..dd5f77dd174ff 100644 --- a/aptos-move/aptos-vm/src/validator_txns/dkg.rs +++ b/aptos-move/aptos-vm/src/validator_txns/dkg.rs @@ -26,6 +26,7 @@ use move_core_types::{ value::{serialize_values, MoveValue}, vm_status::{AbortLocation, StatusCode, VMStatus}, }; +use move_vm_runtime::module_traversal::{TraversalContext, TraversalStorage}; use move_vm_types::gas::UnmeteredGasMeter; #[derive(Debug)] @@ -99,12 +100,13 @@ impl AptosVM { // All check passed, invoke VM to publish DKG result on chain. let mut gas_meter = UnmeteredGasMeter; - let mut session = self.new_session(resolver, session_id); + let mut session = self.new_session(resolver, session_id, None); let args = vec![ MoveValue::Signer(AccountAddress::ONE), dkg_node.transcript_bytes.as_move_value(), ]; + let module_storage = TraversalStorage::new(); session .execute_function_bypass_visibility( &RECONFIGURATION_WITH_DKG_MODULE, @@ -112,6 +114,7 @@ impl AptosVM { vec![], serialize_values(&args), &mut gas_meter, + &mut TraversalContext::new(&module_storage), ) .map_err(|e| { expect_only_successful_execution(e, FINISH_WITH_DKG_RESULT.as_str(), log_context) diff --git a/aptos-move/aptos-vm/src/validator_txns/jwk.rs b/aptos-move/aptos-vm/src/validator_txns/jwk.rs index 64bda638acb7d..9b994e911d723 100644 --- a/aptos-move/aptos-vm/src/validator_txns/jwk.rs +++ b/aptos-move/aptos-vm/src/validator_txns/jwk.rs @@ -32,6 +32,7 @@ use move_core_types::{ value::{serialize_values, MoveValue}, vm_status::{AbortLocation, StatusCode, VMStatus}, }; +use move_vm_runtime::module_traversal::{TraversalContext, TraversalStorage}; use move_vm_types::gas::UnmeteredGasMeter; use std::collections::HashMap; @@ -129,12 +130,13 @@ impl AptosVM { // All verification passed. Apply the `observed`. let mut gas_meter = UnmeteredGasMeter; - let mut session = self.new_session(resolver, session_id); + let mut session = self.new_session(resolver, session_id, None); let args = vec![ MoveValue::Signer(AccountAddress::ONE), vec![observed].as_move_value(), ]; + let module_storage = TraversalStorage::new(); session .execute_function_bypass_visibility( &JWKS_MODULE, @@ -142,6 +144,7 @@ impl AptosVM { vec![], serialize_values(&args), &mut gas_meter, + &mut TraversalContext::new(&module_storage), ) .map_err(|e| { expect_only_successful_execution(e, UPSERT_INTO_OBSERVED_JWKS.as_str(), log_context) diff --git a/aptos-move/aptos-vm/src/verifier/transaction_arg_validation.rs b/aptos-move/aptos-vm/src/verifier/transaction_arg_validation.rs index e99afec7104d5..36ba34b8611ea 100644 --- a/aptos-move/aptos-vm/src/verifier/transaction_arg_validation.rs +++ b/aptos-move/aptos-vm/src/verifier/transaction_arg_validation.rs @@ -20,7 +20,10 @@ use move_core_types::{ value::MoveValue, vm_status::StatusCode, }; -use move_vm_runtime::session::LoadedFunctionInstantiation; +use move_vm_runtime::{ + module_traversal::{TraversalContext, TraversalStorage}, + session::LoadedFunctionInstantiation, +}; use move_vm_types::{ gas::{GasMeter, UnmeteredGasMeter}, loaded_data::runtime_types::Type, @@ -443,8 +446,14 @@ fn validate_and_construct( )?; args.push(arg); } - let serialized_result = - session.execute_instantiated_function(function, instantiation, args, gas_meter)?; + let storage = TraversalStorage::new(); + let serialized_result = session.execute_instantiated_function( + function, + instantiation, + args, + gas_meter, + &mut TraversalContext::new(&storage), + )?; let mut ret_vals = serialized_result.return_values; // We know ret_vals.len() == 1 let deserialize_error = VMStatus::error( diff --git a/aptos-move/e2e-benchmark/src/main.rs b/aptos-move/e2e-benchmark/src/main.rs index dd05848e3f02d..c9288165175f2 100644 --- a/aptos-move/e2e-benchmark/src/main.rs +++ b/aptos-move/e2e-benchmark/src/main.rs @@ -101,7 +101,7 @@ fn main() { }), // This is a cheap bcs (serializing vec), so not representative of what BCS native call should cost. // (, EntryPoints::Loop { loop_count: Some(1000), loop_type: LoopType::BCS { len: 1024 }}), - (117, EntryPoints::CreateObjects { + (135, EntryPoints::CreateObjects { num_objects: 10, object_payload_size: 0, }), @@ -109,7 +109,7 @@ fn main() { num_objects: 10, object_payload_size: 10 * 1024, }), - (1187, EntryPoints::CreateObjects { + (1369, EntryPoints::CreateObjects { num_objects: 100, object_payload_size: 0, }), @@ -142,8 +142,8 @@ fn main() { (257, EntryPoints::TokenV1MintAndTransferFT), (412, EntryPoints::TokenV1MintAndTransferNFTSequential), (368, EntryPoints::TokenV2AmbassadorMint { numbered: true }), - (520, EntryPoints::LiquidityPoolSwap { is_stable: true }), - (500, EntryPoints::LiquidityPoolSwap { is_stable: false }), + (494, EntryPoints::LiquidityPoolSwap { is_stable: true }), + (463, EntryPoints::LiquidityPoolSwap { is_stable: false }), ]; let mut failures = Vec::new(); diff --git a/aptos-move/e2e-move-tests/src/harness.rs b/aptos-move/e2e-move-tests/src/harness.rs index 11751def4360a..84e9ad0a0a1cd 100644 --- a/aptos-move/e2e-move-tests/src/harness.rs +++ b/aptos-move/e2e-move-tests/src/harness.rs @@ -13,9 +13,11 @@ use aptos_language_e2e_tests::{ executor::FakeExecutor, }; use aptos_types::{ - access_path::AccessPath, account_address::AccountAddress, - account_config::{AccountResource, CoinStoreResource, CORE_CODE_ADDRESS}, + account_config::{ + fungible_store::FungibleStoreResource, object::ObjectGroupResource, AccountResource, + CoinStoreResource, CORE_CODE_ADDRESS, + }, chain_id::ChainId, contract_event::ContractEvent, move_utils::MemberId, @@ -25,8 +27,9 @@ use aptos_types::{ state_value::{StateValue, StateValueMetadata}, }, transaction::{ - EntryFunction, Script, SignedTransaction, TransactionArgument, TransactionOutput, - TransactionPayload, TransactionStatus, ViewFunctionOutput, + EntryFunction, Multisig, MultisigTransactionPayload, Script, SignedTransaction, + TransactionArgument, TransactionOutput, TransactionPayload, TransactionStatus, + ViewFunctionOutput, }, }; use aptos_vm::{data_cache::AsMoveResolver, AptosVM}; @@ -77,7 +80,7 @@ pub struct MoveHarness { txn_seq_no: BTreeMap, pub default_gas_unit_price: u64, - max_gas_per_txn: u64, + pub max_gas_per_txn: u64, } #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -160,10 +163,14 @@ impl MoveHarness { /// Creates an account for the given static address. This address needs to be static so /// we can load regular Move code to there without need to rewrite code addresses. pub fn new_account_at(&mut self, addr: AccountAddress) -> Account { + self.new_account_with_balance_at(addr, 1_000_000_000_000_000) + } + + pub fn new_account_with_balance_at(&mut self, addr: AccountAddress, balance: u64) -> Account { // The below will use the genesis keypair but that should be fine. let acc = Account::new_genesis_account(addr); // Mint the account 10M Aptos coins (with 8 decimals). - self.store_and_fund_account(&acc, 1_000_000_000_000_000, 10) + self.store_and_fund_account(&acc, balance, 10) } // Creates an account with a randomly generated address and key pair @@ -349,6 +356,22 @@ impl MoveHarness { ) } + /// Create a multisig transaction. + pub fn create_multisig( + &mut self, + account: &Account, + multisig_address: AccountAddress, + transaction_payload: Option, + ) -> SignedTransaction { + self.create_transaction_payload( + account, + TransactionPayload::Multisig(Multisig { + multisig_address, + transaction_payload, + }), + ) + } + pub fn create_script( &mut self, account: &Account, @@ -374,6 +397,17 @@ impl MoveHarness { self.run(txn) } + /// Run the multisig transaction. + pub fn run_multisig( + &mut self, + account: &Account, + multisig_address: AccountAddress, + transaction_payload: Option, + ) -> TransactionStatus { + let txn = self.create_multisig(account, multisig_address, transaction_payload); + self.run(txn) + } + /// Run the specified entry point `fun` and return the gas used. pub fn evaluate_entry_function_gas( &mut self, @@ -473,7 +507,7 @@ impl MoveHarness { options: Option, patch_metadata: impl FnMut(&mut PackageMetadata), ) -> SignedTransaction { - let package = build_package(path.to_owned(), options.unwrap_or_default()) + let package = BuiltPackage::build(path.to_owned(), options.unwrap_or_default()) .expect("building package must succeed"); self.create_publish_built_package(account, &package, patch_metadata) } @@ -682,9 +716,7 @@ impl MoveHarness { addr: &AccountAddress, struct_tag: StructTag, ) -> Option> { - let path = - AccessPath::resource_access_path(*addr, struct_tag).expect("access path in test"); - self.read_state_value_bytes(&StateKey::access_path(path)) + self.read_state_value_bytes(&StateKey::resource(addr, &struct_tag).unwrap()) } /// Reads the resource data `T`. @@ -706,10 +738,17 @@ impl MoveHarness { addr: &AccountAddress, struct_tag: StructTag, ) -> Option { - self.read_state_value(&StateKey::access_path( - AccessPath::resource_access_path(*addr, struct_tag).expect("access path in test"), - )) - .map(StateValue::into_metadata) + self.read_state_value(&StateKey::resource(addr, &struct_tag).unwrap()) + .map(StateValue::into_metadata) + } + + pub fn read_resource_group_metadata( + &self, + addr: &AccountAddress, + struct_tag: StructTag, + ) -> Option { + self.read_state_value(&StateKey::resource_group(addr, &struct_tag)) + .map(StateValue::into_metadata) } pub fn read_resource_group( @@ -717,8 +756,7 @@ impl MoveHarness { addr: &AccountAddress, struct_tag: StructTag, ) -> Option>> { - let path = AccessPath::resource_group_access_path(*addr, struct_tag); - self.read_state_value_bytes(&StateKey::access_path(path)) + self.read_state_value_bytes(&StateKey::resource_group(addr, &struct_tag)) .map(|data| bcs::from_bytes(&data).unwrap()) } @@ -743,8 +781,16 @@ impl MoveHarness { pub fn read_aptos_balance(&self, addr: &AccountAddress) -> u64 { self.read_resource::(addr, CoinStoreResource::struct_tag()) - .unwrap() - .coin() + .map(|c| c.coin()) + .unwrap_or(0) + + self + .read_resource_from_resource_group::( + &aptos_types::account_config::fungible_store::primary_store(addr), + ObjectGroupResource::struct_tag(), + FungibleStoreResource::struct_tag(), + ) + .map(|c| c.balance()) + .unwrap_or(0) } /// Write the resource data `T`. @@ -755,8 +801,7 @@ impl MoveHarness { struct_tag: StructTag, data: &T, ) { - let path = AccessPath::resource_access_path(addr, struct_tag).expect("access path in test"); - let state_key = StateKey::access_path(path); + let state_key = StateKey::resource(&addr, &struct_tag).unwrap(); self.executor .write_state_value(state_key, bcs::to_bytes(data).unwrap()); } @@ -891,7 +936,7 @@ impl MoveHarness { arguments: Vec>, ) -> ViewFunctionOutput { self.executor - .execute_view_function(fun.module_id, fun.member_id, type_args, arguments) + .execute_view_function(fun, type_args, arguments) } /// Splits transactions into blocks based on passed `block_split``, and diff --git a/aptos-move/e2e-move-tests/src/lib.rs b/aptos-move/e2e-move-tests/src/lib.rs index 4b929143c3551..b545f14251980 100644 --- a/aptos-move/e2e-move-tests/src/lib.rs +++ b/aptos-move/e2e-move-tests/src/lib.rs @@ -12,7 +12,7 @@ pub mod transaction_fee; use anyhow::bail; use aptos_framework::{BuildOptions, BuiltPackage, UPGRADE_POLICY_CUSTOM_FIELD}; pub use harness::*; -use move_command_line_common::{env::read_bool_env_var, testing::MOVE_COMPILER_V2}; +use move_command_line_common::env::get_move_compiler_v2_from_env; use move_model::metadata::CompilerVersion; use move_package::{package_hooks::PackageHooks, source_package::parsed_manifest::CustomDepInfo}; use move_symbol_pool::Symbol; @@ -47,7 +47,7 @@ pub(crate) fn build_package( options: BuildOptions, ) -> anyhow::Result { let mut options = options; - if read_bool_env_var(MOVE_COMPILER_V2) { + if get_move_compiler_v2_from_env() { options.compiler_version = Some(CompilerVersion::V2_0); } BuiltPackage::build(package_path.to_owned(), options) diff --git a/aptos-move/e2e-move-tests/src/tests/access_path_test.rs b/aptos-move/e2e-move-tests/src/tests/access_path_test.rs index 895c38c1c52ba..02b774bd7751b 100644 --- a/aptos-move/e2e-move-tests/src/tests/access_path_test.rs +++ b/aptos-move/e2e-move-tests/src/tests/access_path_test.rs @@ -18,6 +18,8 @@ use move_binary_format::{ }; use move_core_types::{identifier::Identifier, vm_status::StatusCode}; +/// FIXME(aldenhu): fix or remove +#[ignore] #[test] fn access_path_panic() { // github.com/aptos-labs/aptos-core/security/advisories/GHSA-rpw2-84hq-48jj diff --git a/aptos-move/e2e-move-tests/src/tests/fee_payer.rs b/aptos-move/e2e-move-tests/src/tests/fee_payer.rs index ffd8287c5931b..62a03daaac4bb 100644 --- a/aptos-move/e2e-move-tests/src/tests/fee_payer.rs +++ b/aptos-move/e2e-move-tests/src/tests/fee_payer.rs @@ -169,7 +169,7 @@ fn test_account_not_exist_with_fee_payer_insufficient_gas() { let output = h.run_raw(transaction); assert!(transaction_status_eq( output.status(), - &TransactionStatus::Discard(StatusCode::MAX_GAS_UNITS_BELOW_MIN_TRANSACTION_GAS_UNITS) + &TransactionStatus::Discard(StatusCode::MAX_GAS_UNITS_BELOW_MIN_TRANSACTION_GAS_UNITS), )); let alice_after = @@ -351,7 +351,7 @@ fn test_account_not_exist_with_fee_payer_without_create_account() { let output = h.run_raw(transaction); assert!(transaction_status_eq( output.status(), - &TransactionStatus::Discard(StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST) + &TransactionStatus::Discard(StatusCode::SENDING_ACCOUNT_DOES_NOT_EXIST), )); } @@ -380,7 +380,7 @@ fn test_normal_tx_with_fee_payer_insufficient_funds() { let output = h.run_raw(transaction); assert!(transaction_status_eq( output.status(), - &TransactionStatus::Discard(StatusCode::INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE) + &TransactionStatus::Discard(StatusCode::INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE), )); } diff --git a/aptos-move/e2e-move-tests/src/tests/fungible_asset.rs b/aptos-move/e2e-move-tests/src/tests/fungible_asset.rs index 4487ba9477308..786100f52d1c8 100644 --- a/aptos-move/e2e-move-tests/src/tests/fungible_asset.rs +++ b/aptos-move/e2e-move-tests/src/tests/fungible_asset.rs @@ -3,8 +3,13 @@ use crate::{assert_success, tests::common, MoveHarness}; use aptos_types::account_address::{self, AccountAddress}; -use move_core_types::{identifier::Identifier, language_storage::StructTag}; +use move_core_types::{ + identifier::Identifier, + language_storage::{StructTag, TypeTag}, +}; +use once_cell::sync::Lazy; use serde::Deserialize; +use std::str::FromStr; #[derive(Debug, Deserialize, Eq, PartialEq)] struct FungibleStore { @@ -13,12 +18,26 @@ struct FungibleStore { allow_ungated_balance_transfer: bool, } +pub static FUNGIBLE_STORE_TAG: Lazy = Lazy::new(|| StructTag { + address: AccountAddress::from_hex_literal("0x1").unwrap(), + module: Identifier::new("fungible_asset").unwrap(), + name: Identifier::new("FungibleStore").unwrap(), + type_params: vec![], +}); + +pub static OBJ_GROUP_TAG: Lazy = Lazy::new(|| StructTag { + address: AccountAddress::from_hex_literal("0x1").unwrap(), + module: Identifier::new("object").unwrap(), + name: Identifier::new("ObjectGroup").unwrap(), + type_params: vec![], +}); #[test] fn test_basic_fungible_token() { let mut h = MoveHarness::new(); let alice = h.new_account_at(AccountAddress::from_hex_literal("0xcafe").unwrap()); let bob = h.new_account_at(AccountAddress::from_hex_literal("0xface").unwrap()); + let root = h.aptos_framework_account(); let mut build_options = aptos_framework::BuildOptions::default(); build_options @@ -39,6 +58,17 @@ fn test_basic_fungible_token() { ); assert_success!(result); + assert_success!(h.run_entry_function( + &root, + str::parse(&format!( + "0x{}::coin::create_coin_conversion_map", + (*root.address()).to_hex() + )) + .unwrap(), + vec![], + vec![], + )); + let metadata = h .execute_view_function( str::parse(&format!( @@ -114,33 +144,20 @@ fn test_basic_fungible_token() { let bob_primary_store_addr = account_address::create_derived_object_address(*bob.address(), token_addr); - let fungible_store_tag = StructTag { - address: AccountAddress::from_hex_literal("0x1").unwrap(), - module: Identifier::new("fungible_asset").unwrap(), - name: Identifier::new("FungibleStore").unwrap(), - type_params: vec![], - }; - let obj_group_tag = StructTag { - address: AccountAddress::from_hex_literal("0x1").unwrap(), - module: Identifier::new("object").unwrap(), - name: Identifier::new("ObjectGroup").unwrap(), - type_params: vec![], - }; - // Ensure that the group data can be read let mut alice_store: FungibleStore = h .read_resource_from_resource_group( &alice_primary_store_addr, - obj_group_tag.clone(), - fungible_store_tag.clone(), + OBJ_GROUP_TAG.clone(), + FUNGIBLE_STORE_TAG.clone(), ) .unwrap(); let bob_store: FungibleStore = h .read_resource_from_resource_group( &bob_primary_store_addr, - obj_group_tag, - fungible_store_tag, + OBJ_GROUP_TAG.clone(), + FUNGIBLE_STORE_TAG.clone(), ) .unwrap(); @@ -150,3 +167,59 @@ fn test_basic_fungible_token() { alice_store.balance = 10; assert_eq!(alice_store, bob_store); } + +// A simple test to verify gas paying still work for prologue and epilogue. +#[test] +fn test_coin_to_fungible_asset_migration() { + let mut h = MoveHarness::new(); + + let alice = h.new_account_at(AccountAddress::from_hex_literal("0xcafe").unwrap()); + let alice_primary_store_addr = + account_address::create_derived_object_address(*alice.address(), AccountAddress::TEN); + let root = h.aptos_framework_account(); + + assert_success!(h.run_entry_function( + &root, + str::parse(&format!( + "0x{}::coin::create_coin_conversion_map", + (*root.address()).to_hex() + )) + .unwrap(), + vec![], + vec![], + )); + + assert_success!(h.run_entry_function( + &root, + str::parse(&format!( + "0x{}::coin::create_pairing", + (*root.address()).to_hex() + )) + .unwrap(), + vec![TypeTag::from_str("0x1::aptos_coin::AptosCoin").unwrap()], + vec![], + )); + assert!(h + .read_resource_from_resource_group::( + &alice_primary_store_addr, + OBJ_GROUP_TAG.clone(), + FUNGIBLE_STORE_TAG.clone() + ) + .is_none()); + + let result = h.run_entry_function( + &alice, + str::parse("0x1::coin::migrate_to_fungible_store").unwrap(), + vec![TypeTag::from_str("0x1::aptos_coin::AptosCoin").unwrap()], + vec![], + ); + assert_success!(result); + + assert!(h + .read_resource_from_resource_group::( + &alice_primary_store_addr, + OBJ_GROUP_TAG.clone(), + FUNGIBLE_STORE_TAG.clone() + ) + .is_some()); +} diff --git a/aptos-move/e2e-move-tests/src/tests/keyless_feature_gating.rs b/aptos-move/e2e-move-tests/src/tests/keyless_feature_gating.rs index 9135aff780bb6..58fdd63b7589b 100644 --- a/aptos-move/e2e-move-tests/src/tests/keyless_feature_gating.rs +++ b/aptos-move/e2e-move-tests/src/tests/keyless_feature_gating.rs @@ -8,11 +8,11 @@ use aptos_language_e2e_tests::account::{Account, AccountPublicKey, TransactionBu use aptos_types::{ keyless::{ test_utils::{ - get_sample_esk, get_sample_groth16_sig_and_pk, get_sample_iss, get_sample_jwk, - get_sample_openid_sig_and_pk, + get_groth16_sig_and_pk_for_upgraded_vk, get_sample_esk, get_sample_groth16_sig_and_pk, + get_sample_iss, get_sample_jwk, get_sample_openid_sig_and_pk, get_upgraded_vk, }, - Configuration, EphemeralCertificate, KeylessPublicKey, KeylessSignature, - TransactionAndProof, + Configuration, EphemeralCertificate, Groth16VerificationKey, KeylessPublicKey, + KeylessSignature, TransactionAndProof, }, on_chain_config::FeatureFlag, transaction::{ @@ -21,22 +21,23 @@ use aptos_types::{ }, }; use move_core_types::{ - account_address::AccountAddress, transaction_argument::TransactionArgument, - vm_status::StatusCode::FEATURE_UNDER_GATING, + account_address::AccountAddress, + transaction_argument::TransactionArgument, + vm_status::{StatusCode, StatusCode::FEATURE_UNDER_GATING}, }; fn init_feature_gating( enabled_features: Vec, disabled_features: Vec, -) -> (MoveHarness, Account) { +) -> (MoveHarness, Account, Account) { let mut h = MoveHarness::new_with_features(enabled_features, disabled_features); let recipient = h.new_account_at(AccountAddress::from_hex_literal("0xb0b").unwrap()); // initialize JWKs - run_setup_script(&mut h); + let core_resources = run_jwk_and_config_script(&mut h); - (h, recipient) + (h, recipient, core_resources) } fn test_feature_gating( @@ -47,7 +48,7 @@ fn test_feature_gating( ) { let (sig, pk) = get_sig_and_pk(); - let transaction = get_keyless_txn(h, sig, pk, *recipient.address()); + let transaction = create_and_spend_keyless_account(h, sig, pk, *recipient.address()); let output = h.run_raw(transaction); if !should_succeed { @@ -75,12 +76,72 @@ fn test_feature_gating( } } +#[test] +fn test_rotate_vk() { + let (mut h, recipient, core_resources) = init_feature_gating( + vec![ + FeatureFlag::CRYPTOGRAPHY_ALGEBRA_NATIVES, + FeatureFlag::BN254_STRUCTURES, + FeatureFlag::KEYLESS_ACCOUNTS, + ], + vec![], + ); + + // Old proof for old VK + let (old_sig, pk) = get_sample_groth16_sig_and_pk(); + let account = create_keyless_account(&mut h, pk.clone()); + let transaction = + spend_keyless_account(&mut h, old_sig.clone(), &account, *recipient.address()); + let output = h.run_raw(transaction); + assert_success!(output.status().clone()); + + // New proof for old VK + let (new_sig, _) = get_groth16_sig_and_pk_for_upgraded_vk(); + let transaction = + spend_keyless_account(&mut h, new_sig.clone(), &account, *recipient.address()); + let output = h.run_raw(transaction); + //println!("TXN status: {:?}", output.status()); + match output.status() { + TransactionStatus::Discard(sc) => assert_eq!(*sc, StatusCode::INVALID_SIGNATURE), + TransactionStatus::Keep(es) => { + panic!("Expected TransactionStatus::Discard, got Keep({:?})", es) + }, + TransactionStatus::Retry => panic!("Expected TransactionStatus::Discard, got Retry"), + } + + // Upgrade the VK + run_upgrade_vk_script( + &mut h, + core_resources, + Groth16VerificationKey::from(get_upgraded_vk()), + ); + + // New proof for new VK + let transaction = spend_keyless_account(&mut h, new_sig, &account, *recipient.address()); + let output = h.run_raw(transaction); + assert_success!(output.status().clone()); + + // Old proof for old VK + let transaction = spend_keyless_account(&mut h, old_sig, &account, *recipient.address()); + let output = h.run_raw(transaction); + // println!("TXN status: {:?}", output.status()); + match output.status() { + TransactionStatus::Discard(sc) => assert_eq!(*sc, StatusCode::INVALID_SIGNATURE), + TransactionStatus::Keep(es) => { + panic!("Expected TransactionStatus::Discard, got Keep({:?})", es) + }, + TransactionStatus::Retry => panic!("Expected TransactionStatus::Discard, got Retry"), + } +} + #[test] fn test_feature_gating_with_zk_on() { // // ZK & ZKless - let (mut h, recipient) = init_feature_gating( + let (mut h, recipient, _) = init_feature_gating( vec![ + FeatureFlag::CRYPTOGRAPHY_ALGEBRA_NATIVES, + FeatureFlag::BN254_STRUCTURES, FeatureFlag::KEYLESS_ACCOUNTS, FeatureFlag::KEYLESS_BUT_ZKLESS_ACCOUNTS, ], @@ -93,9 +154,14 @@ fn test_feature_gating_with_zk_on() { // // ZK & !ZKless - let (mut h, recipient) = init_feature_gating(vec![FeatureFlag::KEYLESS_ACCOUNTS], vec![ - FeatureFlag::KEYLESS_BUT_ZKLESS_ACCOUNTS, - ]); + let (mut h, recipient, _) = init_feature_gating( + vec![ + FeatureFlag::CRYPTOGRAPHY_ALGEBRA_NATIVES, + FeatureFlag::BN254_STRUCTURES, + FeatureFlag::KEYLESS_ACCOUNTS, + ], + vec![FeatureFlag::KEYLESS_BUT_ZKLESS_ACCOUNTS], + ); // Groth16-based sig => success test_feature_gating(&mut h, &recipient, get_sample_groth16_sig_and_pk, true); // OIDC-based sig => discard @@ -106,10 +172,14 @@ fn test_feature_gating_with_zk_on() { fn test_feature_gating_with_zk_off() { // // !ZK & ZKless - let (mut h, recipient) = - init_feature_gating(vec![FeatureFlag::KEYLESS_BUT_ZKLESS_ACCOUNTS], vec![ - FeatureFlag::KEYLESS_ACCOUNTS, - ]); + let (mut h, recipient, _) = init_feature_gating( + vec![ + FeatureFlag::CRYPTOGRAPHY_ALGEBRA_NATIVES, + FeatureFlag::BN254_STRUCTURES, + FeatureFlag::KEYLESS_BUT_ZKLESS_ACCOUNTS, + ], + vec![FeatureFlag::KEYLESS_ACCOUNTS], + ); // Groth16-based sig => discard test_feature_gating(&mut h, &recipient, get_sample_groth16_sig_and_pk, false); // OIDC-based sig => success @@ -117,27 +187,27 @@ fn test_feature_gating_with_zk_off() { // // !ZK & !ZKless - let (mut h, recipient) = init_feature_gating(vec![], vec![ - FeatureFlag::KEYLESS_ACCOUNTS, - FeatureFlag::KEYLESS_BUT_ZKLESS_ACCOUNTS, - ]); + let (mut h, recipient, _) = init_feature_gating( + vec![ + FeatureFlag::CRYPTOGRAPHY_ALGEBRA_NATIVES, + FeatureFlag::BN254_STRUCTURES, + ], + vec![ + FeatureFlag::KEYLESS_ACCOUNTS, + FeatureFlag::KEYLESS_BUT_ZKLESS_ACCOUNTS, + ], + ); // Groth16-based sig => discard test_feature_gating(&mut h, &recipient, get_sample_groth16_sig_and_pk, false); // OIDC-based sig => discard test_feature_gating(&mut h, &recipient, get_sample_openid_sig_and_pk, false); } -/// Creates and funds a new account at `pk` and sends coins to `recipient`. -fn get_keyless_txn( - h: &mut MoveHarness, - mut sig: KeylessSignature, - pk: KeylessPublicKey, - recipient: AccountAddress, -) -> SignedTransaction { +fn create_keyless_account(h: &mut MoveHarness, pk: KeylessPublicKey) -> Account { let apk = AnyPublicKey::keyless(pk.clone()); let addr = AuthenticationKey::any_key(apk.clone()).account_address(); let account = h.store_and_fund_account( - &Account::new_from_addr(addr, AccountPublicKey::Keyless(pk.clone())), + &Account::new_from_addr(addr, AccountPublicKey::Keyless(pk)), 100000000, 0, ); @@ -145,6 +215,15 @@ fn get_keyless_txn( println!("Actual address: {}", addr.to_hex()); println!("Account address: {}", account.address().to_hex()); + account +} + +fn spend_keyless_account( + h: &mut MoveHarness, + mut sig: KeylessSignature, + account: &Account, + recipient: AccountAddress, +) -> SignedTransaction { let payload = aptos_stdlib::aptos_coin_transfer(recipient, 1); //println!("Payload: {:?}", payload); let raw_txn = TransactionBuilder::new(account.clone()) @@ -162,7 +241,6 @@ fn get_keyless_txn( }; let esk = get_sample_esk(); - // Compute the training wheels signature if not present match &mut sig.cert { EphemeralCertificate::ZeroKnowledgeSig(proof) => { // Training wheels should be disabled. @@ -173,7 +251,8 @@ fn get_keyless_txn( } sig.ephemeral_signature = EphemeralSignature::ed25519(esk.sign(&txn_and_zkp).unwrap()); - let transaction = SignedTransaction::new_keyless(raw_txn, pk, sig); + let transaction = + SignedTransaction::new_keyless(raw_txn, account.pubkey.as_keyless().unwrap(), sig); println!( "Submitted TXN hash: {}", Transaction::UserTransaction(transaction.clone()).hash() @@ -181,7 +260,19 @@ fn get_keyless_txn( transaction } -fn run_setup_script(h: &mut MoveHarness) { +/// Creates and funds a new account at `pk` and sends coins to `recipient`. +fn create_and_spend_keyless_account( + h: &mut MoveHarness, + sig: KeylessSignature, + pk: KeylessPublicKey, + recipient: AccountAddress, +) -> SignedTransaction { + let account = create_keyless_account(h, pk.clone()); + + spend_keyless_account(h, sig, &account, recipient) +} + +fn run_jwk_and_config_script(h: &mut MoveHarness) -> Account { let core_resources = h.new_account_at(AccountAddress::from_hex_literal("0xA550C18").unwrap()); let package = build_package( @@ -217,4 +308,38 @@ fn run_setup_script(h: &mut MoveHarness) { // because it does not (yet) work with resource groups. assert_success!(h.run(txn)); + + core_resources +} + +fn run_upgrade_vk_script(h: &mut MoveHarness, core_resources: Account, vk: Groth16VerificationKey) { + let package = build_package( + common::test_dir_path("keyless_new_vk.data/pack"), + aptos_framework::BuildOptions::default(), + ) + .expect("building package must succeed"); + + let txn = h.create_publish_built_package(&core_resources, &package, |_| {}); + assert_success!(h.run(txn)); + + let script = package.extract_script_code()[0].clone(); + + let txn = TransactionBuilder::new(core_resources.clone()) + .script(Script::new(script, vec![], vec![ + TransactionArgument::U8Vector(vk.alpha_g1), + TransactionArgument::U8Vector(vk.beta_g2), + TransactionArgument::U8Vector(vk.gamma_g2), + TransactionArgument::U8Vector(vk.delta_g2), + TransactionArgument::U8Vector(vk.gamma_abc_g1[0].clone()), + TransactionArgument::U8Vector(vk.gamma_abc_g1[1].clone()), + ])) + .sequence_number(h.sequence_number(core_resources.address())) + .max_gas_amount(1_000_000) + .gas_unit_price(1) + .sign(); + + // NOTE: We cannot write the Groth16Verification key via MoveHarness::set_resource + // because it does not (yet) work with resource groups. + + assert_success!(h.run(txn)); } diff --git a/aptos-move/e2e-move-tests/src/tests/keyless_new_vk.data/pack/Move.toml b/aptos-move/e2e-move-tests/src/tests/keyless_new_vk.data/pack/Move.toml new file mode 100644 index 0000000000000..5059ec9ee8568 --- /dev/null +++ b/aptos-move/e2e-move-tests/src/tests/keyless_new_vk.data/pack/Move.toml @@ -0,0 +1,6 @@ +[package] +name = 'UpdateGroth16VerificationKey' +version = "0.0.0" + +[dependencies] +AptosFramework = { local = "../../../../../framework/aptos-framework" } diff --git a/aptos-move/e2e-move-tests/src/tests/keyless_new_vk.data/pack/sources/main.move b/aptos-move/e2e-move-tests/src/tests/keyless_new_vk.data/pack/sources/main.move new file mode 100644 index 0000000000000..81584c7b01aa9 --- /dev/null +++ b/aptos-move/e2e-move-tests/src/tests/keyless_new_vk.data/pack/sources/main.move @@ -0,0 +1,20 @@ +script { + use aptos_framework::aptos_governance; + use aptos_framework::keyless_account; + + fun main( + core_resources: &signer, + alpha_g1: vector, + beta_g2: vector, + gamma_g2: vector, + delta_g2: vector, + gamma_abc_g1_0: vector, + gamma_abc_g1_1: vector + ) { + let vk = keyless_account::new_groth16_verification_key(alpha_g1, beta_g2, gamma_g2, delta_g2, vector[gamma_abc_g1_0, gamma_abc_g1_1]); + let fx = aptos_governance::get_signer_testnet_only(core_resources, @aptos_framework); + keyless_account::set_groth16_verification_key_for_next_epoch(&fx, vk); + // sets the pending Configuration change to the max expiration horizon from above + aptos_governance::force_end_epoch_test_only(core_resources); + } +} diff --git a/aptos-move/e2e-move-tests/src/tests/keyless_setup.data/pack/Move.toml b/aptos-move/e2e-move-tests/src/tests/keyless_setup.data/pack/Move.toml index 9c710048b40d9..32918657e6fd9 100644 --- a/aptos-move/e2e-move-tests/src/tests/keyless_setup.data/pack/Move.toml +++ b/aptos-move/e2e-move-tests/src/tests/keyless_setup.data/pack/Move.toml @@ -1,5 +1,5 @@ [package] -name = 'InsertJwk' +name = 'InsertJwkAndUpdateMaxExpHorizon' version = "0.0.0" [dependencies] diff --git a/aptos-move/e2e-move-tests/src/tests/keyless_setup.data/pack/sources/main.move b/aptos-move/e2e-move-tests/src/tests/keyless_setup.data/pack/sources/main.move index 2f7a0631421a7..9caaa1b2f3b37 100644 --- a/aptos-move/e2e-move-tests/src/tests/keyless_setup.data/pack/sources/main.move +++ b/aptos-move/e2e-move-tests/src/tests/keyless_setup.data/pack/sources/main.move @@ -19,6 +19,8 @@ script { ]; jwks::set_patches(&fx, patches); - keyless_account::update_max_exp_horizon(&fx, max_exp_horizon_secs); + keyless_account::update_max_exp_horizon_for_next_epoch(&fx, max_exp_horizon_secs); + // sets the pending Configuration change to the max expiration horizon from above + aptos_governance::force_end_epoch_test_only(core_resources); } } diff --git a/aptos-move/e2e-move-tests/src/tests/mint_nft.rs b/aptos-move/e2e-move-tests/src/tests/mint_nft.rs index 17b0ad39660e1..2c134958473ef 100644 --- a/aptos-move/e2e-move-tests/src/tests/mint_nft.rs +++ b/aptos-move/e2e-move-tests/src/tests/mint_nft.rs @@ -145,7 +145,7 @@ fn mint_nft_e2e() { // assert that the token id exists in the nft receiver's token store // read_state_value() will only be successful if the nft receiver's token store has this token id - let state_key = &StateKey::table_item(token_store_table, bcs::to_bytes(&token_id).unwrap()); + let state_key = &StateKey::table_item(&token_store_table, &bcs::to_bytes(&token_id).unwrap()); h.read_state_value_bytes(state_key).unwrap(); } diff --git a/aptos-move/e2e-move-tests/src/tests/missing_gas_parameter.rs b/aptos-move/e2e-move-tests/src/tests/missing_gas_parameter.rs index 4b427c71e010d..8db3c99c4bf3f 100644 --- a/aptos-move/e2e-move-tests/src/tests/missing_gas_parameter.rs +++ b/aptos-move/e2e-move-tests/src/tests/missing_gas_parameter.rs @@ -19,7 +19,7 @@ fn missing_gas_parameter() { }); // Load the code - let acc = h.new_account_at(AccountAddress::from_hex_literal("0xbeef").unwrap()); + let acc = h.new_account_with_balance_at(AccountAddress::from_hex_literal("0xbeef").unwrap(), 0); let txn_status = h.publish_package(&acc, &common::test_dir_path("common.data/do_nothing")); assert!(matches!( txn_status, diff --git a/aptos-move/e2e-move-tests/src/tests/mod.rs b/aptos-move/e2e-move-tests/src/tests/mod.rs index 6319d85693326..c407d74e82e47 100644 --- a/aptos-move/e2e-move-tests/src/tests/mod.rs +++ b/aptos-move/e2e-move-tests/src/tests/mod.rs @@ -47,6 +47,7 @@ mod storage_refund; mod string_args; mod token_event_store; mod token_objects; +mod transaction_context; mod transaction_fee; mod type_too_large; mod vector_numeric_address; diff --git a/aptos-move/e2e-move-tests/src/tests/per_category_gas_limits.rs b/aptos-move/e2e-move-tests/src/tests/per_category_gas_limits.rs index f4d3aefaf30cd..75b40444096f1 100644 --- a/aptos-move/e2e-move-tests/src/tests/per_category_gas_limits.rs +++ b/aptos-move/e2e-move-tests/src/tests/per_category_gas_limits.rs @@ -170,7 +170,7 @@ fn out_of_gas_while_charging_storage_fee() { } fn state_key_size() -> NumBytes { - let key_size = StateKey::table_item(TableHandle(AccountAddress::ONE), vec![0u8]).size(); + let key_size = StateKey::table_item(&TableHandle(AccountAddress::ONE), &[0u8]).size(); (key_size as u64).into() } diff --git a/aptos-move/e2e-move-tests/src/tests/randomness_test_and_abort.rs b/aptos-move/e2e-move-tests/src/tests/randomness_test_and_abort.rs index 0dbb2a2a2afe0..66317a136b737 100644 --- a/aptos-move/e2e-move-tests/src/tests/randomness_test_and_abort.rs +++ b/aptos-move/e2e-move-tests/src/tests/randomness_test_and_abort.rs @@ -43,6 +43,9 @@ fn test_and_abort_defense_is_sound_and_correct() { // The randomness module is initialized, but the randomness seed is not set. set_randomness_seed(&mut h); + h.set_default_gas_unit_price(100); + h.set_max_gas_per_txn(10000); // Should match the default required gas amount. + // This is a safe call that the randomness API should allow through. let status = run_entry_func( &mut h, @@ -83,10 +86,14 @@ fn test_only_private_entry_function_can_be_annotated() { #[test] fn test_unbiasable_annotation() { let mut h = MoveHarness::new(); + deploy_code(AccountAddress::ONE, "randomness.data/pack", &mut h) .expect("building package must succeed"); set_randomness_seed(&mut h); + h.set_default_gas_unit_price(100); + h.set_max_gas_per_txn(10000); // Should match the default required gas amount. + let should_succeed = [ "0x1::test::ok_if_not_annotated_and_not_using_randomness", "0x1::test::ok_if_annotated_and_not_using_randomness", @@ -129,38 +136,32 @@ fn test_undergas_attack_prevention() { .expect("building package must succeed"); set_randomness_seed(&mut h); - // Modify gas parameters so the required deposit for randomness txns is 234_000_000 when gas price is 1. - h.modify_gas_schedule(|gas_params| { - gas_params.vm.txn.max_execution_gas = 200_000_000.into(); - gas_params.vm.txn.max_io_gas = 30_000_000.into(); - gas_params.vm.txn.max_storage_fee = 4_000_000.into(); - gas_params.vm.txn.maximum_number_of_gas_units = 234_000_001.into(); - }); - - h.set_default_gas_unit_price(1); + h.set_default_gas_unit_price(100); + h.set_max_gas_per_txn(10000); // Should match the default required gas amount. // A function to send some amount to 2 people where how to split between the 2 is randomized. let func: MemberId = str::parse("0x1::test::transfer_lucky_money").unwrap(); let recipient_0 = h.new_account_with_balance_and_sequence_number(0, 11); let recipient_1 = h.new_account_with_balance_and_sequence_number(0, 12); - // A txn should be discarded if the sender balance is not enough to pay required deposit. - let sender = h.new_account_with_balance_and_sequence_number(999, 123); + // A txn should be discarded if the sender balance is not enough to pay required deposit: 0.01 APT or 1_000_000 octa. + let sender = h.new_account_with_balance_and_sequence_number(999_999, 123); let args = vec![ - 1_000_000_000_u64.as_move_value(), + 1000_u64.as_move_value(), MoveValue::Address(*recipient_0.address()), MoveValue::Address(*recipient_1.address()), ]; + println!("3 max_gas_per_txn={}", h.max_gas_per_txn); let status = h.run_entry_function(&sender, func.clone(), vec![], serialize_values(&args)); assert!(status.is_discarded()); - assert_eq!(999, h.read_aptos_balance(sender.address())); + assert_eq!(999_999_u64, h.read_aptos_balance(sender.address())); assert_eq!(0, h.read_aptos_balance(recipient_0.address())); assert_eq!(0, h.read_aptos_balance(recipient_1.address())); // A txn should abort but be kept if the sender doesn't have enough balance to complete the transfer. - let sender = h.new_account_with_balance_and_sequence_number(234_999_999, 456); + let sender = h.new_account_with_balance_and_sequence_number(1_001_000_000, 456); let args = vec![ - 1_000_000_000_u64.as_move_value(), + 1_000_000_999_u64.as_move_value(), // 999 more than what sender has after prologue. MoveValue::Address(*recipient_0.address()), MoveValue::Address(*recipient_1.address()), ]; @@ -168,15 +169,15 @@ fn test_undergas_attack_prevention() { let status = assert_ok!(status.as_kept_status()); assert!(matches!(status, ExecutionStatus::MoveAbort { .. })); let sender_balance = h.read_aptos_balance(sender.address()); - assert_gt!(sender_balance, 234_000_000); - assert_lt!(sender_balance, 234_999_999); + assert_gt!(sender_balance, 1_000_000); // At least the locked amount will be returned. + assert_lt!(sender_balance, 1_001_000_000); // Sender lost gas fee. assert_eq!(0, h.read_aptos_balance(recipient_0.address())); assert_eq!(0, h.read_aptos_balance(recipient_1.address())); // Otherwise, the txn should finish normally. - let sender = h.new_account_with_balance_and_sequence_number(1_234_999_999, 789); + let sender = h.new_account_with_balance_and_sequence_number(1_001_000_000, 789); let args = vec![ - 1_000_000_000_u64.as_move_value(), + 500_000_000_u64.as_move_value(), // half of what sender has after prologue. MoveValue::Address(*recipient_0.address()), MoveValue::Address(*recipient_1.address()), ]; @@ -184,10 +185,10 @@ fn test_undergas_attack_prevention() { let status = assert_ok!(status.as_kept_status()); assert!(matches!(status, ExecutionStatus::Success)); let sender_balance = h.read_aptos_balance(sender.address()); - assert_gt!(sender_balance, 234_000_000); - assert_lt!(sender_balance, 234_999_999); + assert_gt!(sender_balance, 1_000_000); // At least the locked amount will be returned. + assert_lt!(sender_balance, 501_000_000); // Sender lost 500_000_000 + gas fee. assert_eq!( - 1_000_000_000, + 500_000_000, h.read_aptos_balance(recipient_0.address()) + h.read_aptos_balance(recipient_1.address()) ); } diff --git a/aptos-move/e2e-move-tests/src/tests/rotate_auth_key.rs b/aptos-move/e2e-move-tests/src/tests/rotate_auth_key.rs index 9559ab0a89b84..ed8e14c4e0e60 100644 --- a/aptos-move/e2e-move-tests/src/tests/rotate_auth_key.rs +++ b/aptos-move/e2e-move-tests/src/tests/rotate_auth_key.rs @@ -230,10 +230,7 @@ pub fn verify_originating_address( parse_struct_tag("0x1::account::OriginatingAddress").unwrap(), ) .unwrap(); - let state_key = &StateKey::table_item( - originating_address_handle, - AccountAddress::from_bytes(auth_key).unwrap().to_vec(), - ); + let state_key = &StateKey::table_item(&originating_address_handle, &auth_key); // Verify that the value in the address redirection table is expected let result = harness.read_state_value_bytes(state_key).unwrap(); assert_eq!(result, expected_address.to_vec()); diff --git a/aptos-move/e2e-move-tests/src/tests/simple_defi.rs b/aptos-move/e2e-move-tests/src/tests/simple_defi.rs index 1adc8067aae19..c2f04fbc51bdb 100644 --- a/aptos-move/e2e-move-tests/src/tests/simple_defi.rs +++ b/aptos-move/e2e-move-tests/src/tests/simple_defi.rs @@ -7,11 +7,11 @@ use aptos_framework::BuildOptions; use aptos_language_e2e_tests::account::Account; use aptos_types::{ account_address::{create_resource_address, AccountAddress}, - account_config::CoinStoreResource, transaction::{EntryFunction, TransactionPayload}, }; use move_core_types::{ident_str, language_storage::ModuleId, parser::parse_struct_tag}; use serde::{Deserialize, Serialize}; +use std::str::FromStr; #[derive(Serialize, Deserialize)] struct ModuleData { @@ -20,8 +20,9 @@ struct ModuleData { mint_cap: Vec, // placeholder for mint capability } -const APTOS_COIN_STRUCT_STRING: &str = "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>"; -const CHLOE_COIN_STRUCT_STRING: &str ="0x1::coin::CoinStore<0xc3bb8488ab1a5815a9d543d7e41b0e0df46a7396f89b22821f07a4362f75ddc5::simple_defi::ChloesCoin>"; +const APTOS_COIN_STRUCT_STRING: &str = "0x1::aptos_coin::AptosCoin"; +const CHLOE_COIN_STRUCT_STRING: &str = + "0xc3bb8488ab1a5815a9d543d7e41b0e0df46a7396f89b22821f07a4362f75ddc5::simple_defi::ChloesCoin"; const EXCHANGE_FROM_FUNCTION: &str = "exchange_from_entry"; const EXCHANGE_TO_FUNCTION: &str = "exchange_to_entry"; @@ -74,8 +75,8 @@ fn exchange_e2e_test() { // verify that exchange_to() and exchange_from() are working properly let test_user_account = h.new_account_with_balance_and_sequence_number(20, 10); - assert_coin_store_balance( - &h, + assert_coin_balance( + &mut h, test_user_account.address(), APTOS_COIN_STRUCT_STRING, 20, @@ -83,40 +84,58 @@ fn exchange_e2e_test() { // swap from 5 aptos coins to 5 chloe's coins run_exchange_function(&mut h, &test_user_account, EXCHANGE_TO_FUNCTION, 5, 10); - assert_coin_store_balance( - &h, + assert_coin_balance( + &mut h, test_user_account.address(), APTOS_COIN_STRUCT_STRING, 15, ); - assert_coin_store_balance(&h, test_user_account.address(), CHLOE_COIN_STRUCT_STRING, 5); - assert_coin_store_balance(&h, &resource_address, APTOS_COIN_STRUCT_STRING, 5); - assert_coin_store_balance(&h, &resource_address, CHLOE_COIN_STRUCT_STRING, 0); + assert_coin_balance( + &mut h, + test_user_account.address(), + CHLOE_COIN_STRUCT_STRING, + 5, + ); + assert_coin_balance(&mut h, &resource_address, APTOS_COIN_STRUCT_STRING, 5); + assert_coin_balance(&mut h, &resource_address, CHLOE_COIN_STRUCT_STRING, 0); // swap to 3 aptos coins from 3 chloe's aptos coins run_exchange_function(&mut h, &test_user_account, EXCHANGE_FROM_FUNCTION, 3, 11); - assert_coin_store_balance( - &h, + assert_coin_balance( + &mut h, test_user_account.address(), APTOS_COIN_STRUCT_STRING, 18, ); - assert_coin_store_balance(&h, test_user_account.address(), CHLOE_COIN_STRUCT_STRING, 2); - assert_coin_store_balance(&h, &resource_address, APTOS_COIN_STRUCT_STRING, 2); - assert_coin_store_balance(&h, &resource_address, CHLOE_COIN_STRUCT_STRING, 0); + assert_coin_balance( + &mut h, + test_user_account.address(), + CHLOE_COIN_STRUCT_STRING, + 2, + ); + assert_coin_balance(&mut h, &resource_address, APTOS_COIN_STRUCT_STRING, 2); + assert_coin_balance(&mut h, &resource_address, CHLOE_COIN_STRUCT_STRING, 0); } /// check the coin store balance of `struct_tag_string` CoinType at the given `address` is the same as the `expected_coin_amount` -fn assert_coin_store_balance( - h: &MoveHarness, +fn assert_coin_balance( + h: &mut MoveHarness, address: &AccountAddress, struct_tag_string: &str, expected_coin_amount: u64, ) { - let coin_store_balance = h - .read_resource::(address, parse_struct_tag(struct_tag_string).unwrap()) + let bytes = h + .execute_view_function( + str::parse("0x1::coin::balance").unwrap(), + vec![move_core_types::language_storage::TypeTag::from_str(struct_tag_string).unwrap()], + vec![address.to_vec()], + ) + .values + .unwrap() + .pop() .unwrap(); - assert_eq!(coin_store_balance.coin(), expected_coin_amount); + let balance = bcs::from_bytes::(bytes.as_slice()).unwrap(); + assert_eq!(balance, expected_coin_amount); } /// run the specified exchange function and check if it runs successfully diff --git a/aptos-move/e2e-move-tests/src/tests/stake.rs b/aptos-move/e2e-move-tests/src/tests/stake.rs index bc4490a3eeccf..14dd0afad42e3 100644 --- a/aptos-move/e2e-move-tests/src/tests/stake.rs +++ b/aptos-move/e2e-move-tests/src/tests/stake.rs @@ -189,6 +189,7 @@ fn test_staking_rewards() { harness.new_block_with_metadata(validator_1_address, vec![]); harness.new_block_with_metadata(validator_2_address, vec![]); + // Enable rewards rate decrease and change rewards config. In production it requires governance. let core_resources = harness.new_account_at(AccountAddress::from_hex_literal("0xA550C18").unwrap()); diff --git a/aptos-move/e2e-move-tests/src/tests/state_metadata.rs b/aptos-move/e2e-move-tests/src/tests/state_metadata.rs index 8bbdf03734e8f..b0aae4ab606bb 100644 --- a/aptos-move/e2e-move-tests/src/tests/state_metadata.rs +++ b/aptos-move/e2e-move-tests/src/tests/state_metadata.rs @@ -40,7 +40,7 @@ fn test_metadata_tracking() { harness .read_resource_metadata(&address2, coin_store.clone()) .unwrap(), - StateValueMetadata::none(), + StateValueMetadata::none() ); // Enable storage slot metadata tracking diff --git a/aptos-move/e2e-move-tests/src/tests/transaction_context.data/pack/Move.toml b/aptos-move/e2e-move-tests/src/tests/transaction_context.data/pack/Move.toml new file mode 100644 index 0000000000000..44ec4cd447c84 --- /dev/null +++ b/aptos-move/e2e-move-tests/src/tests/transaction_context.data/pack/Move.toml @@ -0,0 +1,10 @@ +[package] +name = "transaction_context_test" +version = "0.0.0" + +[addresses] +admin = "0x1" + +[dependencies] +AptosFramework = { local = "../../../../../framework/aptos-framework" } +AptosStdlib = { local = "../../../../../framework/aptos-stdlib" } diff --git a/aptos-move/e2e-move-tests/src/tests/transaction_context.data/pack/sources/transaction_context_test.move b/aptos-move/e2e-move-tests/src/tests/transaction_context.data/pack/sources/transaction_context_test.move new file mode 100644 index 0000000000000..0116d1035c9b0 --- /dev/null +++ b/aptos-move/e2e-move-tests/src/tests/transaction_context.data/pack/sources/transaction_context_test.move @@ -0,0 +1,144 @@ +module admin::transaction_context_test { + use std::option; + use std::signer; + use std::string::{Self, String}; + use std::vector; + use aptos_std::from_bcs; + use aptos_std::type_info; + use aptos_framework::transaction_context; + use aptos_framework::multisig_account; + + /// Since tests in e2e-move-tests/ can only call entry functions which don't have return values, we must store + /// the results we are interested in inside this (rather-artificial) resource, which we can read back in our + /// e2e-move-tests/ test. + struct TransactionContextStore has key { + sender: address, + secondary_signers: vector
, + gas_payer: address, + max_gas_amount: u64, + gas_unit_price: u64, + chain_id: u8, + account_address: address, + module_name: String, + function_name: String, + type_arg_names: vector, + args: vector>, + multisig_address: address, + } + + /// Called when the module is first deployed at address `signer`, which is supposed to be @admin (= 0x1). + fun init_module(sender: &signer) { + assert!(signer::address_of(sender) == @admin, 1); + // Initialize the global resource with the default values. + move_to(sender, + TransactionContextStore { + sender: @0x0, + secondary_signers: vector[], + gas_payer: @0x0, + max_gas_amount: 0, + gas_unit_price: 0, + chain_id: 0, + account_address: @0x0, + module_name: string::utf8(x""), + function_name: string::utf8(x""), + args: vector[], + type_arg_names: vector[], + multisig_address: @0x0, + } + ); + } + + public entry fun store_sender_from_native_txn_context(_s: &signer) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + store.sender = transaction_context::sender(); + } + + public entry fun store_secondary_signers_from_native_txn_context(_s: &signer) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + store.secondary_signers = transaction_context::secondary_signers(); + } + + public entry fun store_secondary_signers_from_native_txn_context_multi( + _s: &signer, + _s2: &signer + ) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + store.secondary_signers = transaction_context::secondary_signers(); + } + + public entry fun store_gas_payer_from_native_txn_context(_s: &signer) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + store.gas_payer = transaction_context::gas_payer(); + } + + public entry fun store_max_gas_amount_from_native_txn_context(_s: &signer) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + store.max_gas_amount = transaction_context::max_gas_amount(); + } + + public entry fun store_gas_unit_price_from_native_txn_context(_s: &signer) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + store.gas_unit_price = transaction_context::gas_unit_price(); + } + + public entry fun store_chain_id_from_native_txn_context(_s: &signer) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + store.chain_id = transaction_context::chain_id(); + } + + entry fun store_entry_function_payload_from_native_txn_context( + _s: &signer, + arg0: u64, + arg1: bool + ) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + let payload_opt = transaction_context::entry_function_payload(); + if (option::is_some(&payload_opt)) { + let payload = option::borrow(&payload_opt); + store.account_address = transaction_context::account_address(payload); + store.module_name = transaction_context::module_name(payload); + store.function_name = transaction_context::function_name(payload); + store.type_arg_names = transaction_context::type_arg_names(payload); + store.args = transaction_context::args(payload); + + // Check that the arguments are correct and can be parsed using `from_bcs`. + assert!(arg0 == from_bcs::to_u64(*vector::borrow(&store.args, 0)), 11); + assert!(arg1 == from_bcs::to_bool(*vector::borrow(&store.args, 1)), 12); + // Check that the type argument names are correct and matched to `type_info::type_name`. + assert!( + store.type_arg_names == vector[type_info::type_name(), type_info::type_name( + ), type_info::type_name()], + 13 + ); + } + } + + entry fun store_multisig_payload_from_native_txn_context(_s: &signer) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + let multisig_opt = transaction_context::multisig_payload(); + if (option::is_some(&multisig_opt)) { + let multisig = option::borrow(&multisig_opt); + store.multisig_address = transaction_context::multisig_address(multisig); + + let entry_opt = transaction_context::inner_entry_function_payload(multisig); + if (option::is_some(&entry_opt)) { + let entry = option::borrow(&entry_opt); + store.account_address = transaction_context::account_address(entry); + store.module_name = transaction_context::module_name(entry); + store.function_name = transaction_context::function_name(entry); + store.type_arg_names = transaction_context::type_arg_names(entry); + store.args = transaction_context::args(entry); + } + } + } + + entry fun prepare_multisig_payload_test(s: &signer, payload: vector) acquires TransactionContextStore { + let store = borrow_global_mut(@admin); + + let multisig_account = multisig_account::get_next_multisig_account_address(signer::address_of(s)); + multisig_account::create(s, 1, vector[], vector[]); + multisig_account::create_transaction(s, multisig_account, payload); + + store.multisig_address = multisig_account; + } +} diff --git a/aptos-move/e2e-move-tests/src/tests/transaction_context.rs b/aptos-move/e2e-move-tests/src/tests/transaction_context.rs new file mode 100644 index 0000000000000..eb2e1c04be260 --- /dev/null +++ b/aptos-move/e2e-move-tests/src/tests/transaction_context.rs @@ -0,0 +1,470 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{assert_success, tests::common, MoveHarness}; +use aptos_language_e2e_tests::account::{Account, TransactionBuilder}; +use aptos_types::{ + move_utils::MemberId, + on_chain_config::FeatureFlag, + transaction::{EntryFunction, MultisigTransactionPayload, TransactionPayload}, +}; +use bcs::to_bytes; +use move_core_types::{ + account_address::AccountAddress, + ident_str, + language_storage::{ModuleId, StructTag, TypeTag, CORE_CODE_ADDRESS}, + parser::parse_struct_tag, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug)] +struct TransactionContextStore { + sender: AccountAddress, + secondary_signers: Vec, + gas_payer: AccountAddress, + max_gas_amount: u64, + gas_unit_price: u64, + chain_id: u8, + account_address: AccountAddress, + module_name: String, + function_name: String, + type_arg_names: Vec, + args: Vec>, + multisig_address: AccountAddress, +} + +fn setup(harness: &mut MoveHarness) -> Account { + let path = common::test_dir_path("transaction_context.data/pack"); + + let account = harness.new_account_at(AccountAddress::ONE); + + assert_success!(harness.publish_package_cache_building(&account, &path)); + + account +} + +fn call_get_sender_from_native_txn_context( + harness: &mut MoveHarness, + account: &Account, +) -> AccountAddress { + let status = harness.run_entry_function( + account, + str::parse("0x1::transaction_context_test::store_sender_from_native_txn_context").unwrap(), + vec![], + vec![], + ); + + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + txn_ctx_store.sender +} + +fn call_get_secondary_signers_from_native_txn_context( + harness: &mut MoveHarness, + account: &Account, +) -> Vec { + let status = harness.run_entry_function( + account, + str::parse( + "0x1::transaction_context_test::store_secondary_signers_from_native_txn_context", + ) + .unwrap(), + vec![], + vec![], + ); + + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + txn_ctx_store.secondary_signers +} + +fn call_get_gas_payer_from_native_txn_context( + harness: &mut MoveHarness, + account: &Account, +) -> AccountAddress { + let status = harness.run_entry_function( + account, + str::parse("0x1::transaction_context_test::store_gas_payer_from_native_txn_context") + .unwrap(), + vec![], + vec![], + ); + + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + txn_ctx_store.gas_payer +} + +fn call_get_max_gas_amount_from_native_txn_context( + harness: &mut MoveHarness, + account: &Account, +) -> u64 { + let status = harness.run_entry_function( + account, + str::parse("0x1::transaction_context_test::store_max_gas_amount_from_native_txn_context") + .unwrap(), + vec![], + vec![], + ); + + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + txn_ctx_store.max_gas_amount +} + +fn call_get_gas_unit_price_from_native_txn_context( + harness: &mut MoveHarness, + account: &Account, +) -> u64 { + let status = harness.run_entry_function( + account, + str::parse("0x1::transaction_context_test::store_gas_unit_price_from_native_txn_context") + .unwrap(), + vec![], + vec![], + ); + + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + txn_ctx_store.gas_unit_price +} + +fn call_get_chain_id_from_native_txn_context(harness: &mut MoveHarness, account: &Account) -> u8 { + let status = harness.run_entry_function( + account, + str::parse("0x1::transaction_context_test::store_chain_id_from_native_txn_context") + .unwrap(), + vec![], + vec![], + ); + + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + txn_ctx_store.chain_id +} + +fn call_get_entry_function_payload_from_native_txn_context( + harness: &mut MoveHarness, + account: &Account, +) -> (AccountAddress, String, String, Vec, Vec>) { + let status = harness.run_entry_function( + account, + str::parse( + "0x1::transaction_context_test::store_entry_function_payload_from_native_txn_context", + ) + .unwrap(), + vec![ + TypeTag::U64, + TypeTag::Vector(Box::new(TypeTag::Address)), + TypeTag::Struct(Box::new(StructTag { + address: AccountAddress::from_hex_literal("0x1").unwrap(), + module: ident_str!("transaction_fee").to_owned(), + name: ident_str!("FeeStatement").to_owned(), + type_params: vec![], + })), + ], + vec![ + bcs::to_bytes(&7777777u64).unwrap(), + bcs::to_bytes(&true).unwrap(), + ], + ); + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + ( + txn_ctx_store.account_address, + txn_ctx_store.module_name, + txn_ctx_store.function_name, + txn_ctx_store.type_arg_names, + txn_ctx_store.args, + ) +} + +fn new_move_harness() -> MoveHarness { + MoveHarness::new_with_features( + vec![ + FeatureFlag::GAS_PAYER_ENABLED, + FeatureFlag::SPONSORED_AUTOMATIC_ACCOUNT_V1_CREATION, + FeatureFlag::TRANSACTION_CONTEXT_EXTENSION, + ], + vec![], + ) +} + +#[test] +fn test_transaction_context_sender() { + let mut harness = new_move_harness(); + let account = setup(&mut harness); + + let addr = call_get_sender_from_native_txn_context(&mut harness, &account); + assert_eq!(addr, AccountAddress::ONE); +} + +#[test] +fn test_transaction_context_max_gas_amount() { + let mut harness = new_move_harness(); + let account = setup(&mut harness); + + let max_gas_amount = call_get_max_gas_amount_from_native_txn_context(&mut harness, &account); + assert_eq!(max_gas_amount, 2000000); +} + +#[test] +fn test_transaction_context_gas_unit_price() { + let mut harness = new_move_harness(); + let account = setup(&mut harness); + + let max_gas_amount = call_get_gas_unit_price_from_native_txn_context(&mut harness, &account); + assert_eq!(max_gas_amount, 100); +} + +#[test] +fn test_transaction_context_chain_id() { + let mut harness = new_move_harness(); + let account = setup(&mut harness); + + let chain_id = call_get_chain_id_from_native_txn_context(&mut harness, &account); + assert_eq!(chain_id, 4); +} + +#[test] +fn test_transaction_context_gas_payer_as_sender() { + let mut harness = new_move_harness(); + let account = setup(&mut harness); + + let gas_payer = call_get_gas_payer_from_native_txn_context(&mut harness, &account); + assert_eq!(gas_payer, *account.address()); +} + +#[test] +fn test_transaction_context_secondary_signers_empty() { + let mut harness = new_move_harness(); + let account = setup(&mut harness); + + let secondary_signers = + call_get_secondary_signers_from_native_txn_context(&mut harness, &account); + assert_eq!(secondary_signers, vec![]); +} + +#[test] +fn test_transaction_context_gas_payer_as_separate_account() { + let mut harness = new_move_harness(); + + let alice = setup(&mut harness); + let bob = harness.new_account_with_balance_and_sequence_number(1000000, 0); + + let fun: MemberId = + str::parse("0x1::transaction_context_test::store_gas_payer_from_native_txn_context") + .unwrap(); + let MemberId { + module_id, + member_id: function_id, + } = fun; + let ty_args = vec![]; + let args = vec![]; + let payload = TransactionPayload::EntryFunction(EntryFunction::new( + module_id, + function_id, + ty_args, + args, + )); + let transaction = TransactionBuilder::new(alice.clone()) + .fee_payer(bob.clone()) + .payload(payload) + .sequence_number(harness.sequence_number(alice.address())) + .max_gas_amount(1_000_000) + .gas_unit_price(1) + .sign_fee_payer(); + + let output = harness.run_raw(transaction); + assert_success!(*output.status()); + + let txn_ctx_store = harness + .read_resource::( + alice.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + let gas_payer = txn_ctx_store.gas_payer; + assert_eq!(gas_payer, *bob.address()); +} + +#[test] +fn test_transaction_context_secondary_signers() { + let mut harness = new_move_harness(); + + let alice = setup(&mut harness); + let bob = harness.new_account_with_balance_and_sequence_number(1000000, 0); + + let fun: MemberId = str::parse( + "0x1::transaction_context_test::store_secondary_signers_from_native_txn_context_multi", + ) + .unwrap(); + let MemberId { + module_id, + member_id: function_id, + } = fun; + let ty_args = vec![]; + let args = vec![]; + let payload = TransactionPayload::EntryFunction(EntryFunction::new( + module_id, + function_id, + ty_args, + args, + )); + let transaction = TransactionBuilder::new(alice.clone()) + .secondary_signers(vec![bob.clone()]) + .payload(payload) + .sequence_number(harness.sequence_number(alice.address())) + .max_gas_amount(1_000_000) + .gas_unit_price(1) + .sign_multi_agent(); + + let output = harness.run_raw(transaction); + assert_success!(*output.status()); + + let txn_ctx_store = harness + .read_resource::( + alice.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + let secondary_signers = txn_ctx_store.secondary_signers; + assert_eq!(secondary_signers, vec![*bob.address()]); +} + +#[test] +fn test_transaction_context_entry_function_payload() { + let mut harness = new_move_harness(); + let account = setup(&mut harness); + + let (account_address, module_name, function_name, type_arg_names, args) = + call_get_entry_function_payload_from_native_txn_context(&mut harness, &account); + + assert_eq!(account_address, AccountAddress::ONE); + assert_eq!(module_name, "transaction_context_test"); + assert_eq!( + function_name, + "store_entry_function_payload_from_native_txn_context" + ); + assert_eq!(type_arg_names, vec![ + "u64", + "vector
", + "0x1::transaction_fee::FeeStatement" + ]); + assert_eq!(args, vec![ + bcs::to_bytes(&7777777u64).unwrap(), + bcs::to_bytes(&true).unwrap() + ]); +} + +#[test] +fn test_transaction_context_multisig_payload() { + let mut harness = new_move_harness(); + let account = setup(&mut harness); + + let multisig_transaction_payload = + MultisigTransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + CORE_CODE_ADDRESS, + ident_str!("transaction_context_test").to_owned(), + ), + ident_str!("store_multisig_payload_from_native_txn_context").to_owned(), + vec![], + vec![], + )); + + let serialized_multisig_transaction_payload = + bcs::to_bytes(&multisig_transaction_payload).unwrap(); + + let status = harness.run_entry_function( + &account, + str::parse("0x1::transaction_context_test::prepare_multisig_payload_test").unwrap(), + vec![], + vec![to_bytes(&serialized_multisig_transaction_payload).unwrap()], + ); + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + let multisig_address = txn_ctx_store.multisig_address; + + let status = harness.run_multisig( + &account, + txn_ctx_store.multisig_address, + Some(multisig_transaction_payload), + ); + assert!(status.status().unwrap().is_success()); + + let txn_ctx_store = harness + .read_resource::( + account.address(), + parse_struct_tag("0x1::transaction_context_test::TransactionContextStore").unwrap(), + ) + .unwrap(); + + assert_eq!(multisig_address, txn_ctx_store.multisig_address); + assert_eq!(txn_ctx_store.account_address, AccountAddress::ONE); + assert_eq!(txn_ctx_store.module_name, "transaction_context_test"); + assert_eq!( + txn_ctx_store.function_name, + "store_multisig_payload_from_native_txn_context" + ); + assert!(txn_ctx_store.type_arg_names.is_empty()); + assert!(txn_ctx_store.args.is_empty()); +} diff --git a/aptos-move/e2e-move-tests/src/tests/transaction_fee.rs b/aptos-move/e2e-move-tests/src/tests/transaction_fee.rs index 0e4074d6caa84..5f134c35ff841 100644 --- a/aptos-move/e2e-move-tests/src/tests/transaction_fee.rs +++ b/aptos-move/e2e-move-tests/src/tests/transaction_fee.rs @@ -131,7 +131,7 @@ impl TestUniverse { } /// Returns the total supply of AptosCoin in the universe. - pub fn read_total_supply(&self) -> u128 { + pub fn read_total_supply(&mut self) -> u128 { self.harness.executor.read_coin_supply().unwrap() } } diff --git a/aptos-move/e2e-tests/Cargo.toml b/aptos-move/e2e-tests/Cargo.toml index b299bdc322ebf..220682233053d 100644 --- a/aptos-move/e2e-tests/Cargo.toml +++ b/aptos-move/e2e-tests/Cargo.toml @@ -41,6 +41,7 @@ move-command-line-common = { workspace = true } move-core-types = { workspace = true, features = ["fuzzing"] } move-ir-compiler = { workspace = true } move-model = { workspace = true } +move-vm-runtime = { workspace = true } move-vm-types = { workspace = true } num_cpus = { workspace = true } once_cell = { workspace = true } diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__create_account__create_account.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__create_account__create_account.exp index d5cc88917143a..f6373c4f18a06 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__create_account__create_account.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__create_account__create_account.exp @@ -5,25 +5,16 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xa550c18, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(201304972f9242cbc3528a1e286323471ab891baa37e0053b85651693a79854a000100000000000000040000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a550c1800000000000000000100000000000000000000000000000000000000000000000000000000000000000000000a550c180000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Creation(00000000000000000000000000000000000200000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000300000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Creation(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000000000000000040000000000000001000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xa550c18, path: "Resource(0x1::account::Account)" }: Modification(201304972f9242cbc3528a1e286323471ab891baa37e0053b85651693a79854a000100000000000000040000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a550c1800000000000000000100000000000000000000000000000000000000000000000000000000000000000000000a550c180000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Creation(00000000000000000000000000000000000200000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000300000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Creation(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000000000000000040000000000000001000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), ), events: [ ContractEvent { key: EventKey { creation_number: 0, account_address: f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1 }, index: 0, type: Struct(StructTag { address: 0000000000000000000000000000000000000000000000000000000000000001, module: Identifier("account"), name: Identifier("CoinRegisterEvent"), type_params: [] }), event_data: "00000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e" }, - ModuleEvent { type: Struct(StructTag { address: 0000000000000000000000000000000000000000000000000000000000000001, module: Identifier("transaction_fee"), name: Identifier("FeeStatement"), type_params: [] }), event_data: "05000000000000000400000000000000010000000000000000000000000000000000000000000000" }, + ModuleEvent { type: Struct(StructTag { address: 0000000000000000000000000000000000000000000000000000000000000001, module: Identifier("transaction_fee"), name: Identifier("FeeStatement"), type_params: [] }), event_data: "05000000000000000400000000000000020000000000000000000000000000000000000000000000" }, ], gas_used: 5, status: Keep( diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__borrow_after_move.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__borrow_after_move.exp index e6c0c18cb2758..1eabebbed04cc 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__borrow_after_move.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__borrow_after_move.exp @@ -5,10 +5,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10c00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10c00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -46,14 +43,8 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10d00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }, - hash: OnceCell(Uninit), - }: Creation(0300000000000000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10d00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }: Creation(0300000000000000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), @@ -76,10 +67,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10e00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10e00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -102,14 +90,8 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10f00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }, - hash: OnceCell(Uninit), - }: Deletion(metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10f00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }: Deletion(metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), @@ -128,10 +110,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11000000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11000000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__change_after_move.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__change_after_move.exp index 118ebf1174c29..9ad2805aa231b 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__change_after_move.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__change_after_move.exp @@ -5,10 +5,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10c00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10c00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -46,14 +43,8 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10d00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }, - hash: OnceCell(Uninit), - }: Creation(0300000000000000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10d00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }: Creation(0300000000000000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), @@ -76,10 +67,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10e00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10e00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -102,14 +90,8 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10f00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }, - hash: OnceCell(Uninit), - }: Deletion(metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10f00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }: Deletion(metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), @@ -128,10 +110,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11000000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11000000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -169,10 +148,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11100000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11100000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__move_from_across_blocks.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__move_from_across_blocks.exp index aacdb1653ada8..6de90c635c1b9 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__move_from_across_blocks.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__data_store__move_from_across_blocks.exp @@ -5,10 +5,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10c00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10c00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -46,14 +43,8 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10d00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }, - hash: OnceCell(Uninit), - }: Creation(0300000000000000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10d00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }: Creation(0300000000000000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), @@ -76,10 +67,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10e00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10e00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -102,14 +90,8 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10f00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }, - hash: OnceCell(Uninit), - }: Deletion(metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10f00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }: Deletion(metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), @@ -132,10 +114,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11000000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11000000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -173,10 +152,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11100000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11100000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), @@ -214,14 +190,8 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11200000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }, - hash: OnceCell(Uninit), - }: Creation(0300000000000000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11200000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }: Creation(0300000000000000, metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), @@ -244,14 +214,8 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11300000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }, - hash: OnceCell(Uninit), - }: Deletion(metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11300000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1::M::T1)" }: Deletion(metadata:StateValueMetadata { inner: Some(StateValueMetadataInner { slot_deposit: 0, bytes_deposit: 0, creation_time_usecs: 0 }) }), }, }, ), @@ -270,10 +234,7 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11400000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe11400000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_bad_sig_function_dep.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_bad_sig_function_dep.exp index 12eb0ef148b29..0f69aa5174cc5 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_bad_sig_function_dep.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_bad_sig_function_dep.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_code_unverifiable.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_code_unverifiable.exp index 8e8ceb72e64bf..4d9befac68311 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_code_unverifiable.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_code_unverifiable.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_nested_type_argument_module_does_not_exist.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_nested_type_argument_module_does_not_exist.exp index c3535520f68f4..c0dd583b20f72 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_nested_type_argument_module_does_not_exist.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_nested_type_argument_module_does_not_exist.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_non_existing_function_dep.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_non_existing_function_dep.exp index 24be6e9bb0b29..f1196b6f09516 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_non_existing_function_dep.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_non_existing_function_dep.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_none_existing_module_dep.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_none_existing_module_dep.exp index c3535520f68f4..c0dd583b20f72 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_none_existing_module_dep.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_none_existing_module_dep.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_type_argument_module_does_not_exist.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_type_argument_module_does_not_exist.exp index c3535520f68f4..c0dd583b20f72 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_type_argument_module_does_not_exist.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__scripts__script_type_argument_module_does_not_exist.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_arbitrary_script_execution.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_arbitrary_script_execution.exp index 6dbe2d79e9a78..12d0d8c5080d8 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_arbitrary_script_execution.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_arbitrary_script_execution.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_script_dependency_fails_verification.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_script_dependency_fails_verification.exp index 20cae02d45aae..c9605b25dac66 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_script_dependency_fails_verification.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_script_dependency_fails_verification.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_script_transitive_dependency_fails_verification.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_script_transitive_dependency_fails_verification.exp index 20cae02d45aae..c9605b25dac66 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_script_transitive_dependency_fails_verification.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_script_transitive_dependency_fails_verification.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_type_tag_dependency_fails_verification.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_type_tag_dependency_fails_verification.exp index 20cae02d45aae..c9605b25dac66 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_type_tag_dependency_fails_verification.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_type_tag_dependency_fails_verification.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_type_tag_transitive_dependency_fails_verification.exp b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_type_tag_transitive_dependency_fails_verification.exp index 20cae02d45aae..c9605b25dac66 100644 --- a/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_type_tag_transitive_dependency_fails_verification.exp +++ b/aptos-move/e2e-tests/goldens/language_e2e_testsuite__tests__verify_txn__test_type_tag_transitive_dependency_fails_verification.exp @@ -5,18 +5,9 @@ Ok( WriteSetV0( WriteSetMut { write_set: { - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }, - hash: OnceCell(Uninit), - }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }, - hash: OnceCell(Uninit), - }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), - StateKey { - inner: TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }, - hash: OnceCell(Uninit), - }: Modification(fce0f505000000000100000000000000, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>)" }: Modification(3d420f00000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, metadata:StateValueMetadata { inner: None }), + StateKey::AccessPath { address: 0xf5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe1, path: "Resource(0x1::account::Account)" }: Modification(20f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10b00000000000000000000000000000000000000000000000000000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe100000000000000000100000000000000f5b9d6f01a99e74c790e2f330c092fa05455a8193f1dfc1b113ecc54d067afe10000, metadata:StateValueMetadata { inner: None }), + StateKey::TableItem { handle: 1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca, key: 0619dc29a0aac8fa146714058e8dd6d2d0f3bdf5f6331907bf91f3acd81e6935 }: Modification(3c230506000000000100000000000000, metadata:StateValueMetadata { inner: None }), }, }, ), diff --git a/aptos-move/e2e-tests/src/account.rs b/aptos-move/e2e-tests/src/account.rs index e7dade6d44de5..0a3c5d8ad9c2f 100644 --- a/aptos-move/e2e-tests/src/account.rs +++ b/aptos-move/e2e-tests/src/account.rs @@ -47,6 +47,13 @@ impl AccountPublicKey { AccountPublicKey::Keyless(_) => None, } } + + pub fn as_keyless(&self) -> Option { + match self { + AccountPublicKey::Keyless(pk) => Some(pk.clone()), + AccountPublicKey::Ed25519(_) => None, + } + } } /// Details about a Aptos account. @@ -496,11 +503,11 @@ impl AccountData { pub fn to_writeset(&self) -> WriteSet { let write_set = vec![ ( - StateKey::access_path(self.make_account_access_path()), + StateKey::resource_typed::(self.address()).unwrap(), WriteOp::legacy_modification(self.to_bytes().into()), ), ( - StateKey::access_path(self.make_coin_store_access_path()), + StateKey::resource_typed::(self.address()).unwrap(), WriteOp::legacy_modification(self.coin_store.to_bytes().into()), ), ]; diff --git a/aptos-move/e2e-tests/src/data_store.rs b/aptos-move/e2e-tests/src/data_store.rs index 94bf4e8da675e..7113f7b704b4b 100644 --- a/aptos-move/e2e-tests/src/data_store.rs +++ b/aptos-move/e2e-tests/src/data_store.rs @@ -6,7 +6,6 @@ use crate::account::AccountData; use aptos_types::{ - access_path::AccessPath, account_config::CoinInfoResource, state_store::{ errors::StateviewError, in_memory_state_view::InMemoryStateView, state_key::StateKey, @@ -106,7 +105,7 @@ impl FakeDataStore { /// Adds CoinInfo to this data store. pub fn add_coin_info(&mut self) { let coin_info = CoinInfoResource::random(u128::MAX); - let write_set = coin_info.to_writeset().expect("access path in test"); + let write_set = coin_info.to_writeset(0).expect("access path in test"); self.add_write_set(&write_set) } @@ -114,9 +113,8 @@ impl FakeDataStore { /// /// Does not do any sort of verification on the module. pub fn add_module(&mut self, module_id: &ModuleId, blob: Vec) { - let access_path = AccessPath::from(module_id); self.set( - StateKey::access_path(access_path), + StateKey::module_id(module_id), StateValue::new_legacy(blob.into()), ); } diff --git a/aptos-move/e2e-tests/src/executor.rs b/aptos-move/e2e-tests/src/executor.rs index 58b15eaabde79..9d716a443175f 100644 --- a/aptos-move/e2e-tests/src/executor.rs +++ b/aptos-move/e2e-tests/src/executor.rs @@ -27,7 +27,6 @@ use aptos_gas_schedule::{ use aptos_keygen::KeyGen; use aptos_memory_usage_tracker::MemoryTrackedGasMeter; use aptos_types::{ - access_path::AccessPath, account_config::{ new_block_event_key, AccountResource, CoinInfoResource, CoinStoreResource, NewBlockEvent, CORE_CODE_ADDRESS, @@ -38,6 +37,7 @@ use aptos_types::{ block_metadata::BlockMetadata, chain_id::ChainId, contract_event::ContractEvent, + move_utils::MemberId, on_chain_config::{ AptosVersion, FeatureFlag, Features, OnChainConfig, TimedFeatureOverride, TimedFeaturesBuilder, ValidatorSet, @@ -71,6 +71,7 @@ use move_core_types::{ language_storage::{ModuleId, TypeTag}, move_resource::MoveResource, }; +use move_vm_runtime::module_traversal::{TraversalContext, TraversalStorage}; use move_vm_types::gas::UnmeteredGasMeter; use serde::Serialize; use std::{ @@ -79,6 +80,7 @@ use std::{ fs::{self, OpenOptions}, io::Write, path::{Path, PathBuf}, + str::FromStr, sync::{Arc, Mutex}, time::Instant, }; @@ -369,7 +371,22 @@ impl FakeExecutor { /// Adds an account to this executor's data store. pub fn add_account_data(&mut self, account_data: &AccountData) { - self.data_store.add_account_data(account_data) + self.data_store.add_account_data(account_data); + let new_added_supply = account_data.balance(); + // When a new account data with balance is initialized. The total_supply should be updated + // correspondingly to be consistent with the global state. + // if new_added_supply = 0, it is a noop. + if new_added_supply != 0 { + let coin_info_resource = self + .read_coin_info_resource() + .expect("coin info must exist in data store"); + let old_supply = self.read_coin_supply().unwrap(); + self.data_store.add_write_set( + &coin_info_resource + .to_writeset(old_supply + (new_added_supply as u128)) + .unwrap(), + ) + } } /// Adds coin info to this executor's data store. @@ -390,12 +407,12 @@ impl FakeExecutor { } pub fn read_resource(&self, addr: &AccountAddress) -> Option { - let ap = - AccessPath::resource_access_path(*addr, T::struct_tag()).expect("access path in test"); - let data_blob = - TStateView::get_state_value_bytes(&self.data_store, &StateKey::access_path(ap)) - .expect("account must exist in data store") - .unwrap_or_else(|| panic!("Can't fetch {} resource for {}", T::STRUCT_NAME, addr)); + let data_blob = TStateView::get_state_value_bytes( + &self.data_store, + &StateKey::resource_typed::(addr).expect("failed to create StateKey"), + ) + .expect("account must exist in data store") + .unwrap_or_else(|| panic!("Can't fetch {} resource for {}", T::STRUCT_NAME, addr)); bcs::from_bytes(&data_blob).ok() } @@ -414,21 +431,21 @@ impl FakeExecutor { } /// Reads supply from CoinInfo resource value from this executor's data store. - pub fn read_coin_supply(&self) -> Option { - self.read_coin_info_resource() - .expect("coin info must exist in data store") - .supply() - .as_ref() - .map(|o| match o.aggregator.as_ref() { - Some(aggregator) => { - let state_key = aggregator.state_key(); - let value_bytes = self - .read_state_value_bytes(&state_key) - .expect("aggregator value must exist in data store"); - bcs::from_bytes(&value_bytes).unwrap() - }, - None => o.integer.as_ref().unwrap().value, - }) + pub fn read_coin_supply(&mut self) -> Option { + let bytes = self + .execute_view_function( + str::parse("0x1::coin::supply").unwrap(), + vec![move_core_types::language_storage::TypeTag::from_str( + "0x1::aptos_coin::AptosCoin", + ) + .unwrap()], + vec![], + ) + .values + .unwrap() + .pop() + .unwrap(); + bcs::from_bytes::>(bytes.as_slice()).unwrap() } /// Reads the CoinInfo resource value from this executor's data store. @@ -866,7 +883,7 @@ impl FakeExecutor { let mut i = 0; let mut times = Vec::new(); while i < iterations { - let mut session = vm.new_session(&resolver, SessionId::void()); + let mut session = vm.new_session(&resolver, SessionId::void(), None); // load function name into cache to ensure cache is hot let _ = session.load_function(module, &Self::name(function_name), &type_params.clone()); @@ -904,6 +921,7 @@ impl FakeExecutor { }; let start = Instant::now(); + let storage = TraversalStorage::new(); // Not sure how to create a common type for both. Box doesn't work for some reason. let result = match gas_meter_type { GasMeterType::RegularGasMeter => session.execute_function_bypass_visibility( @@ -912,6 +930,7 @@ impl FakeExecutor { ty, arg, regular.as_mut().unwrap(), + &mut TraversalContext::new(&storage), ), GasMeterType::UnmeteredGasMeter => session.execute_function_bypass_visibility( module, @@ -919,6 +938,7 @@ impl FakeExecutor { ty, arg, unmetered.as_mut().unwrap(), + &mut TraversalContext::new(&storage), ), }; let elapsed = start.elapsed(); @@ -979,11 +999,12 @@ impl FakeExecutor { /*aggregator_v2_type_tagging=*/ false, ) .unwrap(); - let mut session = vm.new_session(&resolver, SessionId::void()); + let mut session = vm.new_session(&resolver, SessionId::void(), None); let fun_name = Self::name(function_name); let should_error = fun_name.clone().into_string().ends_with(POSTFIX); + let storage = TraversalStorage::new(); let result = session.execute_function_bypass_visibility( module, &fun_name, @@ -1000,6 +1021,7 @@ impl FakeExecutor { // coeff_buffer: BTreeMap::new(), shared_buffer: Arc::clone(&a1), }), + &mut TraversalContext::new(&storage), ); if let Err(err) = result { if !should_error { @@ -1053,7 +1075,8 @@ impl FakeExecutor { false, ) .unwrap(); - let mut session = vm.new_session(&resolver, SessionId::void()); + let mut session = vm.new_session(&resolver, SessionId::void(), None); + let storage = TraversalStorage::new(); session .execute_function_bypass_visibility( module_id, @@ -1061,6 +1084,7 @@ impl FakeExecutor { type_params, args, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&storage), ) .unwrap_or_else(|e| { panic!( @@ -1133,7 +1157,7 @@ impl FakeExecutor { false, ) .unwrap(); - let mut session = vm.new_session(state_view, SessionId::void()); + let mut session = vm.new_session(state_view, SessionId::void(), None); let function = session.load_function(entry_fn.module(), entry_fn.function(), entry_fn.ty_args())?; let args = verifier::transaction_arg_validation::validate_combine_signer_and_txn_args( @@ -1143,6 +1167,7 @@ impl FakeExecutor { &function, struct_constructors, )?; + let storage = TraversalStorage::new(); session .execute_entry_function( entry_fn.module(), @@ -1150,6 +1175,7 @@ impl FakeExecutor { entry_fn.ty_args().to_vec(), args, &mut gas_meter, + &mut TraversalContext::new(&storage), ) .map_err(|e| e.into_vm_status())?; @@ -1188,7 +1214,8 @@ impl FakeExecutor { false, ) .unwrap(); - let mut session = vm.new_session(&resolver, SessionId::void()); + let mut session = vm.new_session(&resolver, SessionId::void(), None); + let storage = TraversalStorage::new(); session .execute_function_bypass_visibility( &Self::module(module_name), @@ -1196,6 +1223,7 @@ impl FakeExecutor { type_params, args, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&storage), ) .map_err(|e| e.into_vm_status())?; @@ -1214,16 +1242,15 @@ impl FakeExecutor { pub fn execute_view_function( &mut self, - module_id: ModuleId, - func_name: Identifier, + fun: MemberId, type_args: Vec, arguments: Vec>, ) -> ViewFunctionOutput { // No gas limit AptosVM::execute_view_function( self.get_state_view(), - module_id, - func_name, + fun.module_id, + fun.member_id, type_args, arguments, u64::MAX, diff --git a/aptos-move/e2e-testsuite/src/tests/verify_txn.rs b/aptos-move/e2e-testsuite/src/tests/verify_txn.rs index 9a7b2f54183a1..bbf2f2d59b4a3 100644 --- a/aptos-move/e2e-testsuite/src/tests/verify_txn.rs +++ b/aptos-move/e2e-testsuite/src/tests/verify_txn.rs @@ -304,9 +304,8 @@ fn verify_simple_payment() { // Test for a max_gas_amount that is insufficient to pay the minimum fee. // Find the minimum transaction gas units and subtract 1. - let mut gas_limit: Gas = txn_gas_params - .min_transaction_gas_units - .to_unit_round_up_with_params(&txn_gas_params); + let mut gas_limit: Gas = + (txn_gas_params.min_transaction_gas_units).to_unit_round_up_with_params(&txn_gas_params); if gas_limit > 0.into() { gas_limit = gas_limit.checked_sub(1.into()).unwrap(); diff --git a/aptos-move/framework/aptos-framework/Move.toml b/aptos-move/framework/aptos-framework/Move.toml index f53cbedc8bc9b..bdc7871934cd4 100644 --- a/aptos-move/framework/aptos-framework/Move.toml +++ b/aptos-move/framework/aptos-framework/Move.toml @@ -6,6 +6,7 @@ version = "1.0.0" std = "0x1" aptos_std = "0x1" aptos_framework = "0x1" +aptos_fungible_asset = "0xA" aptos_token = "0x3" core_resources = "0xA550C18" vm_reserved = "0x0" diff --git a/aptos-move/framework/aptos-framework/doc/aptos_account.md b/aptos-move/framework/aptos-framework/doc/aptos_account.md index 014edcdaa2cb1..6ca7144fe7065 100644 --- a/aptos-move/framework/aptos-framework/doc/aptos_account.md +++ b/aptos-move/framework/aptos-framework/doc/aptos_account.md @@ -375,9 +375,9 @@ This would create the recipient account first and register it to receive the Coi if (!account::exists_at(to)) { create_account(to); spec { - assert coin::is_account_registered<AptosCoin>(to); + assert coin::spec_is_account_registered<AptosCoin>(to); assume aptos_std::type_info::type_of<CoinType>() == aptos_std::type_info::type_of<AptosCoin>() ==> - coin::is_account_registered<CoinType>(to); + coin::spec_is_account_registered<CoinType>(to); }; }; if (!coin::is_account_registered<CoinType>(to)) { @@ -629,10 +629,9 @@ Limit the address of auth_key is not @vm_reserved / @aptos_framework / @aptos_to
// This enforces high-level requirement 1:
+pragma aborts_if_is_partial;
 include CreateAccountAbortsIf;
 ensures exists<account::Account>(auth_key);
-// This enforces high-level requirement 2:
-ensures exists<coin::CoinStore<AptosCoin>>(auth_key);
 
@@ -719,7 +718,8 @@ Limit the address of auth_key is not @vm_reserved / @aptos_framework / @aptos_to -
let account_addr_source = signer::address_of(source);
+
pragma verify = false;
+let account_addr_source = signer::address_of(source);
 requires account_addr_source != to;
 include CreateAccountTransferAbortsIf;
 include GuidAbortsIf<AptosCoin>;
@@ -774,9 +774,7 @@ Limit the address of auth_key is not @vm_reserved / @aptos_framework / @aptos_to
 aborts_if exists i in 0..len(recipients):
     account::exists_at(recipients[i]) && !exists<coin::CoinStore<CoinType>>(recipients[i]) && global<account::Account>(recipients[i]).guid_creation_num + 2 > MAX_U64;
 aborts_if exists i in 0..len(recipients):
-    !coin::is_account_registered<CoinType>(recipients[i]) && !type_info::spec_is_struct<CoinType>();
-aborts_if exists i in 0..len(recipients):
-    !coin::is_account_registered<CoinType>(recipients[i]) && !can_receive_direct_coin_transfers(recipients[i]);
+    !coin::spec_is_account_registered<CoinType>(recipients[i]) && !type_info::spec_is_struct<CoinType>();
 
@@ -792,7 +790,8 @@ Limit the address of auth_key is not @vm_reserved / @aptos_framework / @aptos_to -
let account_addr_source = signer::address_of(from);
+
pragma verify = false;
+let account_addr_source = signer::address_of(from);
 requires account_addr_source != to;
 include CreateAccountTransferAbortsIf;
 include WithdrawAbortsIf<CoinType>;
@@ -857,11 +856,9 @@ Limit the address of auth_key is not @vm_reserved / @aptos_framework / @aptos_to
 
 
schema RegistCoinAbortsIf<CoinType> {
     to: address;
-    aborts_if !coin::is_account_registered<CoinType>(to) && !type_info::spec_is_struct<CoinType>();
-    aborts_if exists<aptos_framework::account::Account>(to)
-        && !coin::is_account_registered<CoinType>(to) && !can_receive_direct_coin_transfers(to);
-    aborts_if type_info::type_of<CoinType>() != type_info::type_of<AptosCoin>()
-        && !coin::is_account_registered<CoinType>(to) && !can_receive_direct_coin_transfers(to);
+    aborts_if !coin::spec_is_account_registered<CoinType>(to) && !type_info::spec_is_struct<CoinType>();
+    aborts_if exists<aptos_framework::account::Account>(to);
+    aborts_if type_info::type_of<CoinType>() != type_info::type_of<AptosCoin>();
 }
 
@@ -899,7 +896,8 @@ Limit the address of auth_key is not @vm_reserved / @aptos_framework / @aptos_to -
include CreateAccountTransferAbortsIf;
+
pragma verify = false;
+include CreateAccountTransferAbortsIf;
 include GuidAbortsIf<CoinType>;
 include RegistCoinAbortsIf<CoinType>;
 let if_exist_coin = exists<coin::CoinStore<CoinType>>(to);
@@ -943,8 +941,9 @@ Check if the address existed.
 Check if the AptosCoin under the address existed.
 
 
-
aborts_if !account::exists_at(addr);
-aborts_if !coin::is_account_registered<AptosCoin>(addr);
+
pragma aborts_if_is_partial;
+aborts_if !account::exists_at(addr);
+aborts_if !coin::spec_is_account_registered<AptosCoin>(addr);
 
@@ -960,10 +959,7 @@ Check if the AptosCoin under the address existed. -
let addr = signer::address_of(account);
-include !exists<DirectTransferConfig>(addr) ==> account::NewEventHandleAbortsIf;
-// This enforces high-level requirement 4:
-ensures global<DirectTransferConfig>(addr).allow_arbitrary_coin_transfers == allow;
+
pragma verify = false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/aptos_governance.md b/aptos-move/framework/aptos-framework/doc/aptos_governance.md index 744fbddd4215f..820c973dba875 100644 --- a/aptos-move/framework/aptos-framework/doc/aptos_governance.md +++ b/aptos-move/framework/aptos-framework/doc/aptos_governance.md @@ -2824,7 +2824,7 @@ Address @aptos_framework must exist ApprovedExecutionHashes and GovernancePropos
pragma verify = false;
 aborts_if !system_addresses::is_aptos_framework_address(signer::address_of(aptos_framework));
 include reconfiguration_with_dkg::FinishRequirement {
-    account: aptos_framework
+    framework: aptos_framework
 };
 include stake::GetReconfigStartTimeRequirement;
 include transaction_fee::RequiresCollectedFeesPerValueLeqBlockAptosSupply;
@@ -2851,7 +2851,7 @@ Address @aptos_framework must exist ApprovedExecutionHashes and GovernancePropos
 
pragma verify = false;
 let address = signer::address_of(aptos_framework);
 include reconfiguration_with_dkg::FinishRequirement {
-    account: aptos_framework
+    framework: aptos_framework
 };
 
@@ -2901,7 +2901,7 @@ Address @aptos_framework must exist GovernanceConfig and GovernanceEvents. let addr = signer::address_of(aptos_framework); aborts_if addr != @aptos_framework; include reconfiguration_with_dkg::FinishRequirement { - account: aptos_framework + framework: aptos_framework }; include stake::GetReconfigStartTimeRequirement; include transaction_fee::RequiresCollectedFeesPerValueLeqBlockAptosSupply; diff --git a/aptos-move/framework/aptos-framework/doc/coin.md b/aptos-move/framework/aptos-framework/doc/coin.md index 122f05b40af9f..65b85eacfe199 100644 --- a/aptos-move/framework/aptos-framework/doc/coin.md +++ b/aptos-move/framework/aptos-framework/doc/coin.md @@ -15,12 +15,41 @@ This module provides the foundation for typesafe Coins. - [Struct `Deposit`](#0x1_coin_Deposit) - [Struct `WithdrawEvent`](#0x1_coin_WithdrawEvent) - [Struct `Withdraw`](#0x1_coin_Withdraw) +- [Struct `CoinEventHandleDeletion`](#0x1_coin_CoinEventHandleDeletion) +- [Struct `PairCreation`](#0x1_coin_PairCreation) +- [Resource `MigrationFlag`](#0x1_coin_MigrationFlag) - [Struct `MintCapability`](#0x1_coin_MintCapability) - [Struct `FreezeCapability`](#0x1_coin_FreezeCapability) - [Struct `BurnCapability`](#0x1_coin_BurnCapability) +- [Resource `CoinConversionMap`](#0x1_coin_CoinConversionMap) +- [Resource `PairedCoinType`](#0x1_coin_PairedCoinType) +- [Resource `PairedFungibleAssetRefs`](#0x1_coin_PairedFungibleAssetRefs) +- [Struct `MintRefReceipt`](#0x1_coin_MintRefReceipt) +- [Struct `TransferRefReceipt`](#0x1_coin_TransferRefReceipt) +- [Struct `BurnRefReceipt`](#0x1_coin_BurnRefReceipt) - [Resource `Ghost$supply`](#0x1_coin_Ghost$supply) - [Resource `Ghost$aggregate_supply`](#0x1_coin_Ghost$aggregate_supply) - [Constants](#@Constants_0) +- [Function `paired_metadata`](#0x1_coin_paired_metadata) +- [Function `create_coin_conversion_map`](#0x1_coin_create_coin_conversion_map) +- [Function `create_pairing`](#0x1_coin_create_pairing) +- [Function `is_apt`](#0x1_coin_is_apt) +- [Function `create_and_return_paired_metadata_if_not_exist`](#0x1_coin_create_and_return_paired_metadata_if_not_exist) +- [Function `ensure_paired_metadata`](#0x1_coin_ensure_paired_metadata) +- [Function `paired_coin`](#0x1_coin_paired_coin) +- [Function `coin_to_fungible_asset`](#0x1_coin_coin_to_fungible_asset) +- [Function `fungible_asset_to_coin`](#0x1_coin_fungible_asset_to_coin) +- [Function `assert_paired_metadata_exists`](#0x1_coin_assert_paired_metadata_exists) +- [Function `paired_mint_ref_exists`](#0x1_coin_paired_mint_ref_exists) +- [Function `get_paired_mint_ref`](#0x1_coin_get_paired_mint_ref) +- [Function `return_paired_mint_ref`](#0x1_coin_return_paired_mint_ref) +- [Function `paired_transfer_ref_exists`](#0x1_coin_paired_transfer_ref_exists) +- [Function `get_paired_transfer_ref`](#0x1_coin_get_paired_transfer_ref) +- [Function `return_paired_transfer_ref`](#0x1_coin_return_paired_transfer_ref) +- [Function `paired_burn_ref_exists`](#0x1_coin_paired_burn_ref_exists) +- [Function `get_paired_burn_ref`](#0x1_coin_get_paired_burn_ref) +- [Function `return_paired_burn_ref`](#0x1_coin_return_paired_burn_ref) +- [Function `borrow_paired_burn_ref`](#0x1_coin_borrow_paired_burn_ref) - [Function `initialize_supply_config`](#0x1_coin_initialize_supply_config) - [Function `allow_supply_upgrades`](#0x1_coin_allow_supply_upgrades) - [Function `initialize_aggregatable_coin`](#0x1_coin_initialize_aggregatable_coin) @@ -28,8 +57,13 @@ This module provides the foundation for typesafe Coins. - [Function `drain_aggregatable_coin`](#0x1_coin_drain_aggregatable_coin) - [Function `merge_aggregatable_coin`](#0x1_coin_merge_aggregatable_coin) - [Function `collect_into_aggregatable_coin`](#0x1_coin_collect_into_aggregatable_coin) +- [Function `calculate_amount_to_withdraw`](#0x1_coin_calculate_amount_to_withdraw) +- [Function `maybe_convert_to_fungible_store`](#0x1_coin_maybe_convert_to_fungible_store) +- [Function `migrate_to_fungible_store`](#0x1_coin_migrate_to_fungible_store) - [Function `coin_address`](#0x1_coin_coin_address) - [Function `balance`](#0x1_coin_balance) +- [Function `is_balance_at_least`](#0x1_coin_is_balance_at_least) +- [Function `coin_balance`](#0x1_coin_coin_balance) - [Function `is_coin_initialized`](#0x1_coin_is_coin_initialized) - [Function `is_coin_store_frozen`](#0x1_coin_is_coin_store_frozen) - [Function `is_account_registered`](#0x1_coin_is_account_registered) @@ -37,9 +71,11 @@ This module provides the foundation for typesafe Coins. - [Function `symbol`](#0x1_coin_symbol) - [Function `decimals`](#0x1_coin_decimals) - [Function `supply`](#0x1_coin_supply) +- [Function `coin_supply`](#0x1_coin_coin_supply) - [Function `burn`](#0x1_coin_burn) - [Function `burn_from`](#0x1_coin_burn_from) - [Function `deposit`](#0x1_coin_deposit) +- [Function `migrated_primary_fungible_store_exists`](#0x1_coin_migrated_primary_fungible_store_exists) - [Function `force_deposit`](#0x1_coin_force_deposit) - [Function `destroy_zero`](#0x1_coin_destroy_zero) - [Function `extract`](#0x1_coin_extract) @@ -60,10 +96,14 @@ This module provides the foundation for typesafe Coins. - [Function `destroy_freeze_cap`](#0x1_coin_destroy_freeze_cap) - [Function `destroy_mint_cap`](#0x1_coin_destroy_mint_cap) - [Function `destroy_burn_cap`](#0x1_coin_destroy_burn_cap) +- [Function `mint_internal`](#0x1_coin_mint_internal) +- [Function `burn_internal`](#0x1_coin_burn_internal) - [Specification](#@Specification_1) - [High-level Requirements](#high-level-req) - [Module-level Specification](#module-level-spec) - [Struct `AggregatableCoin`](#@Specification_1_AggregatableCoin) + - [Function `coin_to_fungible_asset`](#@Specification_1_coin_to_fungible_asset) + - [Function `fungible_asset_to_coin`](#@Specification_1_fungible_asset_to_coin) - [Function `initialize_supply_config`](#@Specification_1_initialize_supply_config) - [Function `allow_supply_upgrades`](#@Specification_1_allow_supply_upgrades) - [Function `initialize_aggregatable_coin`](#@Specification_1_initialize_aggregatable_coin) @@ -71,6 +111,7 @@ This module provides the foundation for typesafe Coins. - [Function `drain_aggregatable_coin`](#@Specification_1_drain_aggregatable_coin) - [Function `merge_aggregatable_coin`](#@Specification_1_merge_aggregatable_coin) - [Function `collect_into_aggregatable_coin`](#@Specification_1_collect_into_aggregatable_coin) + - [Function `maybe_convert_to_fungible_store`](#@Specification_1_maybe_convert_to_fungible_store) - [Function `coin_address`](#@Specification_1_coin_address) - [Function `balance`](#@Specification_1_balance) - [Function `is_coin_initialized`](#@Specification_1_is_coin_initialized) @@ -79,6 +120,7 @@ This module provides the foundation for typesafe Coins. - [Function `symbol`](#@Specification_1_symbol) - [Function `decimals`](#@Specification_1_decimals) - [Function `supply`](#@Specification_1_supply) + - [Function `coin_supply`](#@Specification_1_coin_supply) - [Function `burn`](#@Specification_1_burn) - [Function `burn_from`](#@Specification_1_burn_from) - [Function `deposit`](#@Specification_1_deposit) @@ -97,19 +139,27 @@ This module provides the foundation for typesafe Coins. - [Function `register`](#@Specification_1_register) - [Function `transfer`](#@Specification_1_transfer) - [Function `withdraw`](#@Specification_1_withdraw) + - [Function `mint_internal`](#@Specification_1_mint_internal) + - [Function `burn_internal`](#@Specification_1_burn_internal)
use 0x1::account;
 use 0x1::aggregator;
 use 0x1::aggregator_factory;
+use 0x1::create_signer;
 use 0x1::error;
 use 0x1::event;
 use 0x1::features;
+use 0x1::fungible_asset;
+use 0x1::guid;
+use 0x1::object;
 use 0x1::option;
 use 0x1::optional_aggregator;
+use 0x1::primary_fungible_store;
 use 0x1::signer;
 use 0x1::string;
 use 0x1::system_addresses;
+use 0x1::table;
 use 0x1::type_info;
 
@@ -331,6 +381,7 @@ Event emitted when some amount of a coin is deposited into an account. ## Struct `Deposit` +Module event emitted when some amount of a coin is deposited into an account.
#[event]
@@ -393,6 +444,7 @@ Event emitted when some amount of a coin is withdrawn from an account.
 
 ## Struct `Withdraw`
 
+Module event emitted when some amount of a coin is withdrawn from an account.
 
 
 
#[event]
@@ -421,6 +473,111 @@ Event emitted when some amount of a coin is withdrawn from an account.
 
 
 
+
+
+
+
+## Struct `CoinEventHandleDeletion`
+
+Module event emitted when the event handles related to coin store is deleted.
+
+
+
#[event]
+struct CoinEventHandleDeletion has drop, store
+
+ + + +
+Fields + + +
+
+event_handle_creation_address: address +
+
+ +
+
+deleted_deposit_event_handle_creation_number: u64 +
+
+ +
+
+deleted_withdraw_event_handle_creation_number: u64 +
+
+ +
+
+ + +
+ + + +## Struct `PairCreation` + +Module event emitted when a new pair of coin and fungible asset is created. + + +
#[event]
+struct PairCreation has drop, store
+
+ + + +
+Fields + + +
+
+coin_type: type_info::TypeInfo +
+
+ +
+
+fungible_asset_metadata_address: address +
+
+ +
+
+ + +
+ + + +## Resource `MigrationFlag` + +The flag the existence of which indicates the primary fungible store is created by the migration from CoinStore. + + +
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]
+struct MigrationFlag has key
+
+ + + +
+Fields + + +
+
+dummy_field: bool +
+
+ +
+
+ +
@@ -507,13 +664,14 @@ Capability required to burn coins. - + -## Resource `Ghost$supply` +## Resource `CoinConversionMap` +The mapping between coin and fungible asset. -
struct Ghost$supply<CoinType> has copy, drop, store, key
+
struct CoinConversionMap has key
 
@@ -524,7 +682,7 @@ Capability required to burn coins.
-v: num +coin_to_fungible_asset_map: table::Table<type_info::TypeInfo, object::Object<fungible_asset::Metadata>>
@@ -534,13 +692,15 @@ Capability required to burn coins. - + -## Resource `Ghost$aggregate_supply` +## Resource `PairedCoinType` +The paired coin type info stored in fungible asset metadata object. -
struct Ghost$aggregate_supply<CoinType> has copy, drop, store, key
+
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]
+struct PairedCoinType has key
 
@@ -551,7 +711,7 @@ Capability required to burn coins.
-v: num +type: type_info::TypeInfo
@@ -561,137 +721,206 @@ Capability required to burn coins. - + -## Constants +## Resource `PairedFungibleAssetRefs` +The refs of the paired fungible asset. - -Maximum possible aggregatable coin value. +
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]
+struct PairedFungibleAssetRefs has key
+
-
const MAX_U64: u128 = 18446744073709551615;
-
+
+Fields - +
+
+mint_ref_opt: option::Option<fungible_asset::MintRef> +
+
-Maximum possible coin supply. +
+
+transfer_ref_opt: option::Option<fungible_asset::TransferRef> +
+
+
+
+burn_ref_opt: option::Option<fungible_asset::BurnRef> +
+
-
const MAX_U128: u128 = 340282366920938463463374607431768211455;
-
+
+
+
- + -The value of aggregatable coin used for transaction fees redistribution does not fit in u64. +## Struct `MintRefReceipt` +The hot potato receipt for flash borrowing MintRef. -
const EAGGREGATABLE_COIN_VALUE_TOO_LARGE: u64 = 14;
+
+
struct MintRefReceipt
 
- +
+Fields -Address of account which is used to initialize a coin CoinType doesn't match the deployer of module +
+
+metadata: object::Object<fungible_asset::Metadata> +
+
+ +
+
-
const ECOIN_INFO_ADDRESS_MISMATCH: u64 = 1;
-
+
+ - +## Struct `TransferRefReceipt` -CoinType is already initialized as a coin +The hot potato receipt for flash borrowing TransferRef. -
const ECOIN_INFO_ALREADY_PUBLISHED: u64 = 2;
+
struct TransferRefReceipt
 
- +
+Fields -CoinType hasn't been initialized as a coin +
+
+metadata: object::Object<fungible_asset::Metadata> +
+
-
const ECOIN_INFO_NOT_PUBLISHED: u64 = 3;
-
+
+
+
- + -Name of the coin is too long +## Struct `BurnRefReceipt` +The hot potato receipt for flash borrowing BurnRef. -
const ECOIN_NAME_TOO_LONG: u64 = 12;
+
+
struct BurnRefReceipt
 
- +
+Fields -Deprecated. Account already has CoinStore registered for CoinType +
+
+metadata: object::Object<fungible_asset::Metadata> +
+
-
const ECOIN_STORE_ALREADY_PUBLISHED: u64 = 4;
-
+
+
+
- + -Account hasn't registered CoinStore for CoinType +## Resource `Ghost$supply` -
const ECOIN_STORE_NOT_PUBLISHED: u64 = 5;
+
+
struct Ghost$supply<CoinType> has copy, drop, store, key
 
- +
+Fields -Cannot upgrade the total supply of coins to different implementation. +
+
+v: num +
+
-
const ECOIN_SUPPLY_UPGRADE_NOT_SUPPORTED: u64 = 11;
-
+
+
+
- + -Symbol of the coin is too long +## Resource `Ghost$aggregate_supply` -
const ECOIN_SYMBOL_TOO_LONG: u64 = 13;
+
+
struct Ghost$aggregate_supply<CoinType> has copy, drop, store, key
 
- +
+Fields -Cannot destroy non-zero coins +
+
+v: num +
+
+ +
+
-
const EDESTRUCTION_OF_NONZERO_TOKEN: u64 = 7;
+
+
+ + + +## Constants + + + + +Maximum possible aggregatable coin value. + + +
const MAX_U64: u128 = 18446744073709551615;
 
- + -CoinStore is frozen. Coins cannot be deposited or withdrawn +Maximum possible coin supply. -
const EFROZEN: u64 = 10;
+
const MAX_U128: u128 = 340282366920938463463374607431768211455;
 
@@ -706,59 +935,949 @@ Not enough coins to complete transaction - + -Coin amount cannot be zero +The value of aggregatable coin used for transaction fees redistribution does not fit in u64. -
const EZERO_COIN_AMOUNT: u64 = 9;
+
const EAGGREGATABLE_COIN_VALUE_TOO_LARGE: u64 = 14;
 
- + +APT pairing is not eanbled yet. -
const MAX_COIN_NAME_LENGTH: u64 = 32;
+
const EAPT_PAIRING_IS_NOT_ENABLED: u64 = 28;
 
- + +The BurnRef does not exist. -
const MAX_COIN_SYMBOL_LENGTH: u64 = 10;
+
const EBURN_REF_NOT_FOUND: u64 = 25;
 
- - -## Function `initialize_supply_config` + -Publishes supply configuration. Initially, upgrading is not allowed. +The BurnRefReceipt does not match the BurnRef to be returned. -
public(friend) fun initialize_supply_config(aptos_framework: &signer)
+
const EBURN_REF_RECEIPT_MISMATCH: u64 = 24;
 
-
-Implementation + +The coin converison map is not created yet. -
public(friend) fun initialize_supply_config(aptos_framework: &signer) {
-    system_addresses::assert_aptos_framework(aptos_framework);
-    move_to(aptos_framework, SupplyConfig { allow_upgrades: false });
-}
+
+
const ECOIN_CONVERSION_MAP_NOT_FOUND: u64 = 27;
 
-
+ + +Address of account which is used to initialize a coin CoinType doesn't match the deployer of module + + +
const ECOIN_INFO_ADDRESS_MISMATCH: u64 = 1;
+
+ + + + + +CoinType is already initialized as a coin + + +
const ECOIN_INFO_ALREADY_PUBLISHED: u64 = 2;
+
+ + + + + +CoinType hasn't been initialized as a coin + + +
const ECOIN_INFO_NOT_PUBLISHED: u64 = 3;
+
+ + + + + +Name of the coin is too long + + +
const ECOIN_NAME_TOO_LONG: u64 = 12;
+
+ + + + + +Deprecated. Account already has CoinStore registered for CoinType + + +
const ECOIN_STORE_ALREADY_PUBLISHED: u64 = 4;
+
+ + + + + +Account hasn't registered CoinStore for CoinType + + +
const ECOIN_STORE_NOT_PUBLISHED: u64 = 5;
+
+ + + + + +Cannot upgrade the total supply of coins to different implementation. + + +
const ECOIN_SUPPLY_UPGRADE_NOT_SUPPORTED: u64 = 11;
+
+ + + + + +Symbol of the coin is too long + + +
const ECOIN_SYMBOL_TOO_LONG: u64 = 13;
+
+ + + + + +The feature of migration from coin to fungible asset is not enabled. + + +
const ECOIN_TO_FUNGIBLE_ASSET_FEATURE_NOT_ENABLED: u64 = 18;
+
+ + + + + +The coin type from the map does not match the calling function type argument. + + +
const ECOIN_TYPE_MISMATCH: u64 = 17;
+
+ + + + + +Cannot destroy non-zero coins + + +
const EDESTRUCTION_OF_NONZERO_TOKEN: u64 = 7;
+
+ + + + + +CoinStore is frozen. Coins cannot be deposited or withdrawn + + +
const EFROZEN: u64 = 10;
+
+ + + + + +The migration process from coin to fungible asset is not enabled yet. + + +
const EMIGRATION_FRAMEWORK_NOT_ENABLED: u64 = 26;
+
+ + + + + +The MintRef does not exist. + + +
const EMINT_REF_NOT_FOUND: u64 = 21;
+
+ + + + + +The MintRefReceipt does not match the MintRef to be returned. + + +
const EMINT_REF_RECEIPT_MISMATCH: u64 = 20;
+
+ + + + + +Error regarding paired coin type of the fungible asset metadata. + + +
const EPAIRED_COIN: u64 = 15;
+
+ + + + + +Error regarding paired fungible asset metadata of a coin type. + + +
const EPAIRED_FUNGIBLE_ASSET: u64 = 16;
+
+ + + + + +PairedFungibleAssetRefs resource does not exist. + + +
const EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND: u64 = 19;
+
+ + + + + +The TransferRef does not exist. + + +
const ETRANSFER_REF_NOT_FOUND: u64 = 23;
+
+ + + + + +The TransferRefReceipt does not match the TransferRef to be returned. + + +
const ETRANSFER_REF_RECEIPT_MISMATCH: u64 = 22;
+
+ + + + + + + +
const MAX_COIN_NAME_LENGTH: u64 = 32;
+
+ + + + + + + +
const MAX_COIN_SYMBOL_LENGTH: u64 = 10;
+
+ + + + + +## Function `paired_metadata` + +Get the paired fungible asset metadata object of a coin type. If not exist, return option::none(). + + +
#[view]
+public fun paired_metadata<CoinType>(): option::Option<object::Object<fungible_asset::Metadata>>
+
+ + + +
+Implementation + + +
public fun paired_metadata<CoinType>(): Option<Object<Metadata>> acquires CoinConversionMap {
+    if (exists<CoinConversionMap>(@aptos_framework) && features::coin_to_fungible_asset_migration_feature_enabled(
+    )) {
+        let map = &borrow_global<CoinConversionMap>(@aptos_framework).coin_to_fungible_asset_map;
+        let type = type_info::type_of<CoinType>();
+        if (table::contains(map, type)) {
+            return option::some(*table::borrow(map, type))
+        }
+    };
+    option::none()
+}
+
+ + + +
+ + + +## Function `create_coin_conversion_map` + + + +
public entry fun create_coin_conversion_map(aptos_framework: &signer)
+
+ + + +
+Implementation + + +
public entry fun create_coin_conversion_map(aptos_framework: &signer) {
+    system_addresses::assert_aptos_framework(aptos_framework);
+    if (!exists<CoinConversionMap>(@aptos_framework)) {
+        move_to(aptos_framework, CoinConversionMap {
+            coin_to_fungible_asset_map: table::new(),
+        })
+    };
+}
+
+ + + +
+ + + +## Function `create_pairing` + +Create APT pairing by passing AptosCoin. + + +
public entry fun create_pairing<CoinType>(aptos_framework: &signer)
+
+ + + +
+Implementation + + +
public entry fun create_pairing<CoinType>(
+    aptos_framework: &signer
+) acquires CoinConversionMap, CoinInfo {
+    system_addresses::assert_aptos_framework(aptos_framework);
+    create_and_return_paired_metadata_if_not_exist<CoinType>(true);
+}
+
+ + + +
+ + + +## Function `is_apt` + + + +
fun is_apt<CoinType>(): bool
+
+ + + +
+Implementation + + +
inline fun is_apt<CoinType>(): bool {
+    type_info::type_name<CoinType>() == string::utf8(b"0x1::aptos_coin::AptosCoin")
+}
+
+ + + +
+ + + +## Function `create_and_return_paired_metadata_if_not_exist` + + + +
fun create_and_return_paired_metadata_if_not_exist<CoinType>(allow_apt_creation: bool): object::Object<fungible_asset::Metadata>
+
+ + + +
+Implementation + + +
inline fun create_and_return_paired_metadata_if_not_exist<CoinType>(allow_apt_creation: bool): Object<Metadata> {
+    assert!(
+        features::coin_to_fungible_asset_migration_feature_enabled(),
+        error::invalid_state(EMIGRATION_FRAMEWORK_NOT_ENABLED)
+    );
+    assert!(exists<CoinConversionMap>(@aptos_framework), error::not_found(ECOIN_CONVERSION_MAP_NOT_FOUND));
+    let map = borrow_global_mut<CoinConversionMap>(@aptos_framework);
+    let type = type_info::type_of<CoinType>();
+    if (!table::contains(&map.coin_to_fungible_asset_map, type)) {
+        let is_apt = is_apt<CoinType>();
+        assert!(!is_apt || allow_apt_creation, error::invalid_state(EAPT_PAIRING_IS_NOT_ENABLED));
+        let metadata_object_cref =
+            if (is_apt) {
+                object::create_sticky_object_at_address(@aptos_framework, @aptos_fungible_asset)
+            } else {
+                object::create_sticky_object(coin_address<CoinType>())
+            };
+        primary_fungible_store::create_primary_store_enabled_fungible_asset(
+            &metadata_object_cref,
+            option::map(coin_supply<CoinType>(), |_| MAX_U128),
+            name<CoinType>(),
+            symbol<CoinType>(),
+            decimals<CoinType>(),
+            string::utf8(b""),
+            string::utf8(b""),
+        );
+
+        let metadata_object_signer = &object::generate_signer(&metadata_object_cref);
+        let type = type_info::type_of<CoinType>();
+        move_to(metadata_object_signer, PairedCoinType { type });
+        let metadata_obj = object::object_from_constructor_ref(&metadata_object_cref);
+
+        table::add(&mut map.coin_to_fungible_asset_map, type, metadata_obj);
+        event::emit(PairCreation {
+            coin_type: type,
+            fungible_asset_metadata_address: object_address(&metadata_obj)
+        });
+
+        // Generates all three refs
+        let mint_ref = fungible_asset::generate_mint_ref(&metadata_object_cref);
+        let transfer_ref = fungible_asset::generate_transfer_ref(&metadata_object_cref);
+        let burn_ref = fungible_asset::generate_burn_ref(&metadata_object_cref);
+        move_to(metadata_object_signer,
+            PairedFungibleAssetRefs {
+                mint_ref_opt: option::some(mint_ref),
+                transfer_ref_opt: option::some(transfer_ref),
+                burn_ref_opt: option::some(burn_ref),
+            }
+        );
+    };
+    *table::borrow(&map.coin_to_fungible_asset_map, type)
+}
+
+ + + +
+ + + +## Function `ensure_paired_metadata` + +Get the paired fungible asset metadata object of a coin type, create if not exist. + + +
public(friend) fun ensure_paired_metadata<CoinType>(): object::Object<fungible_asset::Metadata>
+
+ + + +
+Implementation + + +
public(friend) fun ensure_paired_metadata<CoinType>(): Object<Metadata> acquires CoinConversionMap, CoinInfo {
+    create_and_return_paired_metadata_if_not_exist<CoinType>(false)
+}
+
+ + + +
+ + + +## Function `paired_coin` + +Get the paired coin type of a fungible asset metadata object. + + +
#[view]
+public fun paired_coin(metadata: object::Object<fungible_asset::Metadata>): option::Option<type_info::TypeInfo>
+
+ + + +
+Implementation + + +
public fun paired_coin(metadata: Object<Metadata>): Option<TypeInfo> acquires PairedCoinType {
+    let metadata_addr = object::object_address(&metadata);
+    if (exists<PairedCoinType>(metadata_addr)) {
+        option::some(borrow_global<PairedCoinType>(metadata_addr).type)
+    } else {
+        option::none()
+    }
+}
+
+ + + +
+ + + +## Function `coin_to_fungible_asset` + +Conversion from coin to fungible asset + + +
public fun coin_to_fungible_asset<CoinType>(coin: coin::Coin<CoinType>): fungible_asset::FungibleAsset
+
+ + + +
+Implementation + + +
public fun coin_to_fungible_asset<CoinType>(
+    coin: Coin<CoinType>
+): FungibleAsset acquires CoinConversionMap, CoinInfo {
+    let metadata = ensure_paired_metadata<CoinType>();
+    let amount = burn_internal(coin);
+    fungible_asset::mint_internal(metadata, amount)
+}
+
+ + + +
+ + + +## Function `fungible_asset_to_coin` + +Conversion from fungible asset to coin. Not public to push the migration to FA. + + +
fun fungible_asset_to_coin<CoinType>(fungible_asset: fungible_asset::FungibleAsset): coin::Coin<CoinType>
+
+ + + +
+Implementation + + +
fun fungible_asset_to_coin<CoinType>(
+    fungible_asset: FungibleAsset
+): Coin<CoinType> acquires CoinInfo, PairedCoinType {
+    let metadata_addr = object::object_address(&fungible_asset::metadata_from_asset(&fungible_asset));
+    assert!(
+        object::object_exists<PairedCoinType>(metadata_addr),
+        error::not_found(EPAIRED_COIN)
+    );
+    let coin_type_info = borrow_global<PairedCoinType>(metadata_addr).type;
+    assert!(coin_type_info == type_info::type_of<CoinType>(), error::invalid_argument(ECOIN_TYPE_MISMATCH));
+    let amount = fungible_asset::burn_internal(fungible_asset);
+    mint_internal<CoinType>(amount)
+}
+
+ + + +
+ + + +## Function `assert_paired_metadata_exists` + + + +
fun assert_paired_metadata_exists<CoinType>(): object::Object<fungible_asset::Metadata>
+
+ + + +
+Implementation + + +
inline fun assert_paired_metadata_exists<CoinType>(): Object<Metadata> {
+    let metadata_opt = paired_metadata<CoinType>();
+    assert!(option::is_some(&metadata_opt), error::not_found(EPAIRED_FUNGIBLE_ASSET));
+    option::destroy_some(metadata_opt)
+}
+
+ + + +
+ + + +## Function `paired_mint_ref_exists` + +Check whether MintRef has not been taken. + + +
#[view]
+public fun paired_mint_ref_exists<CoinType>(): bool
+
+ + + +
+Implementation + + +
public fun paired_mint_ref_exists<CoinType>(): bool acquires CoinConversionMap, PairedFungibleAssetRefs {
+    let metadata = assert_paired_metadata_exists<CoinType>();
+    let metadata_addr = object_address(&metadata);
+    assert!(exists<PairedFungibleAssetRefs>(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND));
+    option::is_some(&borrow_global<PairedFungibleAssetRefs>(metadata_addr).mint_ref_opt)
+}
+
+ + + +
+ + + +## Function `get_paired_mint_ref` + +Get the MintRef of paired fungible asset of a coin type from MintCapability. + + +
public fun get_paired_mint_ref<CoinType>(_: &coin::MintCapability<CoinType>): (fungible_asset::MintRef, coin::MintRefReceipt)
+
+ + + +
+Implementation + + +
public fun get_paired_mint_ref<CoinType>(
+    _: &MintCapability<CoinType>
+): (MintRef, MintRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs {
+    let metadata = assert_paired_metadata_exists<CoinType>();
+    let metadata_addr = object_address(&metadata);
+    assert!(exists<PairedFungibleAssetRefs>(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND));
+    let mint_ref_opt = &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).mint_ref_opt;
+    assert!(option::is_some(mint_ref_opt), error::not_found(EMINT_REF_NOT_FOUND));
+    (option::extract(mint_ref_opt), MintRefReceipt { metadata })
+}
+
+ + + +
+ + + +## Function `return_paired_mint_ref` + +Return the MintRef with the hot potato receipt. + + +
public fun return_paired_mint_ref(mint_ref: fungible_asset::MintRef, receipt: coin::MintRefReceipt)
+
+ + + +
+Implementation + + +
public fun return_paired_mint_ref(mint_ref: MintRef, receipt: MintRefReceipt) acquires PairedFungibleAssetRefs {
+    let MintRefReceipt { metadata } = receipt;
+    assert!(
+        fungible_asset::mint_ref_metadata(&mint_ref) == metadata,
+        error::invalid_argument(EMINT_REF_RECEIPT_MISMATCH)
+    );
+    let metadata_addr = object_address(&metadata);
+    let mint_ref_opt = &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).mint_ref_opt;
+    option::fill(mint_ref_opt, mint_ref);
+}
+
+ + + +
+ + + +## Function `paired_transfer_ref_exists` + +Check whether TransferRef still exists. + + +
#[view]
+public fun paired_transfer_ref_exists<CoinType>(): bool
+
+ + + +
+Implementation + + +
public fun paired_transfer_ref_exists<CoinType>(): bool acquires CoinConversionMap, PairedFungibleAssetRefs {
+    let metadata = assert_paired_metadata_exists<CoinType>();
+    let metadata_addr = object_address(&metadata);
+    assert!(exists<PairedFungibleAssetRefs>(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND));
+    option::is_some(&borrow_global<PairedFungibleAssetRefs>(metadata_addr).transfer_ref_opt)
+}
+
+ + + +
+ + + +## Function `get_paired_transfer_ref` + +Get the TransferRef of paired fungible asset of a coin type from FreezeCapability. + + +
public fun get_paired_transfer_ref<CoinType>(_: &coin::FreezeCapability<CoinType>): (fungible_asset::TransferRef, coin::TransferRefReceipt)
+
+ + + +
+Implementation + + +
public fun get_paired_transfer_ref<CoinType>(
+    _: &FreezeCapability<CoinType>
+): (TransferRef, TransferRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs {
+    let metadata = assert_paired_metadata_exists<CoinType>();
+    let metadata_addr = object_address(&metadata);
+    assert!(exists<PairedFungibleAssetRefs>(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND));
+    let transfer_ref_opt = &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).transfer_ref_opt;
+    assert!(option::is_some(transfer_ref_opt), error::not_found(ETRANSFER_REF_NOT_FOUND));
+    (option::extract(transfer_ref_opt), TransferRefReceipt { metadata })
+}
+
+ + + +
+ + + +## Function `return_paired_transfer_ref` + +Return the TransferRef with the hot potato receipt. + + +
public fun return_paired_transfer_ref(transfer_ref: fungible_asset::TransferRef, receipt: coin::TransferRefReceipt)
+
+ + + +
+Implementation + + +
public fun return_paired_transfer_ref(
+    transfer_ref: TransferRef,
+    receipt: TransferRefReceipt
+) acquires PairedFungibleAssetRefs {
+    let TransferRefReceipt { metadata } = receipt;
+    assert!(
+        fungible_asset::transfer_ref_metadata(&transfer_ref) == metadata,
+        error::invalid_argument(ETRANSFER_REF_RECEIPT_MISMATCH)
+    );
+    let metadata_addr = object_address(&metadata);
+    let transfer_ref_opt = &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).transfer_ref_opt;
+    option::fill(transfer_ref_opt, transfer_ref);
+}
+
+ + + +
+ + + +## Function `paired_burn_ref_exists` + +Check whether BurnRef has not been taken. + + +
#[view]
+public fun paired_burn_ref_exists<CoinType>(): bool
+
+ + + +
+Implementation + + +
public fun paired_burn_ref_exists<CoinType>(): bool acquires CoinConversionMap, PairedFungibleAssetRefs {
+    let metadata = assert_paired_metadata_exists<CoinType>();
+    let metadata_addr = object_address(&metadata);
+    assert!(exists<PairedFungibleAssetRefs>(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND));
+    option::is_some(&borrow_global<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt)
+}
+
+ + + +
+ + + +## Function `get_paired_burn_ref` + +Get the BurnRef of paired fungible asset of a coin type from BurnCapability. + + +
public fun get_paired_burn_ref<CoinType>(_: &coin::BurnCapability<CoinType>): (fungible_asset::BurnRef, coin::BurnRefReceipt)
+
+ + + +
+Implementation + + +
public fun get_paired_burn_ref<CoinType>(
+    _: &BurnCapability<CoinType>
+): (BurnRef, BurnRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs {
+    let metadata = assert_paired_metadata_exists<CoinType>();
+    let metadata_addr = object_address(&metadata);
+    assert!(exists<PairedFungibleAssetRefs>(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND));
+    let burn_ref_opt = &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt;
+    assert!(option::is_some(burn_ref_opt), error::not_found(EBURN_REF_NOT_FOUND));
+    (option::extract(burn_ref_opt), BurnRefReceipt { metadata })
+}
+
+ + + +
+ + + +## Function `return_paired_burn_ref` + +Return the BurnRef with the hot potato receipt. + + +
public fun return_paired_burn_ref(burn_ref: fungible_asset::BurnRef, receipt: coin::BurnRefReceipt)
+
+ + + +
+Implementation + + +
public fun return_paired_burn_ref(
+    burn_ref: BurnRef,
+    receipt: BurnRefReceipt
+) acquires PairedFungibleAssetRefs {
+    let BurnRefReceipt { metadata } = receipt;
+    assert!(
+        fungible_asset::burn_ref_metadata(&burn_ref) == metadata,
+        error::invalid_argument(EBURN_REF_RECEIPT_MISMATCH)
+    );
+    let metadata_addr = object_address(&metadata);
+    let burn_ref_opt = &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt;
+    option::fill(burn_ref_opt, burn_ref);
+}
+
+ + + +
+ + + +## Function `borrow_paired_burn_ref` + + + +
fun borrow_paired_burn_ref<CoinType>(_: &coin::BurnCapability<CoinType>): &fungible_asset::BurnRef
+
+ + + +
+Implementation + + +
inline fun borrow_paired_burn_ref<CoinType>(
+    _: &BurnCapability<CoinType>
+): &BurnRef acquires CoinConversionMap, PairedFungibleAssetRefs {
+    let metadata = assert_paired_metadata_exists<CoinType>();
+    let metadata_addr = object_address(&metadata);
+    assert!(exists<PairedFungibleAssetRefs>(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND));
+    let burn_ref_opt = &mut borrow_global_mut<PairedFungibleAssetRefs>(metadata_addr).burn_ref_opt;
+    assert!(option::is_some(burn_ref_opt), error::not_found(EBURN_REF_NOT_FOUND));
+    option::borrow(burn_ref_opt)
+}
+
+ + + +
+ + + +## Function `initialize_supply_config` + +Publishes supply configuration. Initially, upgrading is not allowed. + + +
public(friend) fun initialize_supply_config(aptos_framework: &signer)
+
+ + + +
+Implementation + + +
public(friend) fun initialize_supply_config(aptos_framework: &signer) {
+    system_addresses::assert_aptos_framework(aptos_framework);
+    move_to(aptos_framework, SupplyConfig { allow_upgrades: false });
+}
+
+ + + +
@@ -817,14 +1936,206 @@ only be called by Aptos Framework (0x1) account for now because of create_ - + + +## Function `is_aggregatable_coin_zero` + +Returns true if the value of aggregatable coin is zero. + + +
public(friend) fun is_aggregatable_coin_zero<CoinType>(coin: &coin::AggregatableCoin<CoinType>): bool
+
+ + + +
+Implementation + + +
public(friend) fun is_aggregatable_coin_zero<CoinType>(coin: &AggregatableCoin<CoinType>): bool {
+    let amount = aggregator::read(&coin.value);
+    amount == 0
+}
+
+ + + +
+ + + +## Function `drain_aggregatable_coin` + +Drains the aggregatable coin, setting it to zero and returning a standard coin. + + +
public(friend) fun drain_aggregatable_coin<CoinType>(coin: &mut coin::AggregatableCoin<CoinType>): coin::Coin<CoinType>
+
+ + + +
+Implementation + + +
public(friend) fun drain_aggregatable_coin<CoinType>(coin: &mut AggregatableCoin<CoinType>): Coin<CoinType> {
+    spec {
+        // TODO: The data invariant is not properly assumed from CollectedFeesPerBlock.
+        assume aggregator::spec_get_limit(coin.value) == MAX_U64;
+    };
+    let amount = aggregator::read(&coin.value);
+    assert!(amount <= MAX_U64, error::out_of_range(EAGGREGATABLE_COIN_VALUE_TOO_LARGE));
+    spec {
+        update aggregate_supply<CoinType> = aggregate_supply<CoinType> - amount;
+    };
+    aggregator::sub(&mut coin.value, amount);
+    spec {
+        update supply<CoinType> = supply<CoinType> + amount;
+    };
+    Coin<CoinType> {
+        value: (amount as u64),
+    }
+}
+
+ + + +
+ + + +## Function `merge_aggregatable_coin` + +Merges coin into aggregatable coin (dst_coin). + + +
public(friend) fun merge_aggregatable_coin<CoinType>(dst_coin: &mut coin::AggregatableCoin<CoinType>, coin: coin::Coin<CoinType>)
+
+ + + +
+Implementation + + +
public(friend) fun merge_aggregatable_coin<CoinType>(
+    dst_coin: &mut AggregatableCoin<CoinType>,
+    coin: Coin<CoinType>
+) {
+    spec {
+        update supply<CoinType> = supply<CoinType> - coin.value;
+    };
+    let Coin { value } = coin;
+    let amount = (value as u128);
+    spec {
+        update aggregate_supply<CoinType> = aggregate_supply<CoinType> + amount;
+    };
+    aggregator::add(&mut dst_coin.value, amount);
+}
+
+ + + +
+ + + +## Function `collect_into_aggregatable_coin` + +Collects a specified amount of coin form an account into aggregatable coin. + + +
public(friend) fun collect_into_aggregatable_coin<CoinType>(account_addr: address, amount: u64, dst_coin: &mut coin::AggregatableCoin<CoinType>)
+
+ + + +
+Implementation + + +
public(friend) fun collect_into_aggregatable_coin<CoinType>(
+    account_addr: address,
+    amount: u64,
+    dst_coin: &mut AggregatableCoin<CoinType>,
+) acquires CoinStore, CoinConversionMap, CoinInfo, PairedCoinType {
+    // Skip collecting if amount is zero.
+    if (amount == 0) {
+        return
+    };
+
+    let (coin_amount_to_collect, fa_amount_to_collect) = calculate_amount_to_withdraw<CoinType>(
+        account_addr,
+        amount
+    );
+    let coin = if (coin_amount_to_collect > 0) {
+        let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);
+        extract(&mut coin_store.coin, coin_amount_to_collect)
+    } else {
+        zero()
+    };
+    if (fa_amount_to_collect > 0) {
+        let store_addr = primary_fungible_store::primary_store_address(
+            account_addr,
+            option::destroy_some(paired_metadata<CoinType>())
+        );
+        let fa = fungible_asset::withdraw_internal(store_addr, fa_amount_to_collect);
+        merge(&mut coin, fungible_asset_to_coin<CoinType>(fa));
+    };
+    merge_aggregatable_coin(dst_coin, coin);
+}
+
+ + + +
+ + + +## Function `calculate_amount_to_withdraw` + + + +
fun calculate_amount_to_withdraw<CoinType>(account_addr: address, amount: u64): (u64, u64)
+
+ + + +
+Implementation + + +
inline fun calculate_amount_to_withdraw<CoinType>(
+    account_addr: address,
+    amount: u64
+): (u64, u64) {
+    let coin_balance = coin_balance<CoinType>(account_addr);
+    if (coin_balance >= amount) {
+        (amount, 0)
+    } else {
+        let metadata = paired_metadata<CoinType>();
+        if (option::is_none(&metadata) || !primary_fungible_store::primary_store_exists(
+            account_addr,
+            option::destroy_some(metadata)
+        ))
+            abort error::invalid_argument(EINSUFFICIENT_BALANCE)
+        else
+            (coin_balance, amount - coin_balance)
+    }
+}
+
+ + + +
+ + -## Function `is_aggregatable_coin_zero` +## Function `maybe_convert_to_fungible_store` -Returns true if the value of aggregatable coin is zero. -
public(friend) fun is_aggregatable_coin_zero<CoinType>(coin: &coin::AggregatableCoin<CoinType>): bool
+
fun maybe_convert_to_fungible_store<CoinType>(account: address)
 
@@ -833,9 +2144,43 @@ Returns true if the value of aggregatable coin is zero. Implementation -
public(friend) fun is_aggregatable_coin_zero<CoinType>(coin: &AggregatableCoin<CoinType>): bool {
-    let amount = aggregator::read(&coin.value);
-    amount == 0
+
fun maybe_convert_to_fungible_store<CoinType>(account: address) acquires CoinStore, CoinConversionMap, CoinInfo {
+    if (!features::coin_to_fungible_asset_migration_feature_enabled()) {
+        abort error::unavailable(ECOIN_TO_FUNGIBLE_ASSET_FEATURE_NOT_ENABLED)
+    };
+    let metadata = ensure_paired_metadata<CoinType>();
+    let store = primary_fungible_store::ensure_primary_store_exists(account, metadata);
+    let store_address = object::object_address(&store);
+    if (exists<CoinStore<CoinType>>(account)) {
+        let CoinStore<CoinType> { coin, frozen, deposit_events, withdraw_events } = move_from<CoinStore<CoinType>>(
+            account
+        );
+        event::emit(
+            CoinEventHandleDeletion {
+                event_handle_creation_address: guid::creator_address(
+                    event::guid(&deposit_events)
+                ),
+                deleted_deposit_event_handle_creation_number: guid::creation_num(event::guid(&deposit_events)),
+                deleted_withdraw_event_handle_creation_number: guid::creation_num(event::guid(&withdraw_events))
+            }
+        );
+        event::destroy_handle(deposit_events);
+        event::destroy_handle(withdraw_events);
+        if (coin.value == 0) {
+            destroy_zero(coin);
+        } else {
+            fungible_asset::deposit(store, coin_to_fungible_asset(coin));
+        };
+        // Note:
+        // It is possible the primary fungible store may already exist before this function call.
+        // In this case, if the account owns a frozen CoinStore and an unfrozen primary fungible store, this
+        // function would convert and deposit the rest coin into the primary store and freeze it to make the
+        // `frozen` semantic as consistent as possible.
+        fungible_asset::set_frozen_flag_internal(store, frozen);
+    };
+    if (!exists<MigrationFlag>(store_address)) {
+        move_to(&create_signer::create_signer(store_address), MigrationFlag {});
+    }
 }
 
@@ -843,14 +2188,14 @@ Returns true if the value of aggregatable coin is zero. - + -## Function `drain_aggregatable_coin` +## Function `migrate_to_fungible_store` -Drains the aggregatable coin, setting it to zero and returning a standard coin. +Voluntarily migrate to fungible store for CoinType if not yet. -
public(friend) fun drain_aggregatable_coin<CoinType>(coin: &mut coin::AggregatableCoin<CoinType>): coin::Coin<CoinType>
+
public entry fun migrate_to_fungible_store<CoinType>(account: &signer)
 
@@ -859,23 +2204,10 @@ Drains the aggregatable coin, setting it to zero and returning a standard coin. Implementation -
public(friend) fun drain_aggregatable_coin<CoinType>(coin: &mut AggregatableCoin<CoinType>): Coin<CoinType> {
-    spec {
-        // TODO: The data invariant is not properly assumed from CollectedFeesPerBlock.
-        assume aggregator::spec_get_limit(coin.value) == MAX_U64;
-    };
-    let amount = aggregator::read(&coin.value);
-    assert!(amount <= MAX_U64, error::out_of_range(EAGGREGATABLE_COIN_VALUE_TOO_LARGE));
-    spec {
-        update aggregate_supply<CoinType> = aggregate_supply<CoinType> - amount;
-    };
-    aggregator::sub(&mut coin.value, amount);
-    spec {
-        update supply<CoinType> = supply<CoinType> + amount;
-    };
-    Coin<CoinType> {
-        value: (amount as u64),
-    }
+
public entry fun migrate_to_fungible_store<CoinType>(
+    account: &signer
+) acquires CoinStore, CoinConversionMap, CoinInfo {
+    maybe_convert_to_fungible_store<CoinType>(signer::address_of(account));
 }
 
@@ -883,14 +2215,14 @@ Drains the aggregatable coin, setting it to zero and returning a standard coin. - + -## Function `merge_aggregatable_coin` +## Function `coin_address` -Merges coin into aggregatable coin (dst_coin). +A helper function that returns the address of CoinType. -
public(friend) fun merge_aggregatable_coin<CoinType>(dst_coin: &mut coin::AggregatableCoin<CoinType>, coin: coin::Coin<CoinType>)
+
fun coin_address<CoinType>(): address
 
@@ -899,19 +2231,9 @@ Merges coin into aggregatable coin ( Implementation -
public(friend) fun merge_aggregatable_coin<CoinType>(
-    dst_coin: &mut AggregatableCoin<CoinType>,
-    coin: Coin<CoinType>
-) {
-    spec {
-        update supply<CoinType> = supply<CoinType> - coin.value;
-    };
-    let Coin { value } = coin;
-    let amount = (value as u128);
-    spec {
-        update aggregate_supply<CoinType> = aggregate_supply<CoinType> + amount;
-    };
-    aggregator::add(&mut dst_coin.value, amount);
+
fun coin_address<CoinType>(): address {
+    let type_info = type_info::type_of<CoinType>();
+    type_info::account_address(&type_info)
 }
 
@@ -919,14 +2241,15 @@ Merges coin into aggregatable coin ( - + -## Function `collect_into_aggregatable_coin` +## Function `balance` -Collects a specified amount of coin form an account into aggregatable coin. +Returns the balance of owner for provided CoinType and its paired FA if exists. -
public(friend) fun collect_into_aggregatable_coin<CoinType>(account_addr: address, amount: u64, dst_coin: &mut coin::AggregatableCoin<CoinType>)
+
#[view]
+public fun balance<CoinType>(owner: address): u64
 
@@ -935,19 +2258,14 @@ Collects a specified amount of coin form an account into aggregatable coin. Implementation -
public(friend) fun collect_into_aggregatable_coin<CoinType>(
-    account_addr: address,
-    amount: u64,
-    dst_coin: &mut AggregatableCoin<CoinType>,
-) acquires CoinStore {
-    // Skip collecting if amount is zero.
-    if (amount == 0) {
-        return
-    };
-
-    let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);
-    let coin = extract(&mut coin_store.coin, amount);
-    merge_aggregatable_coin(dst_coin, coin);
+
public fun balance<CoinType>(owner: address): u64 acquires CoinConversionMap, CoinStore {
+    let paired_metadata = paired_metadata<CoinType>();
+    coin_balance<CoinType>(owner) + if (option::is_some(&paired_metadata)) {
+        primary_fungible_store::balance(
+            owner,
+            option::extract(&mut paired_metadata)
+        )
+    } else { 0 }
 }
 
@@ -955,14 +2273,15 @@ Collects a specified amount of coin form an account into aggregatable coin. - + -## Function `coin_address` +## Function `is_balance_at_least` -A helper function that returns the address of CoinType. +Returns whether the balance of owner for provided CoinType and its paired FA is >= amount. -
fun coin_address<CoinType>(): address
+
#[view]
+public fun is_balance_at_least<CoinType>(owner: address, amount: u64): bool
 
@@ -971,9 +2290,21 @@ A helper function that returns the address of CoinType. Implementation -
fun coin_address<CoinType>(): address {
-    let type_info = type_info::type_of<CoinType>();
-    type_info::account_address(&type_info)
+
public fun is_balance_at_least<CoinType>(owner: address, amount: u64): bool acquires CoinConversionMap, CoinStore {
+    let coin_balance = coin_balance<CoinType>(owner);
+    if (coin_balance >= amount) {
+        return true
+    };
+
+    let paired_metadata = paired_metadata<CoinType>();
+    let left_amount = amount - coin_balance;
+    if (option::is_some(&paired_metadata)) {
+        primary_fungible_store::is_balance_at_least(
+            owner,
+            option::extract(&mut paired_metadata),
+            left_amount
+        )
+    } else { false }
 }
 
@@ -981,15 +2312,13 @@ A helper function that returns the address of CoinType. - + -## Function `balance` +## Function `coin_balance` -Returns the balance of owner for provided CoinType. -
#[view]
-public fun balance<CoinType>(owner: address): u64
+
fun coin_balance<CoinType>(owner: address): u64
 
@@ -998,12 +2327,12 @@ Returns the balance of owner for provided CoinType. Implementation -
public fun balance<CoinType>(owner: address): u64 acquires CoinStore {
-    assert!(
-        is_account_registered<CoinType>(owner),
-        error::not_found(ECOIN_STORE_NOT_PUBLISHED),
-    );
-    borrow_global<CoinStore<CoinType>>(owner).coin.value
+
inline fun coin_balance<CoinType>(owner: address): u64 {
+    if (exists<CoinStore<CoinType>>(owner)) {
+        borrow_global<CoinStore<CoinType>>(owner).coin.value
+    } else {
+        0
+    }
 }
 
@@ -1054,7 +2383,9 @@ Returns true is account_addr has frozen the CoinStore or if Implementation -
public fun is_coin_store_frozen<CoinType>(account_addr: address): bool acquires CoinStore {
+
public fun is_coin_store_frozen<CoinType>(
+    account_addr: address
+): bool acquires CoinStore, CoinConversionMap {
     if (!is_account_registered<CoinType>(account_addr)) {
         return true
     };
@@ -1085,8 +2416,15 @@ Returns true if account_addr is registered to r
 Implementation
 
 
-
public fun is_account_registered<CoinType>(account_addr: address): bool {
-    exists<CoinStore<CoinType>>(account_addr)
+
public fun is_account_registered<CoinType>(account_addr: address): bool acquires CoinConversionMap {
+    if (exists<CoinStore<CoinType>>(account_addr)) {
+        true
+    } else {
+        let paired_metadata_opt = paired_metadata<CoinType>();
+        (option::is_some(
+            &paired_metadata_opt
+        ) && migrated_primary_fungible_store_exists(account_addr, option::destroy_some(paired_metadata_opt)))
+    }
 }
 
@@ -1191,7 +2529,42 @@ Returns the amount of coin in existence. Implementation -
public fun supply<CoinType>(): Option<u128> acquires CoinInfo {
+
public fun supply<CoinType>(): Option<u128> acquires CoinInfo, CoinConversionMap {
+    let coin_supply = coin_supply<CoinType>();
+    let metadata = paired_metadata<CoinType>();
+    if (option::is_some(&metadata)) {
+        let fungible_asset_supply = fungible_asset::supply(option::extract(&mut metadata));
+        if (option::is_some(&coin_supply)) {
+            let supply = option::borrow_mut(&mut coin_supply);
+            *supply = *supply + option::destroy_some(fungible_asset_supply);
+        };
+    };
+    coin_supply
+}
+
+ + + + + + + +## Function `coin_supply` + +Returns the amount of coin in existence. + + +
#[view]
+public fun coin_supply<CoinType>(): option::Option<u128>
+
+ + + +
+Implementation + + +
public fun coin_supply<CoinType>(): Option<u128> acquires CoinInfo {
     let maybe_supply = &borrow_global<CoinInfo<CoinType>>(coin_address<CoinType>()).supply;
     if (option::is_some(maybe_supply)) {
         // We do track supply, in this case read from optional aggregator.
@@ -1225,21 +2598,8 @@ The capability _cap should be passed as a reference to Implementation
 
 
-
public fun burn<CoinType>(
-    coin: Coin<CoinType>,
-    _cap: &BurnCapability<CoinType>,
-) acquires CoinInfo {
-    spec {
-        update supply<CoinType> = supply<CoinType> - coin.value;
-    };
-    let Coin { value: amount } = coin;
-    assert!(amount > 0, error::invalid_argument(EZERO_COIN_AMOUNT));
-
-    let maybe_supply = &mut borrow_global_mut<CoinInfo<CoinType>>(coin_address<CoinType>()).supply;
-    if (option::is_some(maybe_supply)) {
-        let supply = option::borrow_mut(maybe_supply);
-        optional_aggregator::sub(supply, (amount as u128));
-    }
+
public fun burn<CoinType>(coin: Coin<CoinType>, _cap: &BurnCapability<CoinType>) acquires CoinInfo {
+    burn_internal(coin);
 }
 
@@ -1271,15 +2631,28 @@ Note: This bypasses CoinStore::frozen -- coins within a frozen CoinStore can be account_addr: address, amount: u64, burn_cap: &BurnCapability<CoinType>, -) acquires CoinInfo, CoinStore { +) acquires CoinInfo, CoinStore, CoinConversionMap, PairedFungibleAssetRefs { // Skip burning if amount is zero. This shouldn't error out as it's called as part of transaction fee burning. if (amount == 0) { return }; - let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr); - let coin_to_burn = extract(&mut coin_store.coin, amount); - burn(coin_to_burn, burn_cap); + let (coin_amount_to_burn, fa_amount_to_burn) = calculate_amount_to_withdraw<CoinType>( + account_addr, + amount + ); + if (coin_amount_to_burn > 0) { + let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr); + let coin_to_burn = extract(&mut coin_store.coin, coin_amount_to_burn); + burn(coin_to_burn, burn_cap); + }; + if (fa_amount_to_burn > 0) { + fungible_asset::burn_from( + borrow_paired_burn_ref(burn_cap), + primary_fungible_store::primary_store(account_addr, option::destroy_some(paired_metadata<CoinType>())), + fa_amount_to_burn + ); + }; }
@@ -1303,26 +2676,63 @@ Deposit the coin balance into the recipient's account and emit an event. Implementation -
public fun deposit<CoinType>(account_addr: address, coin: Coin<CoinType>) acquires CoinStore {
-    assert!(
-        is_account_registered<CoinType>(account_addr),
-        error::not_found(ECOIN_STORE_NOT_PUBLISHED),
-    );
+
public fun deposit<CoinType>(
+    account_addr: address,
+    coin: Coin<CoinType>
+) acquires CoinStore, CoinConversionMap, CoinInfo {
+    if (exists<CoinStore<CoinType>>(account_addr)) {
+        let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);
+        assert!(
+            !coin_store.frozen,
+            error::permission_denied(EFROZEN),
+        );
+        if (std::features::module_event_migration_enabled()) {
+            event::emit(Deposit<CoinType> { account: account_addr, amount: coin.value });
+        };
+        event::emit_event<DepositEvent>(
+            &mut coin_store.deposit_events,
+            DepositEvent { amount: coin.value },
+        );
+        merge(&mut coin_store.coin, coin);
+    } else {
+        let metadata = paired_metadata<CoinType>();
+        if (option::is_some(&metadata) && migrated_primary_fungible_store_exists(
+            account_addr,
+            option::destroy_some(metadata)
+        )) {
+            primary_fungible_store::deposit(account_addr, coin_to_fungible_asset(coin));
+        } else {
+            abort error::not_found(ECOIN_STORE_NOT_PUBLISHED)
+        };
+    }
+}
+
- let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr); - assert!( - !coin_store.frozen, - error::permission_denied(EFROZEN), - ); - if (std::features::module_event_migration_enabled()) { - event::emit(Deposit<CoinType> { account: account_addr, amount: coin.value }); - }; - event::emit_event<DepositEvent>( - &mut coin_store.deposit_events, - DepositEvent { amount: coin.value }, - ); - merge(&mut coin_store.coin, coin); + +
+ + + +## Function `migrated_primary_fungible_store_exists` + + + +
fun migrated_primary_fungible_store_exists(account_address: address, metadata: object::Object<fungible_asset::Metadata>): bool
+
+ + + +
+Implementation + + +
inline fun migrated_primary_fungible_store_exists(
+    account_address: address,
+    metadata: Object<Metadata>
+): bool {
+    let primary_store_address = primary_fungible_store::primary_store_address<Metadata>(account_address, metadata);
+    fungible_asset::store_exists(primary_store_address) && exists<MigrationFlag>(primary_store_address)
 }
 
@@ -1347,15 +2757,27 @@ This is for internal use only and doesn't emit an DepositEvent. Implementation -
public(friend) fun force_deposit<CoinType>(account_addr: address, coin: Coin<CoinType>) acquires CoinStore {
-    assert!(
-        is_account_registered<CoinType>(account_addr),
-        error::not_found(ECOIN_STORE_NOT_PUBLISHED),
-    );
-
-    let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);
-
-    merge(&mut coin_store.coin, coin);
+
public(friend) fun force_deposit<CoinType>(
+    account_addr: address,
+    coin: Coin<CoinType>
+) acquires CoinStore, CoinConversionMap, CoinInfo {
+    if (exists<CoinStore<CoinType>>(account_addr)) {
+        let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);
+        merge(&mut coin_store.coin, coin);
+    } else {
+        let metadata = paired_metadata<CoinType>();
+        if (option::is_some(&metadata) && migrated_primary_fungible_store_exists(
+            account_addr,
+            option::destroy_some(metadata)
+        )) {
+            let fa = coin_to_fungible_asset(coin);
+            let metadata = fungible_asset::asset_metadata(&fa);
+            let store = primary_fungible_store::primary_store(account_addr, metadata);
+            fungible_asset::deposit_internal(store, fa);
+        } else {
+            abort error::not_found(ECOIN_STORE_NOT_PUBLISHED)
+        }
+    }
 }
 
@@ -1749,31 +3171,7 @@ Returns minted Coin. amount: u64, _cap: &MintCapability<CoinType>, ): Coin<CoinType> acquires CoinInfo { - if (amount == 0) { - return Coin<CoinType> { - value: 0 - } - }; - - let maybe_supply = &mut borrow_global_mut<CoinInfo<CoinType>>(coin_address<CoinType>()).supply; - if (option::is_some(maybe_supply)) { - let supply = option::borrow_mut(maybe_supply); - spec { - use aptos_framework::optional_aggregator; - use aptos_framework::aggregator; - assume optional_aggregator::is_parallelizable(supply) ==> (aggregator::spec_aggregator_get_val( - option::borrow(supply.aggregator) - ) - + amount <= aggregator::spec_get_limit(option::borrow(supply.aggregator))); - assume !optional_aggregator::is_parallelizable(supply) ==> - (option::borrow(supply.integer).value + amount <= option::borrow(supply.integer).limit); - }; - optional_aggregator::add(supply, (amount as u128)); - }; - spec { - update supply<CoinType> = supply<CoinType> + amount; - }; - Coin<CoinType> { value: amount } + mint_internal<CoinType>(amount) }
@@ -1796,7 +3194,7 @@ Returns minted Coin. Implementation -
public fun register<CoinType>(account: &signer) {
+
public fun register<CoinType>(account: &signer) acquires CoinConversionMap {
     let account_addr = signer::address_of(account);
     // Short-circuit and do nothing if account is already registered for CoinType.
     if (is_account_registered<CoinType>(account_addr)) {
@@ -1838,7 +3236,7 @@ Transfers amount of coins CoinType from fromsigner,
     to: address,
     amount: u64,
-) acquires CoinStore {
+) acquires CoinStore, CoinConversionMap, CoinInfo, PairedCoinType {
     let coin = withdraw<CoinType>(from, amount);
     deposit(to, coin);
 }
@@ -1892,28 +3290,39 @@ Withdraw specified amount of coin CoinType from the si
 
public fun withdraw<CoinType>(
     account: &signer,
     amount: u64,
-): Coin<CoinType> acquires CoinStore {
+): Coin<CoinType> acquires CoinStore, CoinConversionMap, CoinInfo, PairedCoinType {
     let account_addr = signer::address_of(account);
-    assert!(
-        is_account_registered<CoinType>(account_addr),
-        error::not_found(ECOIN_STORE_NOT_PUBLISHED),
-    );
 
-    let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);
-    assert!(
-        !coin_store.frozen,
-        error::permission_denied(EFROZEN),
+    let (coin_amount_to_withdraw, fa_amount_to_withdraw) = calculate_amount_to_withdraw<CoinType>(
+        account_addr,
+        amount
     );
-
-    if (std::features::module_event_migration_enabled()) {
-        event::emit(Withdraw<CoinType> { account: account_addr, amount });
+    let withdrawn_coin = if (coin_amount_to_withdraw > 0) {
+        let coin_store = borrow_global_mut<CoinStore<CoinType>>(account_addr);
+        assert!(
+            !coin_store.frozen,
+            error::permission_denied(EFROZEN),
+        );
+        if (std::features::module_event_migration_enabled()) {
+            event::emit(Withdraw<CoinType> { account: account_addr, amount: coin_amount_to_withdraw });
+        };
+        event::emit_event<WithdrawEvent>(
+            &mut coin_store.withdraw_events,
+            WithdrawEvent { amount: coin_amount_to_withdraw },
+        );
+        extract(&mut coin_store.coin, coin_amount_to_withdraw)
+    } else {
+        zero()
     };
-    event::emit_event<WithdrawEvent>(
-        &mut coin_store.withdraw_events,
-        WithdrawEvent { amount },
-    );
-
-    extract(&mut coin_store.coin, amount)
+    if (fa_amount_to_withdraw > 0) {
+        let fa = primary_fungible_store::withdraw(
+            account,
+            option::destroy_some(paired_metadata<CoinType>()),
+            fa_amount_to_withdraw
+        );
+        merge(&mut withdrawn_coin, fungible_asset_to_coin(fa));
+    };
+    withdrawn_coin
 }
 
@@ -1992,8 +3401,81 @@ Destroy a mint capability. Implementation -
public fun destroy_mint_cap<CoinType>(mint_cap: MintCapability<CoinType>) {
-    let MintCapability<CoinType> {} = mint_cap;
+
public fun destroy_mint_cap<CoinType>(mint_cap: MintCapability<CoinType>) {
+    let MintCapability<CoinType> {} = mint_cap;
+}
+
+ + + +
+ + + +## Function `destroy_burn_cap` + +Destroy a burn capability. + + +
public fun destroy_burn_cap<CoinType>(burn_cap: coin::BurnCapability<CoinType>)
+
+ + + +
+Implementation + + +
public fun destroy_burn_cap<CoinType>(burn_cap: BurnCapability<CoinType>) {
+    let BurnCapability<CoinType> {} = burn_cap;
+}
+
+ + + +
+ + + +## Function `mint_internal` + + + +
fun mint_internal<CoinType>(amount: u64): coin::Coin<CoinType>
+
+ + + +
+Implementation + + +
fun mint_internal<CoinType>(amount: u64): Coin<CoinType> acquires CoinInfo {
+    if (amount == 0) {
+        return Coin<CoinType> {
+            value: 0
+        }
+    };
+
+    let maybe_supply = &mut borrow_global_mut<CoinInfo<CoinType>>(coin_address<CoinType>()).supply;
+    if (option::is_some(maybe_supply)) {
+        let supply = option::borrow_mut(maybe_supply);
+        spec {
+            use aptos_framework::optional_aggregator;
+            use aptos_framework::aggregator;
+            assume optional_aggregator::is_parallelizable(supply) ==> (aggregator::spec_aggregator_get_val(
+                option::borrow(supply.aggregator)
+            )
+                + amount <= aggregator::spec_get_limit(option::borrow(supply.aggregator)));
+            assume !optional_aggregator::is_parallelizable(supply) ==>
+                (option::borrow(supply.integer).value + amount <= option::borrow(supply.integer).limit);
+        };
+        optional_aggregator::add(supply, (amount as u128));
+    };
+    spec {
+        update supply<CoinType> = supply<CoinType> + amount;
+    };
+    Coin<CoinType> { value: amount }
 }
 
@@ -2001,14 +3483,13 @@ Destroy a mint capability.
- + -## Function `destroy_burn_cap` +## Function `burn_internal` -Destroy a burn capability. -
public fun destroy_burn_cap<CoinType>(burn_cap: coin::BurnCapability<CoinType>)
+
fun burn_internal<CoinType>(coin: coin::Coin<CoinType>): u64
 
@@ -2017,8 +3498,19 @@ Destroy a burn capability. Implementation -
public fun destroy_burn_cap<CoinType>(burn_cap: BurnCapability<CoinType>) {
-    let BurnCapability<CoinType> {} = burn_cap;
+
fun burn_internal<CoinType>(coin: Coin<CoinType>): u64 acquires CoinInfo {
+    spec {
+        update supply<CoinType> = supply<CoinType> - coin.value;
+    };
+    let Coin { value: amount } = coin;
+    if (amount != 0) {
+        let maybe_supply = &mut borrow_global_mut<CoinInfo<CoinType>>(coin_address<CoinType>()).supply;
+        if (option::is_some(maybe_supply)) {
+            let supply = option::borrow_mut(maybe_supply);
+            optional_aggregator::sub(supply, (amount as u128));
+        };
+    };
+    amount
 }
 
@@ -2130,10 +3622,7 @@ Destroy a burn capability. global aggregate_supply<CoinType>: num; apply TotalSupplyTracked<CoinType> to *<CoinType> except - initialize, initialize_internal, initialize_with_parallelizable_supply; -// This enforces high-level requirement 4 and high-level requirement 9: -apply TotalSupplyNoChange<CoinType> to *<CoinType> except mint, - burn, burn_from, initialize, initialize_internal, initialize_with_parallelizable_supply; +initialize, initialize_internal, initialize_with_parallelizable_supply;
@@ -2144,7 +3633,7 @@ Destroy a burn capability.
fun spec_fun_supply_tracked<CoinType>(val: u64, supply: Option<OptionalAggregator>): bool {
    option::spec_is_some(supply) ==> val == optional_aggregator::optional_aggregator_value
-           (option::spec_borrow(supply))
+       (option::spec_borrow(supply))
 }
 
@@ -2191,6 +3680,85 @@ Destroy a burn capability. + + + + +
fun spec_paired_metadata<CoinType>(): Option<Object<Metadata>> {
+   if (exists<CoinConversionMap>(@aptos_framework)) {
+       let map = global<CoinConversionMap>(@aptos_framework).coin_to_fungible_asset_map;
+       if (table::spec_contains(map, type_info::type_of<CoinType>())) {
+           let metadata = table::spec_get(map, type_info::type_of<CoinType>());
+           option::spec_some(metadata)
+       } else {
+           option::spec_none()
+       }
+   } else {
+       option::spec_none()
+   }
+}
+
+ + + + + + + +
fun spec_is_account_registered<CoinType>(account_addr: address): bool {
+   let paired_metadata_opt = spec_paired_metadata<CoinType>();
+   exists<CoinStore<CoinType>>(account_addr) || (option::spec_is_some(
+       paired_metadata_opt
+   ) && primary_fungible_store::spec_primary_store_exists(account_addr, option::spec_borrow(paired_metadata_opt)))
+}
+
+ + + + + + + +
schema CoinSubAbortsIf<CoinType> {
+    amount: u64;
+    let addr = type_info::type_of<CoinType>().account_address;
+    let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;
+    include (option::is_some(
+        maybe_supply
+    )) ==> optional_aggregator::SubAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };
+}
+
+ + + + + + + +
schema CoinAddAbortsIf<CoinType> {
+    amount: u64;
+    let addr = type_info::type_of<CoinType>().account_address;
+    let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;
+    include (option::is_some(
+        maybe_supply
+    )) ==> optional_aggregator::AddAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };
+}
+
+ + + + + + + +
schema AbortsIfNotExistCoinInfo<CoinType> {
+    let addr = type_info::type_of<CoinType>().account_address;
+    aborts_if !exists<CoinInfo<CoinType>>(addr);
+}
+
+ + + ### Struct `AggregatableCoin` @@ -2217,6 +3785,40 @@ Destroy a burn capability. + + +### Function `coin_to_fungible_asset` + + +
public fun coin_to_fungible_asset<CoinType>(coin: coin::Coin<CoinType>): fungible_asset::FungibleAsset
+
+ + + + +
pragma verify = false;
+let addr = type_info::type_of<CoinType>().account_address;
+modifies global<CoinInfo<CoinType>>(addr);
+
+ + + + + +### Function `fungible_asset_to_coin` + + +
fun fungible_asset_to_coin<CoinType>(fungible_asset: fungible_asset::FungibleAsset): coin::Coin<CoinType>
+
+ + + + +
pragma verify = false;
+
+ + + ### Function `initialize_supply_config` @@ -2272,7 +3874,7 @@ Can only be updated by @aptos_framework. -
include system_addresses::AbortsIfNotAptosFramework{account: aptos_framework};
+
include system_addresses::AbortsIfNotAptosFramework { account: aptos_framework };
 include aggregator_factory::CreateAggregatorInternalAbortsIf;
 
@@ -2329,7 +3931,7 @@ Can only be updated by @aptos_framework. + coin.value > aggregator::spec_get_limit(aggr); aborts_if aggregator::spec_aggregator_get_val(aggr) + coin.value > MAX_U128; -ensures aggregator::spec_aggregator_get_val(aggr)+ coin.value == aggregator::spec_aggregator_get_val(p_aggr); +ensures aggregator::spec_aggregator_get_val(aggr) + coin.value == aggregator::spec_aggregator_get_val(p_aggr);
@@ -2345,7 +3947,8 @@ Can only be updated by @aptos_framework. -
let aggr = dst_coin.value;
+
pragma verify = false;
+let aggr = dst_coin.value;
 let post p_aggr = dst_coin.value;
 let coin_store = global<CoinStore<CoinType>>(account_addr);
 let post p_coin_store = global<CoinStore<CoinType>>(account_addr);
@@ -2355,12 +3958,44 @@ Can only be updated by @aptos_framework.
     + amount > aggregator::spec_get_limit(aggr);
 aborts_if amount > 0 && aggregator::spec_aggregator_get_val(aggr)
     + amount > MAX_U128;
-ensures aggregator::spec_aggregator_get_val(aggr)+ amount == aggregator::spec_aggregator_get_val(p_aggr);
+ensures aggregator::spec_aggregator_get_val(aggr) + amount == aggregator::spec_aggregator_get_val(p_aggr);
 ensures coin_store.coin.value - amount == p_coin_store.coin.value;
 
+ + +### Function `maybe_convert_to_fungible_store` + + +
fun maybe_convert_to_fungible_store<CoinType>(account: address)
+
+ + + + +
pragma verify = false;
+modifies global<CoinInfo<CoinType>>(account);
+modifies global<CoinStore<CoinType>>(account);
+
+ + + + + + + +
schema DepositAbortsIf<CoinType> {
+    account_addr: address;
+    let coin_store = global<CoinStore<CoinType>>(account_addr);
+    aborts_if !exists<CoinStore<CoinType>>(account_addr);
+    aborts_if coin_store.frozen;
+}
+
+ + + ### Function `coin_address` @@ -2392,7 +4027,7 @@ Get address by reflection. -
// This enforces high-level requirement 6:
+
pragma verify = false;
 aborts_if !exists<CoinStore<CoinType>>(owner);
 ensures result == global<CoinStore<CoinType>>(owner).coin.value;
 
@@ -2429,7 +4064,7 @@ Get address by reflection. -
// This enforces high-level requirement 5 and high-level requirement 7:
+
pragma aborts_if_is_partial;
 aborts_if false;
 
@@ -2446,46 +4081,6 @@ Get address by reflection. - - - - -
schema CoinSubAbortsIf<CoinType> {
-    amount: u64;
-    let addr =  type_info::type_of<CoinType>().account_address;
-    let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;
-    include (option::is_some(maybe_supply)) ==> optional_aggregator::SubAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };
-}
-
- - - - - - - -
schema CoinAddAbortsIf<CoinType> {
-    amount: u64;
-    let addr =  type_info::type_of<CoinType>().account_address;
-    let maybe_supply = global<CoinInfo<CoinType>>(addr).supply;
-    include (option::is_some(maybe_supply)) ==> optional_aggregator::AddAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount };
-}
-
- - - - - - - -
schema AbortsIfNotExistCoinInfo<CoinType> {
-    let addr = type_info::type_of<CoinType>().account_address;
-    aborts_if !exists<CoinInfo<CoinType>>(addr);
-}
-
- - - ### Function `name` @@ -2551,6 +4146,23 @@ Get address by reflection. +
pragma verify = false;
+
+ + + + + +### Function `coin_supply` + + +
#[view]
+public fun coin_supply<CoinType>(): option::Option<u128>
+
+ + + +
let coin_addr = type_info::type_of<CoinType>().account_address;
 // This enforces high-level requirement 7:
 aborts_if !exists<CoinInfo<CoinType>>(coin_addr);
@@ -2577,7 +4189,8 @@ Get address by reflection.
 
 
 
-
let addr =  type_info::type_of<CoinType>().account_address;
+
pragma verify = false;
+let addr = type_info::type_of<CoinType>().account_address;
 modifies global<CoinInfo<CoinType>>(addr);
 include AbortsIfNotExistCoinInfo<CoinType>;
 aborts_if coin.value == 0;
@@ -2598,7 +4211,8 @@ Get address by reflection.
 
 
 
-
let addr = type_info::type_of<CoinType>().account_address;
+
pragma verify = false;
+let addr = type_info::type_of<CoinType>().account_address;
 let coin_store = global<CoinStore<CoinType>>(account_addr);
 let post post_coin_store = global<CoinStore<CoinType>>(account_addr);
 modifies global<CoinInfo<CoinType>>(addr);
@@ -2638,24 +4252,13 @@ Get address by reflection.
 account_addr is not frozen.
 
 
-
modifies global<CoinInfo<CoinType>>(account_addr);
+
pragma verify = false;
+modifies global<CoinInfo<CoinType>>(account_addr);
 // This enforces high-level requirement 8:
 include DepositAbortsIf<CoinType>;
-ensures global<CoinStore<CoinType>>(account_addr).coin.value == old(global<CoinStore<CoinType>>(account_addr)).coin.value + coin.value;
-
- - - - - - - -
schema DepositAbortsIf<CoinType> {
-    account_addr: address;
-    let coin_store = global<CoinStore<CoinType>>(account_addr);
-    aborts_if !exists<CoinStore<CoinType>>(account_addr);
-    aborts_if coin_store.frozen;
-}
+ensures global<CoinStore<CoinType>>(account_addr).coin.value == old(
+    global<CoinStore<CoinType>>(account_addr)
+).coin.value + coin.value;
 
@@ -2671,9 +4274,12 @@ Get address by reflection. -
modifies global<CoinStore<CoinType>>(account_addr);
+
pragma verify = false;
+modifies global<CoinStore<CoinType>>(account_addr);
 aborts_if !exists<CoinStore<CoinType>>(account_addr);
-ensures global<CoinStore<CoinType>>(account_addr).coin.value == old(global<CoinStore<CoinType>>(account_addr)).coin.value + coin.value;
+ensures global<CoinStore<CoinType>>(account_addr).coin.value == old(
+    global<CoinStore<CoinType>>(account_addr)
+).coin.value + coin.value;
 
@@ -2742,7 +4348,7 @@ The value of zero_coin must be 0. -
pragma opaque;
+
pragma verify = false;
 modifies global<CoinStore<CoinType>>(account_addr);
 // This enforces high-level requirement 6:
 aborts_if !exists<CoinStore<CoinType>>(account_addr);
@@ -2764,7 +4370,7 @@ The value of zero_coin must be 0.
 
 
 
-
pragma opaque;
+
pragma verify = false;
 modifies global<CoinStore<CoinType>>(account_addr);
 // This enforces high-level requirement 6:
 aborts_if !exists<CoinStore<CoinType>>(account_addr);
@@ -2847,7 +4453,7 @@ The creator of CoinType must be @aptos_framework.
 
let addr = signer::address_of(account);
 aborts_if addr != @aptos_framework;
 aborts_if monitor_supply && !exists<aggregator_factory::AggregatorFactory>(@aptos_framework);
-include InitializeInternalSchema<CoinType>{
+include InitializeInternalSchema<CoinType> {
     name: name.bytes,
     symbol: symbol.bytes
 };
@@ -2855,27 +4461,6 @@ The creator of CoinType must be @aptos_framework.
 
-Make sure name and symbol are legal length. -Only the creator of CoinType can initialize. - - - - - -
schema InitializeInternalSchema<CoinType> {
-    account: signer;
-    name: vector<u8>;
-    symbol: vector<u8>;
-    let account_addr = signer::address_of(account);
-    let coin_address = type_info::type_of<CoinType>().account_address;
-    aborts_if coin_address != account_addr;
-    aborts_if exists<CoinInfo<CoinType>>(account_addr);
-    aborts_if len(name) > MAX_COIN_NAME_LENGTH;
-    aborts_if len(symbol) > MAX_COIN_SYMBOL_LENGTH;
-}
-
- - @@ -2888,7 +4473,7 @@ Only the creator of CoinType can initialize. -
include InitializeInternalSchema<CoinType>{
+
include InitializeInternalSchema<CoinType> {
     name: name.bytes,
     symbol: symbol.bytes
 };
@@ -2948,9 +4533,6 @@ Only the creator of CoinType can initialize.
 
 
let addr = type_info::type_of<CoinType>().account_address;
 modifies global<CoinInfo<CoinType>>(addr);
-aborts_if (amount != 0) && !exists<CoinInfo<CoinType>>(addr);
-ensures supply<CoinType> == old(supply<CoinType>) + amount;
-ensures result.value == amount;
 
@@ -2968,14 +4550,7 @@ An account can only be registered once. Updating Account.guid_creation_num will not overflow. -
let account_addr = signer::address_of(account);
-let acc = global<account::Account>(account_addr);
-aborts_if !exists<CoinStore<CoinType>>(account_addr) && acc.guid_creation_num + 2 >= account::MAX_GUID_CREATION_NUM;
-aborts_if !exists<CoinStore<CoinType>>(account_addr) && acc.guid_creation_num + 2 > MAX_U64;
-// This enforces high-level requirement 5:
-aborts_if !exists<CoinStore<CoinType>>(account_addr) && !exists<account::Account>(account_addr);
-aborts_if !exists<CoinStore<CoinType>>(account_addr) && !type_info::spec_is_struct<CoinType>();
-ensures exists<CoinStore<CoinType>>(account_addr);
+
pragma verify = false;
 
@@ -2994,7 +4569,8 @@ Updating Account.guid_creation_num will not overflow. from account sufficient balance. -
let account_addr_from = signer::address_of(from);
+
pragma verify = false;
+let account_addr_from = signer::address_of(from);
 let coin_store_from = global<CoinStore<CoinType>>(account_addr_from);
 let post coin_store_post_from = global<CoinStore<CoinType>>(account_addr_from);
 let coin_store_to = global<CoinStore<CoinType>>(to);
@@ -3007,7 +4583,7 @@ Updating Account.guid_creation_num will not overflow.
 aborts_if coin_store_to.frozen;
 aborts_if coin_store_from.coin.value < amount;
 ensures account_addr_from != to ==> coin_store_post_from.coin.value ==
-         coin_store_from.coin.value - amount;
+    coin_store_from.coin.value - amount;
 ensures account_addr_from != to ==> coin_store_post_to.coin.value == coin_store_to.coin.value + amount;
 ensures account_addr_from == to ==> coin_store_post_from.coin.value == coin_store_from.coin.value;
 
@@ -3026,14 +4602,15 @@ Updating Account.guid_creation_num will not overflow. Account is not frozen and sufficient balance. -
include WithdrawAbortsIf<CoinType>;
+
pragma verify = false;
+include WithdrawAbortsIf<CoinType>;
 modifies global<CoinStore<CoinType>>(account_addr);
 let account_addr = signer::address_of(account);
 let coin_store = global<CoinStore<CoinType>>(account_addr);
 let balance = coin_store.coin.value;
 let post coin_post = global<CoinStore<CoinType>>(account_addr).coin.value;
 ensures coin_post == balance - amount;
-ensures result == Coin<CoinType>{value: amount};
+ensures result == Coin<CoinType> { value: amount };
 
@@ -3057,4 +4634,42 @@ Account is not frozen and sufficient balance.
+ + + +### Function `mint_internal` + + +
fun mint_internal<CoinType>(amount: u64): coin::Coin<CoinType>
+
+ + + + +
let addr = type_info::type_of<CoinType>().account_address;
+modifies global<CoinInfo<CoinType>>(addr);
+aborts_if (amount != 0) && !exists<CoinInfo<CoinType>>(addr);
+ensures supply<CoinType> == old(supply<CoinType>) + amount;
+ensures result.value == amount;
+
+ + + + + +### Function `burn_internal` + + +
fun burn_internal<CoinType>(coin: coin::Coin<CoinType>): u64
+
+ + + + +
pragma verify = false;
+let addr = type_info::type_of<CoinType>().account_address;
+modifies global<CoinInfo<CoinType>>(addr);
+
+ + [move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/config_buffer.md b/aptos-move/framework/aptos-framework/doc/config_buffer.md index 025b452a56585..a4ee3dd11301d 100644 --- a/aptos-move/framework/aptos-framework/doc/config_buffer.md +++ b/aptos-move/framework/aptos-framework/doc/config_buffer.md @@ -316,7 +316,6 @@ Typically used in X::on_new_epoch() where X is an on-chaon config.
schema OnNewEpochAbortsIf<T> {
     let type_name = type_info::type_name<T>();
-    aborts_if spec_fun_does_exist<T>(type_name) && !exists<T>(@aptos_framework);
     let configs = global<PendingConfigs>(@aptos_framework);
     include spec_fun_does_exist<T>(type_name) ==> any::UnpackAbortsIf<T> {
         x: simple_map::spec_get(configs.configs, type_name)
@@ -332,7 +331,6 @@ Typically used in X::on_new_epoch() where X is an on-chaon config.
 
 
schema OnNewEpochRequirement<T> {
     let type_name = type_info::type_name<T>();
-    requires spec_fun_does_exist<T>(type_name) ==> exists<T>(@aptos_framework);
     let configs = global<PendingConfigs>(@aptos_framework);
     include spec_fun_does_exist<T>(type_name) ==> any::UnpackRequirement<T> {
         x: simple_map::spec_get(configs.configs, type_name)
diff --git a/aptos-move/framework/aptos-framework/doc/consensus_config.md b/aptos-move/framework/aptos-framework/doc/consensus_config.md
index c7cf016d6217d..ddceb292dbded 100644
--- a/aptos-move/framework/aptos-framework/doc/consensus_config.md
+++ b/aptos-move/framework/aptos-framework/doc/consensus_config.md
@@ -180,7 +180,7 @@ aptos_framework::aptos_governance::reconfigure(&framework_signer);
 Only used in reconfigurations to apply the pending ConsensusConfig, if there is any.
 
 
-
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
@@ -189,9 +189,15 @@ Only used in reconfigurations to apply the pending on_new_epoch() acquires ConsensusConfig { +
public(friend) fun on_new_epoch(framework: &signer) acquires ConsensusConfig {
+    system_addresses::assert_aptos_framework(framework);
     if (config_buffer::does_exist<ConsensusConfig>()) {
-        *borrow_global_mut<ConsensusConfig>(@aptos_framework) = config_buffer::extract();
+        let new_config = config_buffer::extract<ConsensusConfig>();
+        if (exists<ConsensusConfig>(@aptos_framework)) {
+            *borrow_global_mut<ConsensusConfig>(@aptos_framework) = new_config;
+        } else {
+            move_to(framework, new_config);
+        };
     }
 }
 
@@ -380,13 +386,15 @@ When setting now time must be later than last_reconfiguration_time. ### Function `on_new_epoch` -
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
-
include config_buffer::OnNewEpochAbortsIf<ConsensusConfig>;
+
requires @aptos_framework == std::signer::address_of(framework);
+include config_buffer::OnNewEpochRequirement<ConsensusConfig>;
+aborts_if false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/delegation_pool.md b/aptos-move/framework/aptos-framework/doc/delegation_pool.md index 71c38c33ab666..bab9d467506bc 100644 --- a/aptos-move/framework/aptos-framework/doc/delegation_pool.md +++ b/aptos-move/framework/aptos-framework/doc/delegation_pool.md @@ -678,7 +678,8 @@ evicted later by the pool owner. -
struct AddStakeEvent has drop, store
+
#[event]
+struct AddStakeEvent has drop, store
 
@@ -723,7 +724,8 @@ evicted later by the pool owner. -
struct ReactivateStakeEvent has drop, store
+
#[event]
+struct ReactivateStakeEvent has drop, store
 
@@ -762,7 +764,8 @@ evicted later by the pool owner. -
struct UnlockStakeEvent has drop, store
+
#[event]
+struct UnlockStakeEvent has drop, store
 
@@ -801,7 +804,8 @@ evicted later by the pool owner. -
struct WithdrawStakeEvent has drop, store
+
#[event]
+struct WithdrawStakeEvent has drop, store
 
@@ -840,7 +844,8 @@ evicted later by the pool owner. -
struct DistributeCommissionEvent has drop, store
+
#[event]
+struct DistributeCommissionEvent has drop, store
 
@@ -937,7 +942,8 @@ evicted later by the pool owner. -
struct VoteEvent has drop, store
+
#[event]
+struct VoteEvent has drop, store
 
@@ -988,7 +994,8 @@ evicted later by the pool owner. -
struct CreateProposalEvent has drop, store
+
#[event]
+struct CreateProposalEvent has drop, store
 
@@ -1027,7 +1034,8 @@ evicted later by the pool owner. -
struct DelegateVotingPowerEvent has drop, store
+
#[event]
+struct DelegateVotingPowerEvent has drop, store
 
@@ -1837,7 +1845,9 @@ Return the operator commission percentage set on the delegation pool pool_ Implementation -
public fun operator_commission_percentage(pool_address: address): u64 acquires DelegationPool, NextCommissionPercentage {
+
public fun operator_commission_percentage(
+    pool_address: address
+): u64 acquires DelegationPool, NextCommissionPercentage {
     assert_delegation_pool_exists(pool_address);
     if (is_next_commission_percentage_effective(pool_address)) {
         operator_commission_percentage_next_lockup_cycle(pool_address)
@@ -1868,7 +1878,9 @@ Return the operator commission percentage for the next lockup cycle.
 Implementation
 
 
-
public fun operator_commission_percentage_next_lockup_cycle(pool_address: address): u64 acquires DelegationPool, NextCommissionPercentage {
+
public fun operator_commission_percentage_next_lockup_cycle(
+    pool_address: address
+): u64 acquires DelegationPool, NextCommissionPercentage {
     assert_delegation_pool_exists(pool_address);
     if (exists<NextCommissionPercentage>(pool_address)) {
         borrow_global<NextCommissionPercentage>(pool_address).commission_percentage_next_lockup_cycle
@@ -2015,7 +2027,10 @@ in each of its individual states: (active,inactive,Implementation
 
 
-
public fun get_stake(pool_address: address, delegator_address: address): (u64, u64, u64) acquires DelegationPool, BeneficiaryForOperator {
+
public fun get_stake(
+    pool_address: address,
+    delegator_address: address
+): (u64, u64, u64) acquires DelegationPool, BeneficiaryForOperator {
     assert_delegation_pool_exists(pool_address);
     let pool = borrow_global<DelegationPool>(pool_address);
     let (
@@ -2097,7 +2112,10 @@ extracted-fee = (amount - extracted-fee) * reward-rate% * (100% - operator-commi
 Implementation
 
 
-
public fun get_add_stake_fee(pool_address: address, amount: u64): u64 acquires DelegationPool, NextCommissionPercentage {
+
public fun get_add_stake_fee(
+    pool_address: address,
+    amount: u64
+): u64 acquires DelegationPool, NextCommissionPercentage {
     if (stake::is_current_epoch_validator(pool_address)) {
         let (rewards_rate, rewards_rate_denominator) = staking_config::get_reward_rate(&staking_config::get());
         if (rewards_rate_denominator > 0) {
@@ -2162,7 +2180,10 @@ latest state.
 Implementation
 
 
-
public fun calculate_and_update_voter_total_voting_power(pool_address: address, voter: address): u64 acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+
public fun calculate_and_update_voter_total_voting_power(
+    pool_address: address,
+    voter: address
+): u64 acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
     assert_partial_governance_voting_enabled(pool_address);
     // Delegation pool need to be synced to explain rewards(which could change the coin amount) and
     // commission(which could cause share transfer).
@@ -2196,7 +2217,11 @@ latest state.
 Implementation
 
 
-
public fun calculate_and_update_remaining_voting_power(pool_address: address, voter_address: address, proposal_id: u64): u64 acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+
public fun calculate_and_update_remaining_voting_power(
+    pool_address: address,
+    voter_address: address,
+    proposal_id: u64
+): u64 acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
     assert_partial_governance_voting_enabled(pool_address);
     // If the whole stake pool has no voting power(e.g. it has already voted before partial
     // governance voting flag is enabled), the delegator also has no voting power.
@@ -2232,7 +2257,10 @@ latest state.
 Implementation
 
 
-
public fun calculate_and_update_delegator_voter(pool_address: address, delegator_address: address): address acquires DelegationPool, GovernanceRecords {
+
public fun calculate_and_update_delegator_voter(
+    pool_address: address,
+    delegator_address: address
+): address acquires DelegationPool, GovernanceRecords {
     assert_partial_governance_voting_enabled(pool_address);
     calculate_and_update_delegator_voter_internal(
         borrow_global<DelegationPool>(pool_address),
@@ -2460,7 +2488,8 @@ Ownership over setting the operator/voter is granted to owner who h
     move_to(owner, DelegationPoolOwnership { pool_address });
 
     // All delegation pool enable partial governance voting by default once the feature flag is enabled.
-    if (features::partial_governance_voting_enabled() && features::delegation_pool_partial_governance_voting_enabled()) {
+    if (features::partial_governance_voting_enabled(
+    ) && features::delegation_pool_partial_governance_voting_enabled()) {
         enable_partial_governance_voting(pool_address);
     }
 }
@@ -2521,7 +2550,10 @@ The existing voter will be replaced. The function is permissionless.
     pool_address: address,
 ) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
     assert!(features::partial_governance_voting_enabled(), error::invalid_state(EDISABLED_FUNCTION));
-    assert!(features::delegation_pool_partial_governance_voting_enabled(), error::invalid_state(EDISABLED_FUNCTION));
+    assert!(
+        features::delegation_pool_partial_governance_voting_enabled(),
+        error::invalid_state(EDISABLED_FUNCTION)
+    );
     assert_delegation_pool_exists(pool_address);
     // synchronize delegation and stake pools before any user operation.
     synchronize_delegation_pool(pool_address);
@@ -2568,13 +2600,23 @@ Vote on a proposal with a voter's voting power. To successfully vote, the follow
 Implementation
 
 
-
public entry fun vote(voter: &signer, pool_address: address, proposal_id: u64, voting_power: u64, should_pass: bool) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+
public entry fun vote(
+    voter: &signer,
+    pool_address: address,
+    proposal_id: u64,
+    voting_power: u64,
+    should_pass: bool
+) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
     assert_partial_governance_voting_enabled(pool_address);
     // synchronize delegation and stake pools before any user operation.
     synchronize_delegation_pool(pool_address);
 
     let voter_address = signer::address_of(voter);
-    let remaining_voting_power = calculate_and_update_remaining_voting_power(pool_address, voter_address, proposal_id);
+    let remaining_voting_power = calculate_and_update_remaining_voting_power(
+        pool_address,
+        voter_address,
+        proposal_id
+    );
     if (voting_power > remaining_voting_power) {
         voting_power = remaining_voting_power;
     };
@@ -2589,6 +2631,18 @@ Vote on a proposal with a voter's voting power. To successfully vote, the follow
     let pool_signer = retrieve_stake_pool_owner(borrow_global<DelegationPool>(pool_address));
     aptos_governance::partial_vote(&pool_signer, pool_address, proposal_id, voting_power, should_pass);
 
+    if (features::module_event_migration_enabled()) {
+        event::emit(
+            VoteEvent {
+                voter: voter_address,
+                proposal_id,
+                delegation_pool: pool_address,
+                num_votes: voting_power,
+                should_pass,
+            }
+        );
+    };
+
     event::emit_event(
         &mut governance_records.vote_events,
         VoteEvent {
@@ -2655,6 +2709,17 @@ voting power in THIS delegation pool must be not less than the minimum required
     );
 
     let governance_records = borrow_global_mut<GovernanceRecords>(pool_address);
+
+    if (features::module_event_migration_enabled()) {
+        event::emit(
+            CreateProposalEvent {
+                proposal_id,
+                voter: voter_addr,
+                delegation_pool: pool_address,
+            }
+        );
+    };
+
     event::emit_event(
         &mut governance_records.create_proposal_events,
         CreateProposalEvent {
@@ -2788,7 +2853,10 @@ voting power in THIS delegation pool must be not less than the minimum required
 
 
fun assert_partial_governance_voting_enabled(pool_address: address) {
     assert_delegation_pool_exists(pool_address);
-    assert!(partial_governance_voting_enabled(pool_address), error::invalid_state(EPARTIAL_GOVERNANCE_VOTING_NOT_ENABLED));
+    assert!(
+        partial_governance_voting_enabled(pool_address),
+        error::invalid_state(EPARTIAL_GOVERNANCE_VOTING_NOT_ENABLED)
+    );
 }
 
@@ -3108,7 +3176,11 @@ Borrow the mutable used voting power of a voter on a proposal. Implementation -
inline fun borrow_mut_used_voting_power(governance_records: &mut GovernanceRecords, voter: address, proposal_id: u64): &mut u64 {
+
inline fun borrow_mut_used_voting_power(
+    governance_records: &mut GovernanceRecords,
+    voter: address,
+    proposal_id: u64
+): &mut u64 {
     let votes = &mut governance_records.votes;
     let key = VotingRecordKey {
         proposal_id,
@@ -3140,7 +3212,7 @@ Update VoteDelegation of a delegator to up-to-date then borrow_mut it.
 
 
fun update_and_borrow_mut_delegator_vote_delegation(
     pool: &DelegationPool,
-    governance_records :&mut GovernanceRecords,
+    governance_records: &mut GovernanceRecords,
     delegator: address
 ): &mut VoteDelegation {
     let pool_address = get_pool_address(pool);
@@ -3189,7 +3261,7 @@ Update DelegatedVotes of a voter to up-to-date then borrow_mut it.
 
 
fun update_and_borrow_mut_delegated_votes(
     pool: &DelegationPool,
-    governance_records :&mut GovernanceRecords,
+    governance_records: &mut GovernanceRecords,
     voter: address
 ): &mut DelegatedVotes {
     let pool_address = get_pool_address(pool);
@@ -3296,7 +3368,11 @@ Update VoteDelegation of a delegator to up-to-date then return the latest voter.
 Implementation
 
 
-
fun calculate_and_update_delegator_voter_internal(pool: &DelegationPool, governance_records: &mut GovernanceRecords, delegator: address): address {
+
fun calculate_and_update_delegator_voter_internal(
+    pool: &DelegationPool,
+    governance_records: &mut GovernanceRecords,
+    delegator: address
+): address {
     let vote_delegation = update_and_borrow_mut_delegator_vote_delegation(pool, governance_records, delegator);
     vote_delegation.voter
 }
@@ -3322,7 +3398,11 @@ Update DelegatedVotes of a voter to up-to-date then return the total voting powe
 Implementation
 
 
-
fun calculate_and_update_delegated_votes(pool: &DelegationPool, governance_records: &mut GovernanceRecords, voter: address): u64 {
+
fun calculate_and_update_delegated_votes(
+    pool: &DelegationPool,
+    governance_records: &mut GovernanceRecords,
+    voter: address
+): u64 {
     let delegated_votes = update_and_borrow_mut_delegated_votes(pool, governance_records, voter);
     calculate_total_voting_power(pool, delegated_votes)
 }
@@ -3409,7 +3489,10 @@ one for each pool.
 Implementation
 
 
-
public entry fun set_beneficiary_for_operator(operator: &signer, new_beneficiary: address) acquires BeneficiaryForOperator {
+
public entry fun set_beneficiary_for_operator(
+    operator: &signer,
+    new_beneficiary: address
+) acquires BeneficiaryForOperator {
     assert!(features::operator_beneficiary_change_enabled(), std::error::invalid_state(
         EOPERATOR_BENEFICIARY_CHANGE_NOT_SUPPORTED
     ));
@@ -3521,7 +3604,10 @@ Allows an owner to change the delegated voter of the underlying stake pool.
     new_voter: address
 ) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
     // No one can change delegated_voter once the partial governance voting feature is enabled.
-    assert!(!features::delegation_pool_partial_governance_voting_enabled(), error::invalid_state(EDEPRECATED_FUNCTION));
+    assert!(
+        !features::delegation_pool_partial_governance_voting_enabled(),
+        error::invalid_state(EDEPRECATED_FUNCTION)
+    );
     let pool_address = get_owned_pool_address(signer::address_of(owner));
     // synchronize delegation and stake pools before any user operation
     synchronize_delegation_pool(pool_address);
@@ -3564,10 +3650,10 @@ this change won't take effects until the next lockup period.
     let delegation_pool = borrow_global<DelegationPool>(pool_address);
     let governance_records = borrow_global_mut<GovernanceRecords>(pool_address);
     let delegator_vote_delegation = update_and_borrow_mut_delegator_vote_delegation(
-            delegation_pool,
-            governance_records,
-            delegator_address
-        );
+        delegation_pool,
+        governance_records,
+        delegator_address
+    );
     let pending_voter: address = delegator_vote_delegation.pending_voter;
 
     // No need to update if the voter doesn't really change.
@@ -3593,6 +3679,14 @@ this change won't take effects until the next lockup period.
             new_delegated_votes.active_shares_next_lockup + active_shares;
     };
 
+    if (features::module_event_migration_enabled()) {
+        event::emit(DelegateVotingPowerEvent {
+            pool_address,
+            delegator: delegator_address,
+            voter: new_voter,
+        })
+    };
+
     event::emit_event(&mut governance_records.delegate_voting_power_events, DelegateVotingPowerEvent {
         pool_address,
         delegator: delegator_address,
@@ -3839,6 +3933,17 @@ Add amount of coins to the delegation pool pool_addressto appreciate all shares on the active pool atomically
     buy_in_active_shares(pool, NULL_SHAREHOLDER, add_stake_fee);
 
+    if (features::module_event_migration_enabled()) {
+        event::emit(
+            AddStakeEvent {
+                pool_address,
+                delegator_address,
+                amount_added: amount,
+                add_stake_fee,
+            },
+        );
+    };
+
     event::emit_event(
         &mut pool.add_stake_events,
         AddStakeEvent {
@@ -3932,6 +4037,16 @@ at most how much active stake there is on the stake pool.
     buy_in_pending_inactive_shares(pool, delegator_address, amount);
     assert_min_pending_inactive_balance(pool, delegator_address);
 
+    if (features::module_event_migration_enabled()) {
+        event::emit(
+            UnlockStakeEvent {
+                pool_address,
+                delegator_address,
+                amount_unlocked: amount,
+            },
+        );
+    };
+
     event::emit_event(
         &mut pool.unlock_stake_events,
         UnlockStakeEvent {
@@ -3992,6 +4107,16 @@ Move amount of coins from pending_inactive to active.
     buy_in_active_shares(pool, delegator_address, amount);
     assert_min_active_balance(pool, delegator_address);
 
+    if (features::module_event_migration_enabled()) {
+        event::emit(
+            ReactivateStakeEvent {
+                pool_address,
+                delegator_address,
+                amount_reactivated: amount,
+            },
+        );
+    };
+
     event::emit_event(
         &mut pool.reactivate_stake_events,
         ReactivateStakeEvent {
@@ -4023,7 +4148,11 @@ Withdraw amount of owned inactive stake from the delegation pool at
 Implementation
 
 
-
public entry fun withdraw(delegator: &signer, pool_address: address, amount: u64) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+
public entry fun withdraw(
+    delegator: &signer,
+    pool_address: address,
+    amount: u64
+) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
     assert!(amount > 0, error::invalid_argument(EWITHDRAW_ZERO_STAKE));
     // synchronize delegation and stake pools before any user operation
     synchronize_delegation_pool(pool_address);
@@ -4050,7 +4179,11 @@ Withdraw amount of owned inactive stake from the delegation pool at
 Implementation
 
 
-
fun withdraw_internal(pool: &mut DelegationPool, delegator_address: address, amount: u64) acquires GovernanceRecords {
+
fun withdraw_internal(
+    pool: &mut DelegationPool,
+    delegator_address: address,
+    amount: u64
+) acquires GovernanceRecords {
     // TODO: recycle storage when a delegator fully exits the delegation pool.
     // short-circuit if amount to withdraw is 0 so no event is emitted
     if (amount == 0) { return };
@@ -4099,6 +4232,16 @@ Withdraw amount of owned inactive stake from the delegation pool at
     let (_, inactive, _, _) = stake::get_stake(pool_address);
     pool.total_coins_inactive = inactive;
 
+    if (features::module_event_migration_enabled()) {
+        event::emit(
+            WithdrawStakeEvent {
+                pool_address,
+                delegator_address,
+                amount_withdrawn: amount,
+            },
+        );
+    };
+
     event::emit_event(
         &mut pool.withdraw_stake_events,
         WithdrawStakeEvent {
@@ -4248,7 +4391,7 @@ deposited coins_amount. This function doesn't make any coin transfe
     pool: &mut DelegationPool,
     shareholder: address,
     coins_amount: u64,
-): u128 acquires GovernanceRecords{
+): u128 acquires GovernanceRecords {
     let new_shares = pool_u64::amount_to_shares(&pool.active_shares, coins_amount);
     // No need to buy 0 shares.
     if (new_shares == 0) { return 0 };
@@ -4441,7 +4584,12 @@ escape inactivation when current lockup ends.
     let pool_address = get_pool_address(pool);
     // Only redeem shares from the pending_inactive pool at `lockup_cycle` == current OLC.
     if (partial_governance_voting_enabled(pool_address) && lockup_cycle.index == pool.observed_lockup_cycle.index) {
-        update_governanace_records_for_redeem_pending_inactive_shares(pool, pool_address, shares_to_redeem, shareholder);
+        update_governanace_records_for_redeem_pending_inactive_shares(
+            pool,
+            pool_address,
+            shares_to_redeem,
+            shareholder
+        );
     };
 
     let inactive_shares = table::borrow_mut(&mut pool.inactive_shares, lockup_cycle);
@@ -4558,7 +4706,9 @@ shares pools, assign commission to operator and eventually prepare delegation po
 Implementation
 
 
-
public entry fun synchronize_delegation_pool(pool_address: address) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
+
public entry fun synchronize_delegation_pool(
+    pool_address: address
+) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage {
     assert_delegation_pool_exists(pool_address);
     let pool = borrow_global_mut<DelegationPool>(pool_address);
     let (
@@ -4594,7 +4744,11 @@ shares pools, assign commission to operator and eventually prepare delegation po
     // reward operator its commission out of uncommitted active rewards (`add_stake` fees already excluded)
     buy_in_active_shares(pool, beneficiary_for_operator(stake::get_operator(pool_address)), commission_active);
     // reward operator its commission out of uncommitted pending_inactive rewards
-    buy_in_pending_inactive_shares(pool, beneficiary_for_operator(stake::get_operator(pool_address)), commission_pending_inactive);
+    buy_in_pending_inactive_shares(
+        pool,
+        beneficiary_for_operator(stake::get_operator(pool_address)),
+        commission_pending_inactive
+    );
 
     event::emit_event(
         &mut pool.distribute_commission_events,
@@ -4633,7 +4787,9 @@ shares pools, assign commission to operator and eventually prepare delegation po
     };
 
     if (is_next_commission_percentage_effective(pool_address)) {
-        pool.operator_commission_percentage = borrow_global<NextCommissionPercentage>(pool_address).commission_percentage_next_lockup_cycle;
+        pool.operator_commission_percentage = borrow_global<NextCommissionPercentage>(
+            pool_address
+        ).commission_percentage_next_lockup_cycle;
     }
 }
 
@@ -4658,17 +4814,26 @@ shares pools, assign commission to operator and eventually prepare delegation po
inline fun assert_and_update_proposal_used_voting_power(
-    governance_records: &mut GovernanceRecords, pool_address : address, proposal_id : u64, voting_power: u64
+    governance_records: &mut GovernanceRecords, pool_address: address, proposal_id: u64, voting_power: u64
 ) {
     let stake_pool_remaining_voting_power = aptos_governance::get_remaining_voting_power(pool_address, proposal_id);
-    let stake_pool_used_voting_power = aptos_governance::get_voting_power(pool_address) - stake_pool_remaining_voting_power;
-    let proposal_used_voting_power = smart_table::borrow_mut_with_default(&mut governance_records.votes_per_proposal, proposal_id, 0);
+    let stake_pool_used_voting_power = aptos_governance::get_voting_power(
+        pool_address
+    ) - stake_pool_remaining_voting_power;
+    let proposal_used_voting_power = smart_table::borrow_mut_with_default(
+        &mut governance_records.votes_per_proposal,
+        proposal_id,
+        0
+    );
     // A edge case: Before enabling partial governance voting on a delegation pool, the delegation pool has
     // a voter which can vote with all voting power of this delegation pool. If the voter votes on a proposal after
     // partial governance voting flag is enabled, the delegation pool doesn't have enough voting power on this
     // proposal for all the delegators. To be fair, no one can vote on this proposal through this delegation pool.
     // To detect this case, check if the stake pool had used voting power not through delegation_pool module.
-    assert!(stake_pool_used_voting_power == *proposal_used_voting_power, error::invalid_argument(EALREADY_VOTED_BEFORE_ENABLE_PARTIAL_VOTING));
+    assert!(
+        stake_pool_used_voting_power == *proposal_used_voting_power,
+        error::invalid_argument(EALREADY_VOTED_BEFORE_ENABLE_PARTIAL_VOTING)
+    );
     *proposal_used_voting_power = *proposal_used_voting_power + voting_power;
 }
 
@@ -4694,7 +4859,7 @@ shares pools, assign commission to operator and eventually prepare delegation po
fun update_governance_records_for_buy_in_active_shares(
     pool: &DelegationPool, pool_address: address, new_shares: u128, shareholder: address
-) acquires GovernanceRecords{
+) acquires GovernanceRecords {
     // <active shares> of <shareholder> += <new_shares> ---->
     // <active shares> of <current voter of shareholder> += <new_shares>
     // <active shares> of <next voter of shareholder> += <new_shares>
diff --git a/aptos-move/framework/aptos-framework/doc/dispatchable_fungible_asset.md b/aptos-move/framework/aptos-framework/doc/dispatchable_fungible_asset.md
new file mode 100644
index 0000000000000..e25fcf5058f0e
--- /dev/null
+++ b/aptos-move/framework/aptos-framework/doc/dispatchable_fungible_asset.md
@@ -0,0 +1,535 @@
+
+
+
+# Module `0x1::dispatchable_fungible_asset`
+
+This defines the fungible asset module that can issue fungible asset of any Metadata object. The
+metadata object can be any object that equipped with Metadata resource.
+
+The dispatchable_fungible_asset wraps the existing fungible_asset module and adds the ability for token issuer
+to customize the logic for withdraw and deposit operations. For example:
+
+- Deflation token: a fixed percentage of token will be destructed upon transfer.
+- Transfer allowlist: token can only be transfered to addresses in the allow list.
+- Predicated transfer: transfer can only happen when some certain predicate has been met.
+- Loyalty token: a fixed loyalty will be paid to a designated address when a fungible asset transfer happens
+
+The api listed here intended to be an in-place replacement for defi applications that uses fungible_asset api directly
+and is safe for non-dispatchable (aka vanilla) fungible assets as well.
+
+See AIP-73 for further discussion
+
+
+-  [Resource `TransferRefStore`](#0x1_dispatchable_fungible_asset_TransferRefStore)
+-  [Constants](#@Constants_0)
+-  [Function `register_dispatch_functions`](#0x1_dispatchable_fungible_asset_register_dispatch_functions)
+-  [Function `withdraw`](#0x1_dispatchable_fungible_asset_withdraw)
+-  [Function `deposit`](#0x1_dispatchable_fungible_asset_deposit)
+-  [Function `transfer`](#0x1_dispatchable_fungible_asset_transfer)
+-  [Function `transfer_assert_minimum_deposit`](#0x1_dispatchable_fungible_asset_transfer_assert_minimum_deposit)
+-  [Function `derived_balance`](#0x1_dispatchable_fungible_asset_derived_balance)
+-  [Function `borrow_transfer_ref`](#0x1_dispatchable_fungible_asset_borrow_transfer_ref)
+-  [Function `dispatchable_withdraw`](#0x1_dispatchable_fungible_asset_dispatchable_withdraw)
+-  [Function `dispatchable_deposit`](#0x1_dispatchable_fungible_asset_dispatchable_deposit)
+-  [Function `dispatchable_derived_balance`](#0x1_dispatchable_fungible_asset_dispatchable_derived_balance)
+-  [Specification](#@Specification_1)
+    -  [Function `dispatchable_withdraw`](#@Specification_1_dispatchable_withdraw)
+    -  [Function `dispatchable_deposit`](#@Specification_1_dispatchable_deposit)
+    -  [Function `dispatchable_derived_balance`](#@Specification_1_dispatchable_derived_balance)
+
+
+
use 0x1::error;
+use 0x1::features;
+use 0x1::function_info;
+use 0x1::fungible_asset;
+use 0x1::object;
+use 0x1::option;
+
+ + + + + +## Resource `TransferRefStore` + + + +
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]
+struct TransferRefStore has key
+
+ + + +
+Fields + + +
+
+transfer_ref: fungible_asset::TransferRef +
+
+ +
+
+ + +
+ + + +## Constants + + + + +Feature is not activated yet on the network. + + +
const ENOT_ACTIVATED: u64 = 3;
+
+ + + + + +Recipient is not getting the guaranteed value; + + +
const EAMOUNT_MISMATCH: u64 = 2;
+
+ + + + + +Dispatch target is not loaded. + + +
const ENOT_LOADED: u64 = 4;
+
+ + + + + +TransferRefStore doesn't exist on the fungible asset type. + + +
const ESTORE_NOT_FOUND: u64 = 1;
+
+ + + + + +## Function `register_dispatch_functions` + + + +
public fun register_dispatch_functions(constructor_ref: &object::ConstructorRef, withdraw_function: option::Option<function_info::FunctionInfo>, deposit_function: option::Option<function_info::FunctionInfo>, derived_balance_function: option::Option<function_info::FunctionInfo>)
+
+ + + +
+Implementation + + +
public fun register_dispatch_functions(
+    constructor_ref: &ConstructorRef,
+    withdraw_function: Option<FunctionInfo>,
+    deposit_function: Option<FunctionInfo>,
+    derived_balance_function: Option<FunctionInfo>,
+) {
+    fungible_asset::register_dispatch_functions(
+        constructor_ref,
+        withdraw_function,
+        deposit_function,
+        derived_balance_function,
+    );
+    let store_obj = &object::generate_signer(constructor_ref);
+    move_to<TransferRefStore>(
+        store_obj,
+        TransferRefStore {
+            transfer_ref: fungible_asset::generate_transfer_ref(constructor_ref),
+        }
+    );
+}
+
+ + + +
+ + + +## Function `withdraw` + +Withdraw amount of the fungible asset from store by the owner. + +The semantics of deposit will be governed by the function specified in DispatchFunctionStore. + + +
public fun withdraw<T: key>(owner: &signer, store: object::Object<T>, amount: u64): fungible_asset::FungibleAsset
+
+ + + +
+Implementation + + +
public fun withdraw<T: key>(
+    owner: &signer,
+    store: Object<T>,
+    amount: u64,
+): FungibleAsset acquires TransferRefStore {
+    let func_opt = fungible_asset::withdraw_dispatch_function(store);
+    if (option::is_some(&func_opt)) {
+        assert!(
+            features::dispatchable_fungible_asset_enabled(),
+            error::aborted(ENOT_ACTIVATED)
+        );
+        let start_balance = fungible_asset::balance(store);
+        let func = option::borrow(&func_opt);
+        function_info::load_module_from_function(func);
+        let fa = dispatchable_withdraw(
+            store,
+            amount,
+            borrow_transfer_ref(store),
+            func,
+        );
+        let end_balance = fungible_asset::balance(store);
+        assert!(amount <= start_balance - end_balance, error::aborted(EAMOUNT_MISMATCH));
+        fa
+    } else {
+        fungible_asset::withdraw_non_dispatch(owner, store, amount)
+    }
+}
+
+ + + +
+ + + +## Function `deposit` + +Deposit amount of the fungible asset to store. + +The semantics of deposit will be governed by the function specified in DispatchFunctionStore. + + +
public fun deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset)
+
+ + + +
+Implementation + + +
public fun deposit<T: key>(store: Object<T>, fa: FungibleAsset) acquires TransferRefStore {
+    let func_opt = fungible_asset::deposit_dispatch_function(store);
+    if (option::is_some(&func_opt)) {
+        assert!(
+            features::dispatchable_fungible_asset_enabled(),
+            error::aborted(ENOT_ACTIVATED)
+        );
+        let func = option::borrow(&func_opt);
+        function_info::load_module_from_function(func);
+        dispatchable_deposit(
+            store,
+            fa,
+            borrow_transfer_ref(store),
+            func
+        )
+    } else {
+        fungible_asset::deposit_non_dispatch(store, fa)
+    }
+}
+
+ + + +
+ + + +## Function `transfer` + +Transfer an amount of fungible asset from from_store, which should be owned by sender, to receiver. +Note: it does not move the underlying object. + + +
public entry fun transfer<T: key>(sender: &signer, from: object::Object<T>, to: object::Object<T>, amount: u64)
+
+ + + +
+Implementation + + +
public entry fun transfer<T: key>(
+    sender: &signer,
+    from: Object<T>,
+    to: Object<T>,
+    amount: u64,
+) acquires TransferRefStore {
+    let fa = withdraw(sender, from, amount);
+    deposit(to, fa);
+}
+
+ + + +
+ + + +## Function `transfer_assert_minimum_deposit` + +Transfer an amount of fungible asset from from_store, which should be owned by sender, to receiver. +The recipient is guranteed to receive asset greater than the expected amount. +Note: it does not move the underlying object. + + +
public entry fun transfer_assert_minimum_deposit<T: key>(sender: &signer, from: object::Object<T>, to: object::Object<T>, amount: u64, expected: u64)
+
+ + + +
+Implementation + + +
public entry fun transfer_assert_minimum_deposit<T: key>(
+    sender: &signer,
+    from: Object<T>,
+    to: Object<T>,
+    amount: u64,
+    expected: u64
+) acquires TransferRefStore {
+    let start = fungible_asset::balance(to);
+    let fa = withdraw(sender, from, amount);
+    deposit(to, fa);
+    let end = fungible_asset::balance(to);
+    assert!(end - start >= expected, error::aborted(EAMOUNT_MISMATCH));
+}
+
+ + + +
+ + + +## Function `derived_balance` + +Get the derived value of store using the overloaded hook. + +The semantics of value will be governed by the function specified in DispatchFunctionStore. + + +
#[view]
+public fun derived_balance<T: key>(store: object::Object<T>): u64
+
+ + + +
+Implementation + + +
public fun derived_balance<T: key>(store: Object<T>): u64 {
+    let func_opt = fungible_asset::derived_balance_dispatch_function(store);
+    if (option::is_some(&func_opt)) {
+        assert!(
+            features::dispatchable_fungible_asset_enabled(),
+            error::aborted(ENOT_ACTIVATED)
+        );
+        let func = option::borrow(&func_opt);
+        function_info::load_module_from_function(func);
+        dispatchable_derived_balance(store, func)
+    } else {
+        fungible_asset::balance(store)
+    }
+}
+
+ + + +
+ + + +## Function `borrow_transfer_ref` + + + +
fun borrow_transfer_ref<T: key>(metadata: object::Object<T>): &fungible_asset::TransferRef
+
+ + + +
+Implementation + + +
inline fun borrow_transfer_ref<T: key>(metadata: Object<T>): &TransferRef acquires TransferRefStore {
+    let metadata_addr = object::object_address(
+        &fungible_asset::store_metadata(metadata)
+    );
+    assert!(
+        exists<TransferRefStore>(metadata_addr),
+        error::not_found(ESTORE_NOT_FOUND)
+    );
+    &borrow_global<TransferRefStore>(metadata_addr).transfer_ref
+}
+
+ + + +
+ + + +## Function `dispatchable_withdraw` + + + +
fun dispatchable_withdraw<T: key>(store: object::Object<T>, amount: u64, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo): fungible_asset::FungibleAsset
+
+ + + +
+Implementation + + +
native fun dispatchable_withdraw<T: key>(
+    store: Object<T>,
+    amount: u64,
+    transfer_ref: &TransferRef,
+    function: &FunctionInfo,
+): FungibleAsset;
+
+ + + +
+ + + +## Function `dispatchable_deposit` + + + +
fun dispatchable_deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo)
+
+ + + +
+Implementation + + +
native fun dispatchable_deposit<T: key>(
+    store: Object<T>,
+    fa: FungibleAsset,
+    transfer_ref: &TransferRef,
+    function: &FunctionInfo,
+);
+
+ + + +
+ + + +## Function `dispatchable_derived_balance` + + + +
fun dispatchable_derived_balance<T: key>(store: object::Object<T>, function: &function_info::FunctionInfo): u64
+
+ + + +
+Implementation + + +
native fun dispatchable_derived_balance<T: key>(
+    store: Object<T>,
+    function: &FunctionInfo,
+): u64;
+
+ + + +
+ + + +## Specification + + + +
pragma verify = false;
+
+ + + + + +### Function `dispatchable_withdraw` + + +
fun dispatchable_withdraw<T: key>(store: object::Object<T>, amount: u64, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo): fungible_asset::FungibleAsset
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `dispatchable_deposit` + + +
fun dispatchable_deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo)
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `dispatchable_derived_balance` + + +
fun dispatchable_derived_balance<T: key>(store: object::Object<T>, function: &function_info::FunctionInfo): u64
+
+ + + + +
pragma opaque;
+
+ + +[move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/dkg.md b/aptos-move/framework/aptos-framework/doc/dkg.md index caac04c05e90a..9db68a09dd5d3 100644 --- a/aptos-move/framework/aptos-framework/doc/dkg.md +++ b/aptos-move/framework/aptos-framework/doc/dkg.md @@ -467,8 +467,9 @@ Return the dealer epoch of a DKGS -
aborts_if !exists<DKGState>(@aptos_framework);
-aborts_if option::is_none(global<DKGState>(@aptos_framework).in_progress);
+
requires exists<DKGState>(@aptos_framework);
+requires option::is_some(global<DKGState>(@aptos_framework).in_progress);
+aborts_if false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/execution_config.md b/aptos-move/framework/aptos-framework/doc/execution_config.md index 1d5e757cba621..06be205963675 100644 --- a/aptos-move/framework/aptos-framework/doc/execution_config.md +++ b/aptos-move/framework/aptos-framework/doc/execution_config.md @@ -149,7 +149,7 @@ aptos_framework::aptos_governance::reconfigure(&framework_signer); Only used in reconfigurations to apply the pending ExecutionConfig, if there is any. -
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
@@ -158,10 +158,15 @@ Only used in reconfigurations to apply the pending on_new_epoch() acquires ExecutionConfig { +
public(friend) fun on_new_epoch(framework: &signer) acquires ExecutionConfig {
+    system_addresses::assert_aptos_framework(framework);
     if (config_buffer::does_exist<ExecutionConfig>()) {
         let config = config_buffer::extract<ExecutionConfig>();
-        *borrow_global_mut<ExecutionConfig>(@aptos_framework) = config;
+        if (exists<ExecutionConfig>(@aptos_framework)) {
+            *borrow_global_mut<ExecutionConfig>(@aptos_framework) = config;
+        } else {
+            move_to(framework, config);
+        };
     }
 }
 
@@ -232,13 +237,15 @@ When setting now time must be later than last_reconfiguration_time. ### Function `on_new_epoch` -
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
-
include config_buffer::OnNewEpochAbortsIf<ExecutionConfig>;
+
requires @aptos_framework == std::signer::address_of(framework);
+include config_buffer::OnNewEpochRequirement<ExecutionConfig>;
+aborts_if false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/function_info.md b/aptos-move/framework/aptos-framework/doc/function_info.md new file mode 100644 index 0000000000000..e55ff672c939e --- /dev/null +++ b/aptos-move/framework/aptos-framework/doc/function_info.md @@ -0,0 +1,362 @@ + + + +# Module `0x1::function_info` + +The function_info module defines the FunctionInfo type which simulates a function pointer. + + +- [Struct `FunctionInfo`](#0x1_function_info_FunctionInfo) +- [Constants](#@Constants_0) +- [Function `new_function_info`](#0x1_function_info_new_function_info) +- [Function `new_function_info_from_address`](#0x1_function_info_new_function_info_from_address) +- [Function `check_dispatch_type_compatibility`](#0x1_function_info_check_dispatch_type_compatibility) +- [Function `load_module_from_function`](#0x1_function_info_load_module_from_function) +- [Function `check_dispatch_type_compatibility_impl`](#0x1_function_info_check_dispatch_type_compatibility_impl) +- [Function `is_identifier`](#0x1_function_info_is_identifier) +- [Function `load_function_impl`](#0x1_function_info_load_function_impl) +- [Specification](#@Specification_1) + - [Function `check_dispatch_type_compatibility_impl`](#@Specification_1_check_dispatch_type_compatibility_impl) + - [Function `load_function_impl`](#@Specification_1_load_function_impl) + + +
use 0x1::error;
+use 0x1::features;
+use 0x1::signer;
+use 0x1::string;
+
+ + + + + +## Struct `FunctionInfo` + +A String holds a sequence of bytes which is guaranteed to be in utf8 format. + + +
struct FunctionInfo has copy, drop, store
+
+ + + +
+Fields + + +
+
+module_address: address +
+
+ +
+
+module_name: string::String +
+
+ +
+
+function_name: string::String +
+
+ +
+
+ + +
+ + + +## Constants + + + + +Function specified in the FunctionInfo doesn't exist on chain. + + +
const EINVALID_FUNCTION: u64 = 2;
+
+ + + + + +String is not a valid Move identifier + + +
const EINVALID_IDENTIFIER: u64 = 1;
+
+ + + + + +Feature hasn't been activated yet. + + +
const ENOT_ACTIVATED: u64 = 3;
+
+ + + + + +## Function `new_function_info` + +Creates a new function info from names. + + +
public fun new_function_info(module_signer: &signer, module_name: string::String, function_name: string::String): function_info::FunctionInfo
+
+ + + +
+Implementation + + +
public fun new_function_info(
+    module_signer: &signer,
+    module_name: String,
+    function_name: String,
+): FunctionInfo {
+    new_function_info_from_address(
+        signer::address_of(module_signer),
+        module_name,
+        function_name,
+    )
+}
+
+ + + +
+ + + +## Function `new_function_info_from_address` + + + +
public(friend) fun new_function_info_from_address(module_address: address, module_name: string::String, function_name: string::String): function_info::FunctionInfo
+
+ + + +
+Implementation + + +
public(friend) fun new_function_info_from_address(
+    module_address: address,
+    module_name: String,
+    function_name: String,
+): FunctionInfo {
+    assert!(
+        is_identifier(string::bytes(&module_name)),
+        EINVALID_IDENTIFIER
+    );
+    assert!(
+        is_identifier(string::bytes(&function_name)),
+        EINVALID_IDENTIFIER
+    );
+    FunctionInfo {
+        module_address,
+        module_name,
+        function_name,
+    }
+}
+
+ + + +
+ + + +## Function `check_dispatch_type_compatibility` + +Check if the dispatch target function meets the type requirements of the disptach entry point. + +framework_function is the dispatch native function defined in the aptos_framework. +dispatch_target is the function passed in by the user. + +dispatch_target should have the same signature (same argument type, same generics constraint) except +that the framework_function will have a &FunctionInfo in the last argument that will instruct the VM which +function to jump to. + +dispatch_target also needs to be public so the type signature will remain unchanged. + + +
public(friend) fun check_dispatch_type_compatibility(framework_function: &function_info::FunctionInfo, dispatch_target: &function_info::FunctionInfo): bool
+
+ + + +
+Implementation + + +
public(friend) fun check_dispatch_type_compatibility(
+    framework_function: &FunctionInfo,
+    dispatch_target: &FunctionInfo,
+): bool {
+    assert!(
+        features::dispatchable_fungible_asset_enabled(),
+        error::aborted(ENOT_ACTIVATED)
+    );
+    load_function_impl(dispatch_target);
+    check_dispatch_type_compatibility_impl(framework_function, dispatch_target)
+}
+
+ + + +
+ + + +## Function `load_module_from_function` + +Load up a function into VM's loader and charge for its dependencies + +It is **critical** to make sure that this function is invoked before check_dispatch_type_compatibility +or performing any other dispatching logic to ensure: +1. We properly charge gas for the function to dispatch. +2. The function is loaded in the cache so that we can perform further type checking/dispatching logic. + +Calling check_dispatch_type_compatibility_impl or dispatch without loading up the module would yield an error +if such module isn't accessed previously in the transaction. + + +
public(friend) fun load_module_from_function(f: &function_info::FunctionInfo)
+
+ + + +
+Implementation + + +
public(friend) fun load_module_from_function(f: &FunctionInfo) {
+    load_function_impl(f)
+}
+
+ + + +
+ + + +## Function `check_dispatch_type_compatibility_impl` + + + +
fun check_dispatch_type_compatibility_impl(lhs: &function_info::FunctionInfo, r: &function_info::FunctionInfo): bool
+
+ + + +
+Implementation + + +
native fun check_dispatch_type_compatibility_impl(lhs: &FunctionInfo, r: &FunctionInfo): bool;
+
+ + + +
+ + + +## Function `is_identifier` + + + +
fun is_identifier(s: &vector<u8>): bool
+
+ + + +
+Implementation + + +
native fun is_identifier(s: &vector<u8>): bool;
+
+ + + +
+ + + +## Function `load_function_impl` + + + +
fun load_function_impl(f: &function_info::FunctionInfo)
+
+ + + +
+Implementation + + +
native fun load_function_impl(f: &FunctionInfo);
+
+ + + +
+ + + +## Specification + + + +
pragma verify = false;
+
+ + + + + +### Function `check_dispatch_type_compatibility_impl` + + +
fun check_dispatch_type_compatibility_impl(lhs: &function_info::FunctionInfo, r: &function_info::FunctionInfo): bool
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `load_function_impl` + + +
fun load_function_impl(f: &function_info::FunctionInfo)
+
+ + + + +
pragma opaque;
+
+ + +[move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/fungible_asset.md b/aptos-move/framework/aptos-framework/doc/fungible_asset.md index e616354d4a05c..5f83a147ec82d 100644 --- a/aptos-move/framework/aptos-framework/doc/fungible_asset.md +++ b/aptos-move/framework/aptos-framework/doc/fungible_asset.md @@ -11,6 +11,7 @@ metadata object can be any object that equipped with 0x1::error; use 0x1::event; use 0x1::features; +use 0x1::function_info; use 0x1::object; use 0x1::option; use 0x1::signer; @@ -242,6 +257,46 @@ The store object that holds fungible assets of a specific type associated with a
+ + + + +## Resource `DispatchFunctionStore` + + + +
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]
+struct DispatchFunctionStore has key
+
+ + + +
+Fields + + +
+
+withdraw_function: option::Option<function_info::FunctionInfo> +
+
+ +
+
+deposit_function: option::Option<function_info::FunctionInfo> +
+
+ +
+
+derived_balance_function: option::Option<function_info::FunctionInfo> +
+
+ +
+
+ +
@@ -609,12 +664,12 @@ Maximum possible coin supply. - + -Insufficient balance to withdraw or transfer. +Trying to re-register dispatch hook on a fungible asset. -
const EINSUFFICIENT_BALANCE: u64 = 4;
+
const EALREADY_REGISTERED: u64 = 29;
 
@@ -689,6 +744,26 @@ Decimals is over the maximum of 32 + + +Provided deposit function type doesn't meet the signature requirement. + + +
const EDEPOSIT_FUNCTION_SIGNATURE_MISMATCH: u64 = 26;
+
+ + + + + +Provided derived_balance function type doesn't meet the signature requirement. + + +
const EDERIVED_BALANCE_FUNCTION_SIGNATURE_MISMATCH: u64 = 27;
+
+ + + Fungible asset and store do not match. @@ -709,6 +784,36 @@ Fungible asset do not match when merging. + + +Flag for the existence of fungible store. + + +
const EFUNGIBLE_STORE_EXISTENCE: u64 = 23;
+
+ + + + + +Insufficient balance to withdraw or transfer. + + +
const EINSUFFICIENT_BALANCE: u64 = 4;
+
+ + + + + +Invalid withdraw/deposit on dispatchable token. + + +
const EINVALID_DISPATCHABLE_OPERATIONS: u64 = 28;
+
+ + + The fungible asset's supply has exceeded maximum. @@ -739,6 +844,16 @@ Name of the fungible asset metadata is too long + + +Account is not the owner of metadata object. + + +
const ENOT_METADATA_OWNER: u64 = 24;
+
+ + + Account is not the store's owner. @@ -829,6 +944,16 @@ URI for the icon of the fungible asset metadata is too long + + +Provided withdraw function type doesn't meet the signature requirement. + + +
const EWITHDRAW_FUNCTION_SIGNATURE_MISMATCH: u64 = 25;
+
+ + + @@ -935,6 +1060,117 @@ if option::some(MAX_U128) is used, it is treated as unlimited supply. + + + + +## Function `register_dispatch_functions` + +Create a fungible asset store whose transfer rule would be overloaded by the provided function. + + +
public(friend) fun register_dispatch_functions(constructor_ref: &object::ConstructorRef, withdraw_function: option::Option<function_info::FunctionInfo>, deposit_function: option::Option<function_info::FunctionInfo>, derived_balance_function: option::Option<function_info::FunctionInfo>)
+
+ + + +
+Implementation + + +
public(friend) fun register_dispatch_functions(
+    constructor_ref: &ConstructorRef,
+    withdraw_function: Option<FunctionInfo>,
+    deposit_function: Option<FunctionInfo>,
+    derived_balance_function: Option<FunctionInfo>,
+) {
+    // Verify that caller type matches callee type so wrongly typed function cannot be registered.
+    option::for_each_ref(&withdraw_function, |withdraw_function| {
+        let dispatcher_withdraw_function_info = function_info::new_function_info_from_address(
+            @aptos_framework,
+            string::utf8(b"dispatchable_fungible_asset"),
+            string::utf8(b"dispatchable_withdraw"),
+        );
+
+        assert!(
+            function_info::check_dispatch_type_compatibility(
+                &dispatcher_withdraw_function_info,
+                withdraw_function
+            ),
+            error::invalid_argument(
+                EWITHDRAW_FUNCTION_SIGNATURE_MISMATCH
+            )
+        );
+    });
+
+    option::for_each_ref(&deposit_function, |deposit_function| {
+        let dispatcher_deposit_function_info = function_info::new_function_info_from_address(
+            @aptos_framework,
+            string::utf8(b"dispatchable_fungible_asset"),
+            string::utf8(b"dispatchable_deposit"),
+        );
+        // Verify that caller type matches callee type so wrongly typed function cannot be registered.
+        assert!(
+            function_info::check_dispatch_type_compatibility(
+                &dispatcher_deposit_function_info,
+                deposit_function
+            ),
+            error::invalid_argument(
+                EDEPOSIT_FUNCTION_SIGNATURE_MISMATCH
+            )
+        );
+    });
+
+    option::for_each_ref(&derived_balance_function, |balance_function| {
+        let dispatcher_derived_balance_function_info = function_info::new_function_info_from_address(
+            @aptos_framework,
+            string::utf8(b"dispatchable_fungible_asset"),
+            string::utf8(b"dispatchable_derived_balance"),
+        );
+        // Verify that caller type matches callee type so wrongly typed function cannot be registered.
+        assert!(
+            function_info::check_dispatch_type_compatibility(
+                &dispatcher_derived_balance_function_info,
+                balance_function
+            ),
+            error::invalid_argument(
+                EDERIVED_BALANCE_FUNCTION_SIGNATURE_MISMATCH
+            )
+        );
+    });
+
+    // Cannot register hook for APT.
+    assert!(
+        object::address_from_constructor_ref(constructor_ref) != @aptos_fungible_asset,
+        error::invalid_argument(EALREADY_REGISTERED)
+    );
+    assert!(
+        !object::can_generate_delete_ref(constructor_ref),
+        error::invalid_argument(EOBJECT_IS_DELETABLE)
+    );
+    assert!(
+        !exists<DispatchFunctionStore>(
+            object::address_from_constructor_ref(constructor_ref)
+        ),
+        error::already_exists(EALREADY_REGISTERED)
+    );
+
+    let store_obj = &object::generate_signer(constructor_ref);
+
+    // Store the overload function hook.
+    move_to<DispatchFunctionStore>(
+        store_obj,
+        DispatchFunctionStore {
+            withdraw_function,
+            deposit_function,
+            derived_balance_function,
+        }
+    );
+}
+
+ + +
@@ -1303,6 +1539,37 @@ Get the balance of a given store. + + + + +## Function `is_balance_at_least` + +Check whether the balance of a given store is >= amount. + + +
#[view]
+public fun is_balance_at_least<T: key>(store: object::Object<T>, amount: u64): bool
+
+ + + +
+Implementation + + +
public fun is_balance_at_least<T: key>(store: Object<T>, amount: u64): bool acquires FungibleStore {
+    let store_addr = object::object_address(&store);
+    if (store_exists(store_addr)) {
+        borrow_store_resource(&store).balance >= amount
+    } else {
+        amount == 0
+    }
+}
+
+ + +
@@ -1331,6 +1598,184 @@ If the store has not been created, we default to returning false so deposits can + + + + +## Function `is_dispatchable` + +Return whether a fungible asset type is dispatchable. + + +
#[view]
+public fun is_dispatchable(store: object::Object<fungible_asset::Metadata>): bool
+
+ + + +
+Implementation + + +
public fun is_dispatchable(store: Object<Metadata>): bool acquires FungibleStore {
+    let fa_store = borrow_store_resource(&store);
+    let metadata_addr = object::object_address(&fa_store.metadata);
+    exists<DispatchFunctionStore>(metadata_addr)
+}
+
+ + + +
+ + + +## Function `deposit_dispatch_function` + + + +
public fun deposit_dispatch_function<T: key>(store: object::Object<T>): option::Option<function_info::FunctionInfo>
+
+ + + +
+Implementation + + +
public fun deposit_dispatch_function<T: key>(store: Object<T>): Option<FunctionInfo> acquires FungibleStore, DispatchFunctionStore {
+    let fa_store = borrow_store_resource(&store);
+    let metadata_addr = object::object_address(&fa_store.metadata);
+    if(exists<DispatchFunctionStore>(metadata_addr)) {
+        borrow_global<DispatchFunctionStore>(metadata_addr).deposit_function
+    } else {
+        option::none()
+    }
+}
+
+ + + +
+ + + +## Function `has_deposit_dispatch_function` + + + +
fun has_deposit_dispatch_function(metadata: object::Object<fungible_asset::Metadata>): bool
+
+ + + +
+Implementation + + +
fun has_deposit_dispatch_function(metadata: Object<Metadata>): bool acquires DispatchFunctionStore {
+    let metadata_addr = object::object_address(&metadata);
+    // Short circuit on APT for better perf
+    if(metadata_addr != @aptos_fungible_asset && exists<DispatchFunctionStore>(metadata_addr)) {
+        option::is_some(&borrow_global<DispatchFunctionStore>(metadata_addr).deposit_function)
+    } else {
+        false
+    }
+}
+
+ + + +
+ + + +## Function `withdraw_dispatch_function` + + + +
public fun withdraw_dispatch_function<T: key>(store: object::Object<T>): option::Option<function_info::FunctionInfo>
+
+ + + +
+Implementation + + +
public fun withdraw_dispatch_function<T: key>(store: Object<T>): Option<FunctionInfo> acquires FungibleStore, DispatchFunctionStore {
+    let fa_store = borrow_store_resource(&store);
+    let metadata_addr = object::object_address(&fa_store.metadata);
+    if(exists<DispatchFunctionStore>(metadata_addr)) {
+        borrow_global<DispatchFunctionStore>(metadata_addr).withdraw_function
+    } else {
+        option::none()
+    }
+}
+
+ + + +
+ + + +## Function `has_withdraw_dispatch_function` + + + +
fun has_withdraw_dispatch_function(metadata: object::Object<fungible_asset::Metadata>): bool
+
+ + + +
+Implementation + + +
fun has_withdraw_dispatch_function(metadata: Object<Metadata>): bool acquires DispatchFunctionStore {
+    let metadata_addr = object::object_address(&metadata);
+    // Short circuit on APT for better perf
+    if (metadata_addr != @aptos_fungible_asset && exists<DispatchFunctionStore>(metadata_addr)) {
+        option::is_some(&borrow_global<DispatchFunctionStore>(metadata_addr).withdraw_function)
+    } else {
+        false
+    }
+}
+
+ + + +
+ + + +## Function `derived_balance_dispatch_function` + + + +
public(friend) fun derived_balance_dispatch_function<T: key>(store: object::Object<T>): option::Option<function_info::FunctionInfo>
+
+ + + +
+Implementation + + +
public(friend) fun derived_balance_dispatch_function<T: key>(store: Object<T>): Option<FunctionInfo> acquires FungibleStore, DispatchFunctionStore {
+    let fa_store = borrow_store_resource(&store);
+    let metadata_addr = object::object_address(&fa_store.metadata);
+    if (exists<DispatchFunctionStore>(metadata_addr)) {
+        borrow_global<DispatchFunctionStore>(metadata_addr).derived_balance_function
+    } else {
+        option::none()
+    }
+}
+
+ + +
@@ -1454,7 +1899,7 @@ Note: it does not move the underlying object. from: Object<T>, to: Object<T>, amount: u64, -) acquires FungibleStore { +) acquires FungibleStore, DispatchFunctionStore { let fa = withdraw(sender, from, amount); deposit(to, fa); } @@ -1559,9 +2004,15 @@ Withdraw amount of the fungible asset from store by th owner: &signer, store: Object<T>, amount: u64, -): FungibleAsset acquires FungibleStore { +): FungibleAsset acquires FungibleStore, DispatchFunctionStore { assert!(object::owns(store, signer::address_of(owner)), error::permission_denied(ENOT_STORE_OWNER)); - assert!(!is_frozen(store), error::invalid_argument(ESTORE_IS_FROZEN)); + assert!(store_exists(object::object_address(&store)), error::invalid_argument(ESTORE_IS_FROZEN)); + let fa_store = borrow_store_resource(&store); + assert!( + !has_withdraw_dispatch_function(fa_store.metadata), + error::invalid_argument(EINVALID_DISPATCHABLE_OPERATIONS) + ); + assert!(!fa_store.frozen, error::invalid_argument(ESTORE_IS_FROZEN)); withdraw_internal(object::object_address(&store), amount) }
@@ -1586,8 +2037,71 @@ Deposit amount of the fungible asset to store. Implementation -
public fun deposit<T: key>(store: Object<T>, fa: FungibleAsset) acquires FungibleStore {
-    assert!(!is_frozen(store), error::invalid_argument(ESTORE_IS_FROZEN));
+
public fun deposit<T: key>(store: Object<T>, fa: FungibleAsset) acquires FungibleStore, DispatchFunctionStore {
+    assert!(store_exists(object::object_address(&store)), error::permission_denied(ESTORE_IS_FROZEN));
+    let fa_store = borrow_store_resource(&store);
+    assert!(
+        !has_deposit_dispatch_function(fa_store.metadata),
+        error::invalid_argument(EINVALID_DISPATCHABLE_OPERATIONS)
+    );
+    assert!(!fa_store.frozen, error::permission_denied(ESTORE_IS_FROZEN));
+    deposit_internal(store, fa);
+}
+
+ + + + + + + +## Function `withdraw_non_dispatch` + +Withdraw amount of the fungible asset from store by the owner. + + +
public(friend) fun withdraw_non_dispatch<T: key>(owner: &signer, store: object::Object<T>, amount: u64): fungible_asset::FungibleAsset
+
+ + + +
+Implementation + + +
public(friend) fun withdraw_non_dispatch<T: key>(
+    owner: &signer,
+    store: Object<T>,
+    amount: u64,
+): FungibleAsset acquires FungibleStore {
+    assert!(object::owns(store, signer::address_of(owner)), error::permission_denied(ENOT_STORE_OWNER));
+    assert!(!is_frozen(store), error::permission_denied(ESTORE_IS_FROZEN));
+    withdraw_internal(object::object_address(&store), amount)
+}
+
+ + + +
+ + + +## Function `deposit_non_dispatch` + +Deposit amount of the fungible asset to store. + + +
public(friend) fun deposit_non_dispatch<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset)
+
+ + + +
+Implementation + + +
public(friend) fun deposit_non_dispatch<T: key>(store: Object<T>, fa: FungibleAsset) acquires FungibleStore {
+    assert!(!is_frozen(store), error::permission_denied(ESTORE_IS_FROZEN));
     deposit_internal(store, fa);
 }
 
@@ -1613,10 +2127,36 @@ Mint the specified amount of the fungible asset.
public fun mint(ref: &MintRef, amount: u64): FungibleAsset acquires Supply, ConcurrentSupply {
-    assert!(amount > 0, error::invalid_argument(EAMOUNT_CANNOT_BE_ZERO));
     let metadata = ref.metadata;
-    increase_supply(&metadata, amount);
+    mint_internal(metadata, amount)
+}
+
+ + + +
+ + + +## Function `mint_internal` +CAN ONLY BE CALLED BY coin.move for migration. + + +
public(friend) fun mint_internal(metadata: object::Object<fungible_asset::Metadata>, amount: u64): fungible_asset::FungibleAsset
+
+ + + +
+Implementation + + +
public(friend) fun mint_internal(
+    metadata: Object<Metadata>,
+    amount: u64
+): FungibleAsset acquires Supply, ConcurrentSupply {
+    increase_supply(&metadata, amount);
     FungibleAsset {
         metadata,
         amount
@@ -1645,7 +2185,7 @@ Mint the specified amount of the fungible asset to a destination st
 
 
 
public fun mint_to<T: key>(ref: &MintRef, store: Object<T>, amount: u64)
-acquires FungibleStore, Supply, ConcurrentSupply {
+acquires FungibleStore, Supply, ConcurrentSupply, DispatchFunctionStore {
     deposit(store, mint(ref, amount));
 }
 
@@ -1679,6 +2219,33 @@ Enable/disable a store's ability to do direct transfers of the fungible asset. ref.metadata == store_metadata(store), error::invalid_argument(ETRANSFER_REF_AND_STORE_MISMATCH), ); + set_frozen_flag_internal(store, frozen) +} +
+ + + +
+ + + +## Function `set_frozen_flag_internal` + + + +
public(friend) fun set_frozen_flag_internal<T: key>(store: object::Object<T>, frozen: bool)
+
+ + + +
+Implementation + + +
public(friend) fun set_frozen_flag_internal<T: key>(
+    store: Object<T>,
+    frozen: bool
+) acquires FungibleStore {
     let store_addr = object::object_address(&store);
     borrow_global_mut<FungibleStore>(store_addr).frozen = frozen;
 
@@ -1707,12 +2274,43 @@ Burns a fungible asset
 
 
 
public fun burn(ref: &BurnRef, fa: FungibleAsset) acquires Supply, ConcurrentSupply {
+    assert!(
+        ref.metadata == metadata_from_asset(&fa),
+        error::invalid_argument(EBURN_REF_AND_FUNGIBLE_ASSET_MISMATCH)
+    );
+    burn_internal(fa);
+}
+
+ + + +
+ + + +## Function `burn_internal` + +CAN ONLY BE CALLED BY coin.move for migration. + + +
public(friend) fun burn_internal(fa: fungible_asset::FungibleAsset): u64
+
+ + + +
+Implementation + + +
public(friend) fun burn_internal(
+    fa: FungibleAsset
+): u64 acquires Supply, ConcurrentSupply {
     let FungibleAsset {
         metadata,
-        amount,
+        amount
     } = fa;
-    assert!(ref.metadata == metadata, error::invalid_argument(EBURN_REF_AND_FUNGIBLE_ASSET_MISMATCH));
     decrease_supply(&metadata, amount);
+    amount
 }
 
@@ -1968,7 +2566,7 @@ Destroy an empty fungible asset. -
fun deposit_internal<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset)
+
public(friend) fun deposit_internal<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset)
 
@@ -1977,7 +2575,7 @@ Destroy an empty fungible asset. Implementation -
fun deposit_internal<T: key>(store: Object<T>, fa: FungibleAsset) acquires FungibleStore {
+
public(friend) fun deposit_internal<T: key>(store: Object<T>, fa: FungibleAsset) acquires FungibleStore {
     let FungibleAsset { metadata, amount } = fa;
     if (amount == 0) return;
 
@@ -2002,7 +2600,7 @@ Destroy an empty fungible asset.
 Extract amount of the fungible asset from store.
 
 
-
fun withdraw_internal(store_addr: address, amount: u64): fungible_asset::FungibleAsset
+
public(friend) fun withdraw_internal(store_addr: address, amount: u64): fungible_asset::FungibleAsset
 
@@ -2011,18 +2609,18 @@ Extract amount of the fungible asset from store. Implementation -
fun withdraw_internal(
+
public(friend) fun withdraw_internal(
     store_addr: address,
     amount: u64,
 ): FungibleAsset acquires FungibleStore {
-    assert!(amount != 0, error::invalid_argument(EAMOUNT_CANNOT_BE_ZERO));
+    assert!(exists<FungibleStore>(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE));
     let store = borrow_global_mut<FungibleStore>(store_addr);
-    assert!(store.balance >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE));
-    store.balance = store.balance - amount;
-
     let metadata = store.metadata;
-    event::emit(Withdraw { store: store_addr, amount });
-
+    if (amount != 0) {
+        assert!(store.balance >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE));
+        store.balance = store.balance - amount;
+        event::emit<Withdraw>(Withdraw { store: store_addr, amount });
+    };
     FungibleAsset { metadata, amount }
 }
 
@@ -2048,7 +2646,9 @@ Increase the supply of a fungible asset by minting.
fun increase_supply<T: key>(metadata: &Object<T>, amount: u64) acquires Supply, ConcurrentSupply {
-    assert!(amount != 0, error::invalid_argument(EAMOUNT_CANNOT_BE_ZERO));
+    if (amount == 0) {
+        return
+    };
     let metadata_address = object::object_address(metadata);
 
     if (exists<ConcurrentSupply>(metadata_address)) {
@@ -2068,7 +2668,7 @@ Increase the supply of a fungible asset by minting.
         };
         supply.current = supply.current + (amount as u128);
     } else {
-        assert!(false, error::not_found(ESUPPLY_NOT_FOUND));
+        abort error::not_found(ESUPPLY_NOT_FOUND)
     }
 }
 
@@ -2094,7 +2694,9 @@ Decrease the supply of a fungible asset by burning.
fun decrease_supply<T: key>(metadata: &Object<T>, amount: u64) acquires Supply, ConcurrentSupply {
-    assert!(amount != 0, error::invalid_argument(EAMOUNT_CANNOT_BE_ZERO));
+    if (amount == 0) {
+        return
+    };
     let metadata_address = object::object_address(metadata);
 
     if (exists<ConcurrentSupply>(metadata_address)) {
@@ -2192,7 +2794,9 @@ Decrease the supply of a fungible asset by burning.
 
 
 
inline fun borrow_store_resource<T: key>(store: &Object<T>): &FungibleStore acquires FungibleStore {
-    borrow_global<FungibleStore>(object::object_address(store))
+    let store_addr = object::object_address(store);
+    assert!(exists<FungibleStore>(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE));
+    borrow_global<FungibleStore>(store_addr)
 }
 
@@ -2220,7 +2824,10 @@ Decrease the supply of a fungible asset by burning. ) acquires Supply { let metadata_object_address = object::address_from_extend_ref(ref); let metadata_object_signer = object::generate_signer_for_extending(ref); - assert!(features::concurrent_fungible_assets_enabled(), error::invalid_argument(ECONCURRENT_SUPPLY_NOT_ENABLED)); + assert!( + features::concurrent_fungible_assets_enabled(), + error::invalid_argument(ECONCURRENT_SUPPLY_NOT_ENABLED) + ); assert!(exists<Supply>(metadata_object_address), error::not_found(ESUPPLY_NOT_FOUND)); let Supply { current, diff --git a/aptos-move/framework/aptos-framework/doc/gas_schedule.md b/aptos-move/framework/aptos-framework/doc/gas_schedule.md index 395cc2f0fd92d..102058589b5eb 100644 --- a/aptos-move/framework/aptos-framework/doc/gas_schedule.md +++ b/aptos-move/framework/aptos-framework/doc/gas_schedule.md @@ -288,7 +288,7 @@ aptos_framework::aptos_governance::reconfigure(&framework_signer); Only used in reconfigurations to apply the pending GasScheduleV2, if there is any. -
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
@@ -297,11 +297,15 @@ Only used in reconfigurations to apply the pending on_new_epoch() acquires GasScheduleV2 { +
public(friend) fun on_new_epoch(framework: &signer) acquires GasScheduleV2 {
+    system_addresses::assert_aptos_framework(framework);
     if (config_buffer::does_exist<GasScheduleV2>()) {
-        let new_gas_schedule: GasScheduleV2 = config_buffer::extract<GasScheduleV2>();
-        let gas_schedule = borrow_global_mut<GasScheduleV2>(@aptos_framework);
-        *gas_schedule = new_gas_schedule;
+        let new_gas_schedule = config_buffer::extract<GasScheduleV2>();
+        if (exists<GasScheduleV2>(@aptos_framework)) {
+            *borrow_global_mut<GasScheduleV2>(@aptos_framework) = new_gas_schedule;
+        } else {
+            move_to(framework, new_gas_schedule);
+        }
     }
 }
 
@@ -506,13 +510,15 @@ Only used in reconfigurations to apply the pending on_new_epoch() +
public(friend) fun on_new_epoch(framework: &signer)
 
-
include config_buffer::OnNewEpochAbortsIf<GasScheduleV2>;
+
requires @aptos_framework == std::signer::address_of(framework);
+include config_buffer::OnNewEpochRequirement<GasScheduleV2>;
+aborts_if false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/jwk_consensus_config.md b/aptos-move/framework/aptos-framework/doc/jwk_consensus_config.md index 065046a29786c..b2f0f012886d9 100644 --- a/aptos-move/framework/aptos-framework/doc/jwk_consensus_config.md +++ b/aptos-move/framework/aptos-framework/doc/jwk_consensus_config.md @@ -18,6 +18,7 @@ Structs and functions related to JWK consensus configurations. - [Function `new_v1`](#0x1_jwk_consensus_config_new_v1) - [Function `new_oidc_provider`](#0x1_jwk_consensus_config_new_oidc_provider) - [Specification](#@Specification_1) + - [Function `on_new_epoch`](#@Specification_1_on_new_epoch)
use 0x1::config_buffer;
@@ -236,7 +237,7 @@ aptos_governance::reconfigure(&framework_signer);
 Only used in reconfigurations to apply the pending JWKConsensusConfig, if there is any.
 
 
-
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
@@ -245,10 +246,15 @@ Only used in reconfigurations to apply the pending on_new_epoch() acquires JWKConsensusConfig { +
public(friend) fun on_new_epoch(framework: &signer) acquires JWKConsensusConfig {
+    system_addresses::assert_aptos_framework(framework);
     if (config_buffer::does_exist<JWKConsensusConfig>()) {
         let new_config = config_buffer::extract<JWKConsensusConfig>();
-        borrow_global_mut<JWKConsensusConfig>(@aptos_framework).variant = new_config.variant;
+        if (exists<JWKConsensusConfig>(@aptos_framework)) {
+            *borrow_global_mut<JWKConsensusConfig>(@aptos_framework) = new_config;
+        } else {
+            move_to(framework, new_config);
+        };
     }
 }
 
@@ -351,8 +357,20 @@ Construct an + +### Function `on_new_epoch` + + +
public(friend) fun on_new_epoch(framework: &signer)
+
+ + + -
invariant [suspendable] chain_status::is_operating() ==> exists<JWKConsensusConfig>(@aptos_framework);
+
requires @aptos_framework == std::signer::address_of(framework);
+include config_buffer::OnNewEpochRequirement<JWKConsensusConfig>;
+aborts_if false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/jwks.md b/aptos-move/framework/aptos-framework/doc/jwks.md index 211afabce8bc5..e0c09f7fa7214 100644 --- a/aptos-move/framework/aptos-framework/doc/jwks.md +++ b/aptos-move/framework/aptos-framework/doc/jwks.md @@ -55,6 +55,8 @@ have a simple layout which is easily accessible in Rust. - [Function `upsert_jwk`](#0x1_jwks_upsert_jwk) - [Function `remove_jwk`](#0x1_jwks_remove_jwk) - [Function `apply_patch`](#0x1_jwks_apply_patch) +- [Specification](#@Specification_1) + - [Function `on_new_epoch`](#@Specification_1_on_new_epoch)
use 0x1::chain_status;
@@ -920,7 +922,7 @@ aptos_framework::aptos_governance::reconfigure(&framework_signer);
 Only used in reconfigurations to apply the pending SupportedOIDCProviders, if there is any.
 
 
-
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
@@ -929,9 +931,15 @@ Only used in reconfigurations to apply the pending on_new_epoch() acquires SupportedOIDCProviders { +
public(friend) fun on_new_epoch(framework: &signer) acquires SupportedOIDCProviders {
+    system_addresses::assert_aptos_framework(framework);
     if (config_buffer::does_exist<SupportedOIDCProviders>()) {
-        *borrow_global_mut<SupportedOIDCProviders>(@aptos_framework) = config_buffer::extract();
+        let new_config = config_buffer::extract<SupportedOIDCProviders>();
+        if (exists<SupportedOIDCProviders>(@aptos_framework)) {
+            *borrow_global_mut<SupportedOIDCProviders>(@aptos_framework) = new_config;
+        } else {
+            move_to(framework, new_config);
+        }
     }
 }
 
@@ -1642,5 +1650,26 @@ Maintains the sorted-by-issuer invariant in + +## Specification + + + + +### Function `on_new_epoch` + + +
public(friend) fun on_new_epoch(framework: &signer)
+
+ + + + +
requires @aptos_framework == std::signer::address_of(framework);
+include config_buffer::OnNewEpochRequirement<SupportedOIDCProviders>;
+aborts_if false;
+
+ [move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/keyless_account.md b/aptos-move/framework/aptos-framework/doc/keyless_account.md index 781b5895219b0..0afb88331c19b 100644 --- a/aptos-move/framework/aptos-framework/doc/keyless_account.md +++ b/aptos-move/framework/aptos-framework/doc/keyless_account.md @@ -13,15 +13,29 @@ This module is responsible for configuring keyless blockchain accounts which wer - [Constants](#@Constants_0) - [Function `new_groth16_verification_key`](#0x1_keyless_account_new_groth16_verification_key) - [Function `new_configuration`](#0x1_keyless_account_new_configuration) +- [Function `validate_groth16_vk`](#0x1_keyless_account_validate_groth16_vk) - [Function `update_groth16_verification_key`](#0x1_keyless_account_update_groth16_verification_key) - [Function `update_configuration`](#0x1_keyless_account_update_configuration) - [Function `update_training_wheels`](#0x1_keyless_account_update_training_wheels) - [Function `update_max_exp_horizon`](#0x1_keyless_account_update_max_exp_horizon) - [Function `remove_all_override_auds`](#0x1_keyless_account_remove_all_override_auds) - [Function `add_override_aud`](#0x1_keyless_account_add_override_aud) - - -
use 0x1::option;
+-  [Function `set_groth16_verification_key_for_next_epoch`](#0x1_keyless_account_set_groth16_verification_key_for_next_epoch)
+-  [Function `set_configuration_for_next_epoch`](#0x1_keyless_account_set_configuration_for_next_epoch)
+-  [Function `update_training_wheels_for_next_epoch`](#0x1_keyless_account_update_training_wheels_for_next_epoch)
+-  [Function `update_max_exp_horizon_for_next_epoch`](#0x1_keyless_account_update_max_exp_horizon_for_next_epoch)
+-  [Function `remove_all_override_auds_for_next_epoch`](#0x1_keyless_account_remove_all_override_auds_for_next_epoch)
+-  [Function `add_override_aud_for_next_epoch`](#0x1_keyless_account_add_override_aud_for_next_epoch)
+-  [Function `on_new_epoch`](#0x1_keyless_account_on_new_epoch)
+-  [Specification](#@Specification_1)
+
+
+
use 0x1::bn254_algebra;
+use 0x1::chain_status;
+use 0x1::config_buffer;
+use 0x1::crypto_algebra;
+use 0x1::ed25519;
+use 0x1::option;
 use 0x1::signer;
 use 0x1::string;
 use 0x1::system_addresses;
@@ -65,7 +79,7 @@ The 288-byte Groth16 verification key (VK) for the ZK relation that implements k
 
 
 
#[resource_group_member(#[group = 0x1::keyless_account::Group])]
-struct Groth16VerificationKey has store, key
+struct Groth16VerificationKey has drop, store, key
 
@@ -118,7 +132,7 @@ The 288-byte Groth16 verification key (VK) for the ZK relation that implements k
#[resource_group_member(#[group = 0x1::keyless_account::Group])]
-struct Configuration has store, key
+struct Configuration has copy, drop, store, key
 
@@ -189,6 +203,26 @@ The 288-byte Groth16 verification key (VK) for the ZK relation that implements k ## Constants + + +A serialized BN254 G1 point is invalid. + + +
const E_INVALID_BN254_G1_SERIALIZATION: u64 = 2;
+
+ + + + + +A serialized BN254 G2 point is invalid. + + +
const E_INVALID_BN254_G2_SERIALIZATION: u64 = 3;
+
+ + + The training wheels PK needs to be 32 bytes long. @@ -274,12 +308,48 @@ The training wheels PK needs to be 32 bytes long. +
+ + + +## Function `validate_groth16_vk` + +Pre-validate the VK to actively-prevent incorrect VKs from being set on-chain. + + +
fun validate_groth16_vk(vk: &keyless_account::Groth16VerificationKey)
+
+ + + +
+Implementation + + +
fun validate_groth16_vk(vk: &Groth16VerificationKey) {
+    // Could be leveraged to speed up the VM deserialization of the VK by 2x, since it can assume the points are valid.
+    assert!(option::is_some(&crypto_algebra::deserialize<bn254_algebra::G1, bn254_algebra::FormatG1Compr>(&vk.alpha_g1)), E_INVALID_BN254_G1_SERIALIZATION);
+    assert!(option::is_some(&crypto_algebra::deserialize<bn254_algebra::G2, bn254_algebra::FormatG2Compr>(&vk.beta_g2)), E_INVALID_BN254_G2_SERIALIZATION);
+    assert!(option::is_some(&crypto_algebra::deserialize<bn254_algebra::G2, bn254_algebra::FormatG2Compr>(&vk.gamma_g2)), E_INVALID_BN254_G2_SERIALIZATION);
+    assert!(option::is_some(&crypto_algebra::deserialize<bn254_algebra::G2, bn254_algebra::FormatG2Compr>(&vk.delta_g2)), E_INVALID_BN254_G2_SERIALIZATION);
+    for(i in 0..vector::length(&vk.gamma_abc_g1)) {
+        assert!(option::is_some(&crypto_algebra::deserialize<bn254_algebra::G1, bn254_algebra::FormatG1Compr>(vector::borrow(&vk.gamma_abc_g1, i))), E_INVALID_BN254_G1_SERIALIZATION);
+    };
+}
+
+ + +
## Function `update_groth16_verification_key` +Sets the Groth16 verification key, only callable during genesis. To call during governance proposals, use +set_groth16_verification_key_for_next_epoch. + +WARNING: See set_groth16_verification_key_for_next_epoch for caveats.
public fun update_groth16_verification_key(fx: &signer, vk: keyless_account::Groth16VerificationKey)
@@ -291,19 +361,10 @@ The training wheels PK needs to be 32 bytes long.
 Implementation
 
 
-
public fun update_groth16_verification_key(fx: &signer, vk: Groth16VerificationKey) acquires Groth16VerificationKey {
+
public fun update_groth16_verification_key(fx: &signer, vk: Groth16VerificationKey) {
     system_addresses::assert_aptos_framework(fx);
-
-    if (exists<Groth16VerificationKey>(signer::address_of(fx))) {
-        let Groth16VerificationKey {
-            alpha_g1: _,
-            beta_g2: _,
-            gamma_g2: _,
-            delta_g2: _,
-            gamma_abc_g1: _
-        } = move_from<Groth16VerificationKey>(signer::address_of(fx));
-    };
-
+    chain_status::assert_genesis();
+    // There should not be a previous resource set here.
     move_to(fx, vk);
 }
 
@@ -316,6 +377,10 @@ The training wheels PK needs to be 32 bytes long. ## Function `update_configuration` +Sets the keyless configuration, only callable during genesis. To call during governance proposals, use +set_configuration_for_next_epoch. + +WARNING: See set_configuration_for_next_epoch for caveats.
public fun update_configuration(fx: &signer, config: keyless_account::Configuration)
@@ -327,22 +392,10 @@ The training wheels PK needs to be 32 bytes long.
 Implementation
 
 
-
public fun update_configuration(fx: &signer, config: Configuration) acquires Configuration {
+
public fun update_configuration(fx: &signer, config: Configuration) {
     system_addresses::assert_aptos_framework(fx);
-
-    if (exists<Configuration>(signer::address_of(fx))) {
-        let Configuration {
-            override_aud_vals: _,
-            max_signatures_per_txn: _,
-            max_exp_horizon_secs: _,
-            training_wheels_pubkey: _,
-            max_commited_epk_bytes: _,
-            max_iss_val_bytes: _,
-            max_extra_field_bytes: _,
-            max_jwt_header_b64_bytes: _,
-        } = move_from<Configuration>(signer::address_of(fx));
-    };
-
+    chain_status::assert_genesis();
+    // There should not be a previous resource set here.
     move_to(fx, config);
 }
 
@@ -357,7 +410,8 @@ The training wheels PK needs to be 32 bytes long. -
public fun update_training_wheels(fx: &signer, pk: option::Option<vector<u8>>)
+
#[deprecated]
+public fun update_training_wheels(fx: &signer, pk: option::Option<vector<u8>>)
 
@@ -368,6 +422,8 @@ The training wheels PK needs to be 32 bytes long.
public fun update_training_wheels(fx: &signer, pk: Option<vector<u8>>) acquires Configuration {
     system_addresses::assert_aptos_framework(fx);
+    chain_status::assert_genesis();
+
     if (option::is_some(&pk)) {
         assert!(vector::length(option::borrow(&pk)) == 32, E_TRAINING_WHEELS_PK_WRONG_SIZE)
     };
@@ -387,7 +443,8 @@ The training wheels PK needs to be 32 bytes long.
 
 
 
-
public fun update_max_exp_horizon(fx: &signer, max_exp_horizon_secs: u64)
+
#[deprecated]
+public fun update_max_exp_horizon(fx: &signer, max_exp_horizon_secs: u64)
 
@@ -398,6 +455,7 @@ The training wheels PK needs to be 32 bytes long.
public fun update_max_exp_horizon(fx: &signer, max_exp_horizon_secs: u64) acquires Configuration {
     system_addresses::assert_aptos_framework(fx);
+    chain_status::assert_genesis();
 
     let config = borrow_global_mut<Configuration>(signer::address_of(fx));
     config.max_exp_horizon_secs = max_exp_horizon_secs;
@@ -414,7 +472,8 @@ The training wheels PK needs to be 32 bytes long.
 
 
 
-
public fun remove_all_override_auds(fx: &signer)
+
#[deprecated]
+public fun remove_all_override_auds(fx: &signer)
 
@@ -425,6 +484,7 @@ The training wheels PK needs to be 32 bytes long.
public fun remove_all_override_auds(fx: &signer) acquires Configuration {
     system_addresses::assert_aptos_framework(fx);
+    chain_status::assert_genesis();
 
     let config = borrow_global_mut<Configuration>(signer::address_of(fx));
     config.override_aud_vals = vector[];
@@ -441,7 +501,8 @@ The training wheels PK needs to be 32 bytes long.
 
 
 
-
public fun add_override_aud(fx: &signer, aud: string::String)
+
#[deprecated]
+public fun add_override_aud(fx: &signer, aud: string::String)
 
@@ -452,6 +513,7 @@ The training wheels PK needs to be 32 bytes long.
public fun add_override_aud(fx: &signer, aud: String) acquires Configuration {
     system_addresses::assert_aptos_framework(fx);
+    chain_status::assert_genesis();
 
     let config = borrow_global_mut<Configuration>(signer::address_of(fx));
     vector::push_back(&mut config.override_aud_vals, aud);
@@ -462,5 +524,278 @@ The training wheels PK needs to be 32 bytes long.
 
 
 
+
+
+## Function `set_groth16_verification_key_for_next_epoch`
+
+Queues up a change to the Groth16 verification key. The change will only be effective after reconfiguration.
+Only callable via governance proposal.
+
+WARNING: To mitigate against DoS attacks, a VK change should be done together with a training wheels PK change,
+so that old ZKPs for the old VK cannot be replayed as potentially-valid ZKPs.
+
+WARNING: If a malicious key is set, this would lead to stolen funds.
+
+
+
public fun set_groth16_verification_key_for_next_epoch(fx: &signer, vk: keyless_account::Groth16VerificationKey)
+
+ + + +
+Implementation + + +
public fun set_groth16_verification_key_for_next_epoch(fx: &signer, vk: Groth16VerificationKey) {
+    system_addresses::assert_aptos_framework(fx);
+    validate_groth16_vk(&vk);
+    config_buffer::upsert<Groth16VerificationKey>(vk);
+}
+
+ + + +
+ + + +## Function `set_configuration_for_next_epoch` + +Queues up a change to the keyless configuration. The change will only be effective after reconfiguration. Only +callable via governance proposal. + +WARNING: A malicious Configuration could lead to DoS attacks, create liveness issues, or enable a malicious +recovery service provider to phish users' accounts. + + +
public fun set_configuration_for_next_epoch(fx: &signer, config: keyless_account::Configuration)
+
+ + + +
+Implementation + + +
public fun set_configuration_for_next_epoch(fx: &signer, config: Configuration) {
+    system_addresses::assert_aptos_framework(fx);
+    config_buffer::upsert<Configuration>(config);
+}
+
+ + + +
+ + + +## Function `update_training_wheels_for_next_epoch` + +Convenience method to queue up a change to the training wheels PK. The change will only be effective after +reconfiguration. Only callable via governance proposal. + +WARNING: If a malicious key is set, this *could* lead to stolen funds. + + +
public fun update_training_wheels_for_next_epoch(fx: &signer, pk: option::Option<vector<u8>>)
+
+ + + +
+Implementation + + +
public fun update_training_wheels_for_next_epoch(fx: &signer, pk: Option<vector<u8>>) acquires Configuration {
+    system_addresses::assert_aptos_framework(fx);
+
+    // If a PK is being set, validate it first.
+    if (option::is_some(&pk)) {
+        let bytes = *option::borrow(&pk);
+        let vpk = ed25519::new_validated_public_key_from_bytes(bytes);
+        assert!(option::is_some(&vpk), E_TRAINING_WHEELS_PK_WRONG_SIZE)
+    };
+
+    let config = if (config_buffer::does_exist<Configuration>()) {
+        config_buffer::extract<Configuration>()
+    } else {
+        *borrow_global<Configuration>(signer::address_of(fx))
+    };
+
+    config.training_wheels_pubkey = pk;
+
+    set_configuration_for_next_epoch(fx, config);
+}
+
+ + + +
+ + + +## Function `update_max_exp_horizon_for_next_epoch` + +Convenience method to queues up a change to the max expiration horizon. The change will only be effective after +reconfiguration. Only callable via governance proposal. + + +
public fun update_max_exp_horizon_for_next_epoch(fx: &signer, max_exp_horizon_secs: u64)
+
+ + + +
+Implementation + + +
public fun update_max_exp_horizon_for_next_epoch(fx: &signer, max_exp_horizon_secs: u64) acquires Configuration {
+    system_addresses::assert_aptos_framework(fx);
+
+    let config = if (config_buffer::does_exist<Configuration>()) {
+        config_buffer::extract<Configuration>()
+    } else {
+        *borrow_global<Configuration>(signer::address_of(fx))
+    };
+
+    config.max_exp_horizon_secs = max_exp_horizon_secs;
+
+    set_configuration_for_next_epoch(fx, config);
+}
+
+ + + +
+ + + +## Function `remove_all_override_auds_for_next_epoch` + +Convenience method to queue up clearing the set of override aud's. The change will only be effective after +reconfiguration. Only callable via governance proposal. + +WARNING: When no override aud is set, recovery of keyless accounts associated with applications that disappeared +is no longer possible. + + +
public fun remove_all_override_auds_for_next_epoch(fx: &signer)
+
+ + + +
+Implementation + + +
public fun remove_all_override_auds_for_next_epoch(fx: &signer) acquires Configuration {
+    system_addresses::assert_aptos_framework(fx);
+
+    let config = if (config_buffer::does_exist<Configuration>()) {
+        config_buffer::extract<Configuration>()
+    } else {
+        *borrow_global<Configuration>(signer::address_of(fx))
+    };
+
+    config.override_aud_vals = vector[];
+
+    set_configuration_for_next_epoch(fx, config);
+}
+
+ + + +
+ + + +## Function `add_override_aud_for_next_epoch` + +Convenience method to queue up an append to to the set of override aud's. The change will only be effective +after reconfiguration. Only callable via governance proposal. + +WARNING: If a malicious override aud is set, this *could* lead to stolen funds. + + +
public fun add_override_aud_for_next_epoch(fx: &signer, aud: string::String)
+
+ + + +
+Implementation + + +
public fun add_override_aud_for_next_epoch(fx: &signer, aud: String) acquires Configuration {
+    system_addresses::assert_aptos_framework(fx);
+
+    let config = if (config_buffer::does_exist<Configuration>()) {
+        config_buffer::extract<Configuration>()
+    } else {
+        *borrow_global<Configuration>(signer::address_of(fx))
+    };
+
+    vector::push_back(&mut config.override_aud_vals, aud);
+
+    set_configuration_for_next_epoch(fx, config);
+}
+
+ + + +
+ + + +## Function `on_new_epoch` + +Only used in reconfigurations to apply the queued up configuration changes, if there are any. + + +
public(friend) fun on_new_epoch(fx: &signer)
+
+ + + +
+Implementation + + +
public(friend) fun on_new_epoch(fx: &signer) acquires Groth16VerificationKey, Configuration {
+    system_addresses::assert_aptos_framework(fx);
+
+    if (config_buffer::does_exist<Groth16VerificationKey>()) {
+        let vk = config_buffer::extract();
+        if (exists<Groth16VerificationKey>(@aptos_framework)) {
+            *borrow_global_mut<Groth16VerificationKey>(@aptos_framework) = vk;
+        } else {
+            move_to(fx, vk);
+        }
+    };
+
+    if(config_buffer::does_exist<Configuration>()) {
+        let config = config_buffer::extract();
+        if (exists<Configuration>(@aptos_framework)) {
+            *borrow_global_mut<Configuration>(@aptos_framework) = config;
+        } else {
+            move_to(fx, config);
+        }
+    };
+}
+
+ + + +
+ + + +## Specification + + + +
pragma verify=false;
+
+ [move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/managed_coin.md b/aptos-move/framework/aptos-framework/doc/managed_coin.md index ded5b6a28e6b2..8ae37e71a1f9c 100644 --- a/aptos-move/framework/aptos-framework/doc/managed_coin.md +++ b/aptos-move/framework/aptos-framework/doc/managed_coin.md @@ -324,7 +324,8 @@ Required if user wants to start accepting deposits of CoinType in h -
let account_addr = signer::address_of(account);
+
pragma verify = false;
+let account_addr = signer::address_of(account);
 aborts_if !exists<Capabilities<CoinType>>(account_addr);
 let coin_store = global<coin::CoinStore<CoinType>>(account_addr);
 let balance = coin_store.coin.value;
@@ -381,7 +382,8 @@ The Capabilities should not exist in the signer address.
 The dst_addr should not be frozen.
 
 
-
let account_addr = signer::address_of(account);
+
pragma verify = false;
+let account_addr = signer::address_of(account);
 // This enforces high-level requirement 3:
 aborts_if !exists<Capabilities<CoinType>>(account_addr);
 let addr = type_info::type_of<CoinType>().account_address;
@@ -410,7 +412,8 @@ An account can only be registered once.
 Updating Account.guid_creation_num will not overflow.
 
 
-
let account_addr = signer::address_of(account);
+
pragma verify = false;
+let account_addr = signer::address_of(account);
 let acc = global<account::Account>(account_addr);
 aborts_if !exists<coin::CoinStore<CoinType>>(account_addr) && acc.guid_creation_num + 2 >= account::MAX_GUID_CREATION_NUM;
 aborts_if !exists<coin::CoinStore<CoinType>>(account_addr) && acc.guid_creation_num + 2 > MAX_U64;
diff --git a/aptos-move/framework/aptos-framework/doc/multisig_account.md b/aptos-move/framework/aptos-framework/doc/multisig_account.md
index 0a4fc99f18a70..97ef3cef67eee 100644
--- a/aptos-move/framework/aptos-framework/doc/multisig_account.md
+++ b/aptos-move/framework/aptos-framework/doc/multisig_account.md
@@ -2677,8 +2677,7 @@ Create a multisig transaction, which will have one approval initially (from the
     assert!(vector::length(&payload) > 0, error::invalid_argument(EPAYLOAD_CANNOT_BE_EMPTY));
 
     assert_multisig_account_exists(multisig_account);
-    let multisig_account_resource = borrow_global_mut<MultisigAccount>(multisig_account);
-    assert_is_owner_internal(owner, multisig_account_resource);
+    assert_is_owner(owner, multisig_account);
 
     let creator = address_of(owner);
     let transaction = MultisigTransaction {
@@ -2688,7 +2687,7 @@ Create a multisig transaction, which will have one approval initially (from the
         creator,
         creation_time_secs: now_seconds(),
     };
-    add_transaction(creator, multisig_account, multisig_account_resource, transaction);
+    add_transaction(creator, multisig_account, transaction);
 }
 
@@ -2723,8 +2722,7 @@ to provide the full payload, which will be validated against the hash stored on- assert!(vector::length(&payload_hash) == 32, error::invalid_argument(EINVALID_PAYLOAD_HASH)); assert_multisig_account_exists(multisig_account); - let multisig_account_resource = borrow_global_mut<MultisigAccount>(multisig_account); - assert_is_owner_internal(owner, multisig_account_resource); + assert_is_owner(owner, multisig_account); let creator = address_of(owner); let transaction = MultisigTransaction { @@ -2734,7 +2732,7 @@ to provide the full payload, which will be validated against the hash stored on- creator, creation_time_secs: now_seconds(), }; - add_transaction(creator, multisig_account, multisig_account_resource, transaction); + add_transaction(creator, multisig_account, transaction); }
@@ -2936,8 +2934,9 @@ Remove the next transaction if it has sufficient owner rejections. multisig_account: address, ) acquires MultisigAccount { assert_multisig_account_exists(multisig_account); - let sequence_number = last_resolved_sequence_number(multisig_account) + 1; + assert_is_owner(owner, multisig_account); + let sequence_number = last_resolved_sequence_number(multisig_account) + 1; let owner_addr = address_of(owner); if(features::multisig_v2_enhancement_feature_enabled()) { // Implicitly vote for rejection if the owner has not voted for rejection yet. @@ -3249,7 +3248,7 @@ This function is private so no other code can call this beside the VM itself as -
fun add_transaction(creator: address, multisig_account_address: address, multisig_account: &mut multisig_account::MultisigAccount, transaction: multisig_account::MultisigTransaction)
+
fun add_transaction(creator: address, multisig_account: address, transaction: multisig_account::MultisigTransaction)
 
@@ -3258,33 +3257,33 @@ This function is private so no other code can call this beside the VM itself as Implementation -
fun add_transaction(
+
inline fun add_transaction(
     creator: address,
-    multisig_account_address: address,
-    multisig_account: &mut MultisigAccount,
+    multisig_account: address,
     transaction: MultisigTransaction
 ) {
     if(features::multisig_v2_enhancement_feature_enabled()) {
-        let num_pending_transactions = multisig_account.next_sequence_number - (multisig_account.last_executed_sequence_number + 1);
         assert!(
-            num_pending_transactions < MAX_PENDING_TRANSACTIONS,
+            available_transaction_queue_capacity(multisig_account) > 0,
             error::invalid_state(EMAX_PENDING_TRANSACTIONS_EXCEEDED)
         );
     };
 
+    let multisig_account_resource = borrow_global_mut<MultisigAccount>(multisig_account);
+
     // The transaction creator also automatically votes for the transaction.
     simple_map::add(&mut transaction.votes, creator, true);
 
-    let sequence_number = multisig_account.next_sequence_number;
-    multisig_account.next_sequence_number = sequence_number + 1;
-    table::add(&mut multisig_account.transactions, sequence_number, transaction);
+    let sequence_number = multisig_account_resource.next_sequence_number;
+    multisig_account_resource.next_sequence_number = sequence_number + 1;
+    table::add(&mut multisig_account_resource.transactions, sequence_number, transaction);
     if (std::features::module_event_migration_enabled()) {
         emit(
-            CreateTransaction { multisig_account: multisig_account_address, creator, sequence_number, transaction }
+            CreateTransaction { multisig_account: multisig_account, creator, sequence_number, transaction }
         );
     };
     emit_event(
-        &mut multisig_account.create_transaction_events,
+        &mut multisig_account_resource.create_transaction_events,
         CreateTransactionEvent { creator, sequence_number, transaction },
     );
 }
diff --git a/aptos-move/framework/aptos-framework/doc/object.md b/aptos-move/framework/aptos-framework/doc/object.md
index d609ea72e54b2..a16cfaa3c9ef3 100644
--- a/aptos-move/framework/aptos-framework/doc/object.md
+++ b/aptos-move/framework/aptos-framework/doc/object.md
@@ -39,6 +39,7 @@ make it so that a reference to a global object can be returned from a function.
 -  [Function `is_object`](#0x1_object_is_object)
 -  [Function `object_exists`](#0x1_object_object_exists)
 -  [Function `create_object_address`](#0x1_object_create_object_address)
+-  [Function `create_user_derived_object_address_impl`](#0x1_object_create_user_derived_object_address_impl)
 -  [Function `create_user_derived_object_address`](#0x1_object_create_user_derived_object_address)
 -  [Function `create_guid_object_address`](#0x1_object_create_guid_object_address)
 -  [Function `exists_at`](#0x1_object_exists_at)
@@ -48,6 +49,7 @@ make it so that a reference to a global object can be returned from a function.
 -  [Function `create_user_derived_object`](#0x1_object_create_user_derived_object)
 -  [Function `create_object`](#0x1_object_create_object)
 -  [Function `create_sticky_object`](#0x1_object_create_sticky_object)
+-  [Function `create_sticky_object_at_address`](#0x1_object_create_sticky_object_at_address)
 -  [Function `create_object_from_account`](#0x1_object_create_object_from_account)
 -  [Function `create_object_from_object`](#0x1_object_create_object_from_object)
 -  [Function `create_object_from_guid`](#0x1_object_create_object_from_guid)
@@ -88,6 +90,7 @@ make it so that a reference to a global object can be returned from a function.
     -  [Module-level Specification](#module-level-spec)
     -  [Function `address_to_object`](#@Specification_1_address_to_object)
     -  [Function `create_object_address`](#@Specification_1_create_object_address)
+    -  [Function `create_user_derived_object_address_impl`](#@Specification_1_create_user_derived_object_address_impl)
     -  [Function `create_user_derived_object_address`](#@Specification_1_create_user_derived_object_address)
     -  [Function `create_guid_object_address`](#@Specification_1_create_guid_object_address)
     -  [Function `exists_at`](#@Specification_1_exists_at)
@@ -97,6 +100,7 @@ make it so that a reference to a global object can be returned from a function.
     -  [Function `create_user_derived_object`](#@Specification_1_create_user_derived_object)
     -  [Function `create_object`](#@Specification_1_create_object)
     -  [Function `create_sticky_object`](#@Specification_1_create_sticky_object)
+    -  [Function `create_sticky_object_at_address`](#@Specification_1_create_sticky_object_at_address)
     -  [Function `create_object_from_account`](#@Specification_1_create_object_from_account)
     -  [Function `create_object_from_object`](#@Specification_1_create_object_from_object)
     -  [Function `create_object_from_guid`](#@Specification_1_create_object_from_guid)
@@ -842,6 +846,28 @@ Derives an object address from source material: sha3_256([creator address | seed
 
 
 
+
+
+
+
+## Function `create_user_derived_object_address_impl`
+
+
+
+
fun create_user_derived_object_address_impl(source: address, derive_from: address): address
+
+ + + +
+Implementation + + +
native fun create_user_derived_object_address_impl(source: address, derive_from: address): address;
+
+ + +
@@ -861,10 +887,14 @@ Derives an object address from the source address and an object: sha3_256([sourc
public fun create_user_derived_object_address(source: address, derive_from: address): address {
-    let bytes = bcs::to_bytes(&source);
-    vector::append(&mut bytes, bcs::to_bytes(&derive_from));
-    vector::push_back(&mut bytes, OBJECT_DERIVED_SCHEME);
-    from_bcs::to_address(hash::sha3_256(bytes))
+    if (std::features::object_native_derived_address_enabled()) {
+        create_user_derived_object_address_impl(source, derive_from)
+    } else {
+        let bytes = bcs::to_bytes(&source);
+        vector::append(&mut bytes, bcs::to_bytes(&derive_from));
+        vector::push_back(&mut bytes, OBJECT_DERIVED_SCHEME);
+        from_bcs::to_address(hash::sha3_256(bytes))
+    }
 }
 
@@ -1080,6 +1110,34 @@ Same as create_object except the object to be created will be undel + + + + +## Function `create_sticky_object_at_address` + +Create a sticky object at a specific address. Only used by aptos_framework::coin. + + +
public(friend) fun create_sticky_object_at_address(owner_address: address, object_address: address): object::ConstructorRef
+
+ + + +
+Implementation + + +
public(friend) fun create_sticky_object_at_address(
+    owner_address: address,
+    object_address: address,
+): ConstructorRef {
+    create_object_internal(owner_address, object_address, false)
+}
+
+ + +
@@ -1843,13 +1901,15 @@ hierarchy.
inline fun transfer_raw_inner(object: address, to: address) acquires ObjectCore {
     let object_core = borrow_global_mut<ObjectCore>(object);
     if (object_core.owner != to) {
-        event::emit(
-            Transfer {
-                object,
-                from: object_core.owner,
-                to,
-            },
-        );
+        if (std::features::module_event_migration_enabled()) {
+            event::emit(
+                Transfer {
+                    object,
+                    from: object_core.owner,
+                    to,
+                },
+            );
+        };
         event::emit_event(
             &mut object_core.transfer_events,
             TransferEvent {
@@ -2278,6 +2338,32 @@ Return true if the provided address has indirect or direct ownership of the prov
 
 
 
+
+
+
+
+
fun spec_create_user_derived_object_address_impl(source: address, derive_from: address): address;
+
+ + + + + +### Function `create_user_derived_object_address_impl` + + +
fun create_user_derived_object_address_impl(source: address, derive_from: address): address
+
+ + + + +
pragma opaque;
+ensures [abstract] result == spec_create_user_derived_object_address_impl(source, derive_from);
+
+ + + ### Function `create_user_derived_object_address` @@ -2503,6 +2589,22 @@ Return true if the provided address has indirect or direct ownership of the prov + + +### Function `create_sticky_object_at_address` + + +
public(friend) fun create_sticky_object_at_address(owner_address: address, object_address: address): object::ConstructorRef
+
+ + + + +
pragma verify = false;
+
+ + + ### Function `create_object_from_account` diff --git a/aptos-move/framework/aptos-framework/doc/overloadable_fungible_asset.md b/aptos-move/framework/aptos-framework/doc/overloadable_fungible_asset.md new file mode 100644 index 0000000000000..d6b1cd21e0043 --- /dev/null +++ b/aptos-move/framework/aptos-framework/doc/overloadable_fungible_asset.md @@ -0,0 +1,414 @@ + + + +# Module `0x1::overloadable_fungible_asset` + +This defines the fungible asset module that can issue fungible asset of any Metadata object. The +metadata object can be any object that equipped with Metadata resource. + +The overloadable_fungible_asset wraps the existing fungible_asset module and adds the ability for token issuer +to customize the logic for withdraw and deposit operations. For example: + +- Deflation token: a fixed percentage of token will be destructed upon transfer. +- Transfer allowlist: token can only be transfered to addresses in the allow list. +- Predicated transfer: transfer can only happen when some certain predicate has been met. +- Loyalty token: a fixed loyalty will be paid to a designated address when a fungible asset transfer happens + +See AIP-73 for further discussion + + +- [Resource `OverloadFunctionStore`](#0x1_overloadable_fungible_asset_OverloadFunctionStore) +- [Constants](#@Constants_0) +- [Function `register_overload_functions`](#0x1_overloadable_fungible_asset_register_overload_functions) +- [Function `withdraw`](#0x1_overloadable_fungible_asset_withdraw) +- [Function `deposit`](#0x1_overloadable_fungible_asset_deposit) +- [Function `transfer_fixed_send`](#0x1_overloadable_fungible_asset_transfer_fixed_send) +- [Function `transfer_fixed_receive`](#0x1_overloadable_fungible_asset_transfer_fixed_receive) +- [Function `dispatchable_withdraw`](#0x1_overloadable_fungible_asset_dispatchable_withdraw) +- [Function `dispatchable_deposit`](#0x1_overloadable_fungible_asset_dispatchable_deposit) + + +
use 0x1::error;
+use 0x1::function_info;
+use 0x1::fungible_asset;
+use 0x1::object;
+use 0x1::signer;
+use 0x1::string;
+
+ + + + + +## Resource `OverloadFunctionStore` + + + +
#[resource_group_member(#[group = 0x1::object::ObjectGroup])]
+struct OverloadFunctionStore has key
+
+ + + +
+Fields + + +
+
+withdraw_function: function_info::FunctionInfo +
+
+ +
+
+deposit_function: function_info::FunctionInfo +
+
+ +
+
+transfer_ref: fungible_asset::TransferRef +
+
+ +
+
+ + +
+ + + +## Constants + + + + +Trying to register overload functions to fungible asset that has already been initialized with custom transfer function. + + +
const EALREADY_REGISTERED: u64 = 5;
+
+ + + + + +Fungibility is only available for non-deletable objects. + + +
const EOBJECT_IS_DELETABLE: u64 = 18;
+
+ + + + + +Recipient is not getting the guaranteed value; + + +
const EAMOUNT_MISMATCH: u64 = 4;
+
+ + + + + +Provided deposit function type doesn't meet the signature requirement. + + +
const EDEPOSIT_FUNCTION_SIGNATURE_MISMATCH: u64 = 2;
+
+ + + + + +Calling overloadable api on non-overloadable fungible asset store. + + +
const EFUNCTION_STORE_NOT_FOUND: u64 = 3;
+
+ + + + + +Provided withdraw function type doesn't meet the signature requirement. + + +
const EWITHDRAW_FUNCTION_SIGNATURE_MISMATCH: u64 = 1;
+
+ + + + + +## Function `register_overload_functions` + +Create a fungible asset store whose transfer rule would be overloaded by the provided function. + + +
public fun register_overload_functions(constructor_ref: &object::ConstructorRef, withdraw_function: function_info::FunctionInfo, deposit_function: function_info::FunctionInfo)
+
+ + + +
+Implementation + + +
public fun register_overload_functions(
+    constructor_ref: &ConstructorRef,
+    withdraw_function: FunctionInfo,
+		deposit_function: FunctionInfo,
+) {
+    let dispatcher_withdraw_function_info = function_info::new_function_info(
+	        @aptos_framework,
+        string::utf8(b"overloadable_fungible_asset"),
+        string::utf8(b"dispatchable_withdraw"),
+    );
+    // Verify that caller type matches callee type so wrongly typed function cannot be registered.
+    assert!(function_info::check_dispatch_type_compatibility(
+        &dispatcher_withdraw_function_info,
+        &withdraw_function
+    ), error::invalid_argument(EWITHDRAW_FUNCTION_SIGNATURE_MISMATCH));
+
+    let dispatcher_deposit_function_info = function_info::new_function_info(
+	        @aptos_framework,
+        string::utf8(b"overloadable_fungible_asset"),
+        string::utf8(b"dispatchable_deposit"),
+    );
+    // Verify that caller type matches callee type so wrongly typed function cannot be registered.
+    assert!(function_info::check_dispatch_type_compatibility(
+        &dispatcher_deposit_function_info,
+        &deposit_function
+    ), error::invalid_argument(EDEPOSIT_FUNCTION_SIGNATURE_MISMATCH));
+
+    assert!(!object::can_generate_delete_ref(constructor_ref), error::invalid_argument(EOBJECT_IS_DELETABLE));
+    assert!(!exists<OverloadFunctionStore>(object::address_from_constructor_ref(constructor_ref)), error::already_exists(EALREADY_REGISTERED));
+
+    // Freeze the FungibleStore to force usign the new overloaded api.
+    let extend_ref = object::generate_extend_ref(constructor_ref);
+    fungible_asset::set_global_frozen_flag(&extend_ref, true);
+
+    let store_obj = &object::generate_signer(constructor_ref);
+
+    // Store the overload function hook.
+    move_to<OverloadFunctionStore>(store_obj, OverloadFunctionStore {
+        withdraw_function,
+		    deposit_function,
+        transfer_ref: fungible_asset::generate_transfer_ref(constructor_ref),
+    });
+}
+
+ + + +
+ + + +## Function `withdraw` + +Withdraw amount of the fungible asset from store by the owner. + +The semantics of deposit will be governed by the function specified in OverloadFunctionStore. + + +
public fun withdraw<T: key>(owner: &signer, store: object::Object<T>, amount: u64): fungible_asset::FungibleAsset
+
+ + + +
+Implementation + + +
public fun withdraw<T: key>(
+    owner: &signer,
+    store: Object<T>,
+    amount: u64,
+): FungibleAsset acquires OverloadFunctionStore {
+    let metadata_addr = object::object_address(&fungible_asset::store_metadata(store));
+    let owner_address = signer::address_of(owner);
+    assert!(exists<OverloadFunctionStore>(metadata_addr), error::not_found(EFUNCTION_STORE_NOT_FOUND));
+    let overloadable_store = borrow_global<OverloadFunctionStore>(metadata_addr);
+    dispatchable_withdraw(
+        owner_address,
+        store,
+        amount,
+        &overloadable_store.transfer_ref,
+        &overloadable_store.withdraw_function,
+    )
+}
+
+ + + +
+ + + +## Function `deposit` + +Deposit amount of the fungible asset to store. + +The semantics of deposit will be governed by the function specified in OverloadFunctionStore. + + +
public fun deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset)
+
+ + + +
+Implementation + + +
public fun deposit<T: key>(
+    store: Object<T>,
+    fa: FungibleAsset
+) acquires OverloadFunctionStore {
+    let metadata_addr = object::object_address(&fungible_asset::store_metadata(store));
+    assert!(exists<OverloadFunctionStore>(metadata_addr), error::not_found(EFUNCTION_STORE_NOT_FOUND));
+    let overloadable_store = borrow_global<OverloadFunctionStore>(metadata_addr);
+    dispatchable_deposit(
+        store,
+        fa,
+        &overloadable_store.transfer_ref,
+        &overloadable_store.deposit_function,
+    );
+}
+
+ + + +
+ + + +## Function `transfer_fixed_send` + +A transfer with a fixed amount debited from the sender + + +
public fun transfer_fixed_send<T: key>(_sender: &signer, from: object::Object<T>, to: object::Object<T>, send_amount: u64)
+
+ + + +
+Implementation + + +
public fun transfer_fixed_send<T: key>(
+    _sender: &signer,
+    from: Object<T>,
+    to: Object<T>,
+    send_amount: u64,
+) acquires OverloadFunctionStore {
+    let metadata_addr = object::object_address(&fungible_asset::store_metadata(from));
+    assert!(exists<OverloadFunctionStore>(metadata_addr), error::not_found(EFUNCTION_STORE_NOT_FOUND));
+    let overloadable_store = borrow_global<OverloadFunctionStore>(metadata_addr);
+    let fa = fungible_asset::withdraw_with_ref(&overloadable_store.transfer_ref, from, send_amount);
+    deposit(to, fa);
+}
+
+ + + +
+ + + +## Function `transfer_fixed_receive` + +A transfer with a fixed amount credited to the recipient + + +
public fun transfer_fixed_receive<T: key>(sender: &signer, from: object::Object<T>, to: object::Object<T>, receive_amount: u64)
+
+ + + +
+Implementation + + +
public fun transfer_fixed_receive<T: key>(
+    sender: &signer,
+    from: Object<T>,
+    to: Object<T>,
+    receive_amount: u64,
+) acquires OverloadFunctionStore {
+    let fa = withdraw(sender, from, receive_amount);
+    let metadata_addr = object::object_address(&fungible_asset::store_metadata(from));
+    let overloadable_store = borrow_global<OverloadFunctionStore>(metadata_addr);
+    assert!(fungible_asset::amount(&fa) == receive_amount, error::aborted(EAMOUNT_MISMATCH));
+    fungible_asset::deposit_with_ref(&overloadable_store.transfer_ref, to, fa);
+}
+
+ + + +
+ + + +## Function `dispatchable_withdraw` + + + +
fun dispatchable_withdraw<T: key>(owner: address, store: object::Object<T>, amount: u64, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo): fungible_asset::FungibleAsset
+
+ + + +
+Implementation + + +
native fun dispatchable_withdraw<T: key>(
+    owner: address,
+    store: Object<T>,
+    amount: u64,
+    transfer_ref: &TransferRef,
+    function: &FunctionInfo,
+): FungibleAsset;
+
+ + + +
+ + + +## Function `dispatchable_deposit` + + + +
fun dispatchable_deposit<T: key>(store: object::Object<T>, fa: fungible_asset::FungibleAsset, transfer_ref: &fungible_asset::TransferRef, function: &function_info::FunctionInfo)
+
+ + + +
+Implementation + + +
native fun dispatchable_deposit<T: key>(
+    store: Object<T>,
+    fa: FungibleAsset,
+    transfer_ref: &TransferRef,
+    function: &FunctionInfo,
+);
+
+ + + +
+ + +[move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/overview.md b/aptos-move/framework/aptos-framework/doc/overview.md index b664590e84026..314baa3612ba9 100644 --- a/aptos-move/framework/aptos-framework/doc/overview.md +++ b/aptos-move/framework/aptos-framework/doc/overview.md @@ -28,9 +28,11 @@ This is the reference documentation of the Aptos framework. - [`0x1::consensus_config`](consensus_config.md#0x1_consensus_config) - [`0x1::create_signer`](create_signer.md#0x1_create_signer) - [`0x1::delegation_pool`](delegation_pool.md#0x1_delegation_pool) +- [`0x1::dispatchable_fungible_asset`](dispatchable_fungible_asset.md#0x1_dispatchable_fungible_asset) - [`0x1::dkg`](dkg.md#0x1_dkg) - [`0x1::event`](event.md#0x1_event) - [`0x1::execution_config`](execution_config.md#0x1_execution_config) +- [`0x1::function_info`](function_info.md#0x1_function_info) - [`0x1::fungible_asset`](fungible_asset.md#0x1_fungible_asset) - [`0x1::gas_schedule`](gas_schedule.md#0x1_gas_schedule) - [`0x1::genesis`](genesis.md#0x1_genesis) @@ -46,6 +48,7 @@ This is the reference documentation of the Aptos framework. - [`0x1::optional_aggregator`](optional_aggregator.md#0x1_optional_aggregator) - [`0x1::primary_fungible_store`](primary_fungible_store.md#0x1_primary_fungible_store) - [`0x1::randomness`](randomness.md#0x1_randomness) +- [`0x1::randomness_api_v0_config`](randomness_api_v0_config.md#0x1_randomness_api_v0_config) - [`0x1::randomness_config`](randomness_config.md#0x1_randomness_config) - [`0x1::randomness_config_seqnum`](randomness_config_seqnum.md#0x1_randomness_config_seqnum) - [`0x1::reconfiguration`](reconfiguration.md#0x1_reconfiguration) diff --git a/aptos-move/framework/aptos-framework/doc/primary_fungible_store.md b/aptos-move/framework/aptos-framework/doc/primary_fungible_store.md index b04e9f0e3b1b5..600a6ee0ccd28 100644 --- a/aptos-move/framework/aptos-framework/doc/primary_fungible_store.md +++ b/aptos-move/framework/aptos-framework/doc/primary_fungible_store.md @@ -26,10 +26,13 @@ fungible asset to it. This emits an deposit event. - [Function `primary_store`](#0x1_primary_fungible_store_primary_store) - [Function `primary_store_exists`](#0x1_primary_fungible_store_primary_store_exists) - [Function `balance`](#0x1_primary_fungible_store_balance) +- [Function `is_balance_at_least`](#0x1_primary_fungible_store_is_balance_at_least) - [Function `is_frozen`](#0x1_primary_fungible_store_is_frozen) - [Function `withdraw`](#0x1_primary_fungible_store_withdraw) - [Function `deposit`](#0x1_primary_fungible_store_deposit) +- [Function `force_deposit`](#0x1_primary_fungible_store_force_deposit) - [Function `transfer`](#0x1_primary_fungible_store_transfer) +- [Function `transfer_assert_minimum_deposit`](#0x1_primary_fungible_store_transfer_assert_minimum_deposit) - [Function `mint`](#0x1_primary_fungible_store_mint) - [Function `burn`](#0x1_primary_fungible_store_burn) - [Function `set_frozen_flag`](#0x1_primary_fungible_store_set_frozen_flag) @@ -42,7 +45,9 @@ fungible asset to it. This emits an deposit event. - [Module-level Specification](#module-level-spec) -
use 0x1::fungible_asset;
+
use 0x1::dispatchable_fungible_asset;
+use 0x1::features;
+use 0x1::fungible_asset;
 use 0x1::object;
 use 0x1::option;
 use 0x1::signer;
@@ -184,8 +189,12 @@ Create a primary store object to hold fungible asset for the given address.
     let metadata_addr = object::object_address(&metadata);
     object::address_to_object<Metadata>(metadata_addr);
     let derive_ref = &borrow_global<DeriveRefPod>(metadata_addr).metadata_derive_ref;
-    let constructor_ref = &object::create_user_derived_object(owner_addr, derive_ref);
-
+    let constructor_ref = if (metadata_addr == @aptos_fungible_asset && features::primary_apt_fungible_store_at_user_address_enabled(
+    )) {
+        &object::create_sticky_object_at_address(owner_addr, owner_addr)
+    } else {
+        &object::create_user_derived_object(owner_addr, derive_ref)
+    };
     // Disable ungated transfer as deterministic stores shouldn't be transferrable.
     let transfer_ref = &object::generate_transfer_ref(constructor_ref);
     object::disable_ungated_transfer(transfer_ref);
@@ -217,7 +226,11 @@ Get the address of the primary store for the given account.
 
 
public fun primary_store_address<T: key>(owner: address, metadata: Object<T>): address {
     let metadata_addr = object::object_address(&metadata);
-    object::create_user_derived_object_address(owner, metadata_addr)
+    if (metadata_addr == @aptos_fungible_asset && features::primary_apt_fungible_store_at_user_address_enabled()) {
+        owner
+    } else {
+        object::create_user_derived_object_address(owner, metadata_addr)
+    }
 }
 
@@ -306,6 +319,35 @@ Get the balance of account's p + + + + +## Function `is_balance_at_least` + + + +
#[view]
+public fun is_balance_at_least<T: key>(account: address, metadata: object::Object<T>, amount: u64): bool
+
+ + + +
+Implementation + + +
public fun is_balance_at_least<T: key>(account: address, metadata: Object<T>, amount: u64): bool {
+    if (primary_store_exists(account, metadata)) {
+        fungible_asset::is_balance_at_least(primary_store(account, metadata), amount)
+    } else {
+        amount == 0
+    }
+}
+
+ + +
@@ -354,11 +396,11 @@ Withdraw amount of fungible asset from the given account's primary Implementation -
public fun withdraw<T: key>(owner: &signer, metadata: Object<T>, amount: u64): FungibleAsset {
-    let store = primary_store(signer::address_of(owner), metadata);
+
public fun withdraw<T: key>(owner: &signer, metadata: Object<T>, amount: u64): FungibleAsset acquires DeriveRefPod {
+    let store = ensure_primary_store_exists(signer::address_of(owner), metadata);
     // Check if the store object has been burnt or not. If so, unburn it first.
     may_be_unburn(owner, store);
-    fungible_asset::withdraw(owner, store, amount)
+    dispatchable_fungible_asset::withdraw(owner, store, amount)
 }
 
@@ -385,7 +427,34 @@ Deposit fungible asset fa to the given account's primary store.
public fun deposit(owner: address, fa: FungibleAsset) acquires DeriveRefPod {
     let metadata = fungible_asset::asset_metadata(&fa);
     let store = ensure_primary_store_exists(owner, metadata);
-    fungible_asset::deposit(store, fa);
+    dispatchable_fungible_asset::deposit(store, fa);
+}
+
+ + + + + + + +## Function `force_deposit` + +Deposit fungible asset fa to the given account's primary store. + + +
public(friend) fun force_deposit(owner: address, fa: fungible_asset::FungibleAsset)
+
+ + + +
+Implementation + + +
public(friend) fun force_deposit(owner: address, fa: FungibleAsset) acquires DeriveRefPod {
+    let metadata = fungible_asset::asset_metadata(&fa);
+    let store = ensure_primary_store_exists(owner, metadata);
+    fungible_asset::deposit_internal(store, fa);
 }
 
@@ -419,7 +488,49 @@ Transfer amount of fungible asset from sender's primary store to re // Check if the sender store object has been burnt or not. If so, unburn it first. may_be_unburn(sender, sender_store); let recipient_store = ensure_primary_store_exists(recipient, metadata); - fungible_asset::transfer(sender, sender_store, recipient_store, amount); + dispatchable_fungible_asset::transfer(sender, sender_store, recipient_store, amount); +} +
+ + + + + + + +## Function `transfer_assert_minimum_deposit` + +Transfer amount of fungible asset from sender's primary store to receiver's primary store. +Use the minimum deposit assertion api to make sure receipient will receive a minimum amount of fund. + + +
public entry fun transfer_assert_minimum_deposit<T: key>(sender: &signer, metadata: object::Object<T>, recipient: address, amount: u64, expected: u64)
+
+ + + +
+Implementation + + +
public entry fun transfer_assert_minimum_deposit<T: key>(
+    sender: &signer,
+    metadata: Object<T>,
+    recipient: address,
+    amount: u64,
+    expected: u64,
+) acquires DeriveRefPod {
+    let sender_store = ensure_primary_store_exists(signer::address_of(sender), metadata);
+    // Check if the sender store object has been burnt or not. If so, unburn it first.
+    may_be_unburn(sender, sender_store);
+    let recipient_store = ensure_primary_store_exists(recipient, metadata);
+    dispatchable_fungible_asset::transfer_assert_minimum_deposit(
+        sender,
+        sender_store,
+        recipient_store,
+        amount,
+        expected
+    );
 }
 
@@ -744,4 +855,33 @@ Transfer amount of FA from the primary store of from t
+ + + + + +
fun spec_primary_store_exists<T: key>(account: address, metadata: Object<T>): bool {
+   fungible_asset::store_exists(spec_primary_store_address(account, metadata))
+}
+
+ + + + + + + +
fun spec_primary_store_address<T: key>(owner: address, metadata: Object<T>): address {
+   let metadata_addr = object::object_address(metadata);
+   if (metadata_addr == @aptos_fungible_asset && features::spec_is_enabled(
+       features::PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS
+   )) {
+       owner
+   } else {
+       object::spec_create_user_derived_object_address(owner, metadata_addr)
+   }
+}
+
+ + [move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/randomness.md b/aptos-move/framework/aptos-framework/doc/randomness.md index 4d59e3571c71b..a0a73e8d7ca33 100644 --- a/aptos-move/framework/aptos-framework/doc/randomness.md +++ b/aptos-move/framework/aptos-framework/doc/randomness.md @@ -189,13 +189,13 @@ Event emitted every time a public randomness API in this module is called. - + Randomness APIs calls must originate from a private entry function with -#[randomness] annotation. Otherwise, test-and-abort attacks are possible. +#[randomness] annotation. Otherwise, malicious users can bias randomness result. -
const E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT: u64 = 1;
+
const E_API_USE_IS_BIASIBLE: u64 = 1;
 
@@ -282,7 +282,7 @@ of the hash function).
fun next_32_bytes(): vector<u8> acquires PerBlockRandomness {
-    assert!(is_unbiasable(), E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT);
+    assert!(is_unbiasable(), E_API_USE_IS_BIASIBLE);
 
     let input = DST;
     let randomness = borrow_global<PerBlockRandomness>(@aptos_framework);
@@ -940,7 +940,7 @@ Compute (a + b) % m, assuming m >= 1, 0 <= a < m, 0&
 ## Function `fetch_and_increment_txn_counter`
 
 Fetches and increments a transaction-specific 32-byte randomness-related counter.
-Aborts with E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT if randomness is not unbiasable.
+Aborts with E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT if randomness is not unbiasable.
 
 
 
fun fetch_and_increment_txn_counter(): vector<u8>
diff --git a/aptos-move/framework/aptos-framework/doc/randomness_api_v0_config.md b/aptos-move/framework/aptos-framework/doc/randomness_api_v0_config.md
new file mode 100644
index 0000000000000..017747749cb9e
--- /dev/null
+++ b/aptos-move/framework/aptos-framework/doc/randomness_api_v0_config.md
@@ -0,0 +1,146 @@
+
+
+
+# Module `0x1::randomness_api_v0_config`
+
+
+
+-  [Resource `RequiredGasDeposit`](#0x1_randomness_api_v0_config_RequiredGasDeposit)
+-  [Function `initialize`](#0x1_randomness_api_v0_config_initialize)
+-  [Function `set_for_next_epoch`](#0x1_randomness_api_v0_config_set_for_next_epoch)
+-  [Function `on_new_epoch`](#0x1_randomness_api_v0_config_on_new_epoch)
+-  [Specification](#@Specification_0)
+
+
+
use 0x1::chain_status;
+use 0x1::config_buffer;
+use 0x1::option;
+use 0x1::system_addresses;
+
+ + + + + +## Resource `RequiredGasDeposit` + + + +
struct RequiredGasDeposit has drop, store, key
+
+ + + +
+Fields + + +
+
+gas_amount: option::Option<u64> +
+
+ +
+
+ + +
+ + + +## Function `initialize` + +Only used in genesis. + + +
fun initialize(framework: &signer, required_amount: randomness_api_v0_config::RequiredGasDeposit)
+
+ + + +
+Implementation + + +
fun initialize(framework: &signer, required_amount: RequiredGasDeposit) {
+    system_addresses::assert_aptos_framework(framework);
+    chain_status::assert_genesis();
+    move_to(framework, required_amount)
+}
+
+ + + +
+ + + +## Function `set_for_next_epoch` + +This can be called by on-chain governance to update RequiredGasDeposit for the next epoch. + + +
public fun set_for_next_epoch(framework: &signer, gas_amount: option::Option<u64>)
+
+ + + +
+Implementation + + +
public fun set_for_next_epoch(framework: &signer, gas_amount: Option<u64>) {
+    system_addresses::assert_aptos_framework(framework);
+    config_buffer::upsert(RequiredGasDeposit { gas_amount });
+}
+
+ + + +
+ + + +## Function `on_new_epoch` + +Only used in reconfigurations to apply the pending RequiredGasDeposit, if there is any. + + +
public fun on_new_epoch(framework: &signer)
+
+ + + +
+Implementation + + +
public fun on_new_epoch(framework: &signer) acquires RequiredGasDeposit {
+    system_addresses::assert_aptos_framework(framework);
+    if (config_buffer::does_exist<RequiredGasDeposit>()) {
+        let new_config = config_buffer::extract<RequiredGasDeposit>();
+        if (exists<RequiredGasDeposit>(@aptos_framework)) {
+            *borrow_global_mut<RequiredGasDeposit>(@aptos_framework) = new_config;
+        } else {
+            move_to(framework, new_config);
+        }
+    }
+}
+
+ + + +
+ + + +## Specification + + + +
pragma verify = false;
+
+ + +[move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/randomness_config.md b/aptos-move/framework/aptos-framework/doc/randomness_config.md index b4c76d80473f0..b658b03cdd6c0 100644 --- a/aptos-move/framework/aptos-framework/doc/randomness_config.md +++ b/aptos-move/framework/aptos-framework/doc/randomness_config.md @@ -20,6 +20,7 @@ Structs and functions for on-chain randomness configurations. - [Function `new_v2`](#0x1_randomness_config_new_v2) - [Function `current`](#0x1_randomness_config_current) - [Specification](#@Specification_1) + - [Function `on_new_epoch`](#@Specification_1_on_new_epoch) - [Function `current`](#@Specification_1_current) @@ -240,7 +241,7 @@ This can be called by on-chain governance to update on-chain consensus configs f Only used in reconfigurations to apply the pending RandomnessConfig, if there is any. -
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
@@ -249,10 +250,15 @@ Only used in reconfigurations to apply the pending on_new_epoch() acquires RandomnessConfig { +
public(friend) fun on_new_epoch(framework: &signer) acquires RandomnessConfig {
+    system_addresses::assert_aptos_framework(framework);
     if (config_buffer::does_exist<RandomnessConfig>()) {
         let new_config = config_buffer::extract<RandomnessConfig>();
-        borrow_global_mut<RandomnessConfig>(@aptos_framework).variant = new_config.variant;
+        if (exists<RandomnessConfig>(@aptos_framework)) {
+            *borrow_global_mut<RandomnessConfig>(@aptos_framework) = new_config;
+        } else {
+            move_to(framework, new_config);
+        }
     }
 }
 
@@ -421,8 +427,20 @@ Get the currently effective randomness configuration object. ## Specification + + +### Function `on_new_epoch` + + +
public(friend) fun on_new_epoch(framework: &signer)
+
+ + + -
invariant [suspendable] chain_status::is_operating() ==> exists<RandomnessConfig>(@aptos_framework);
+
requires @aptos_framework == std::signer::address_of(framework);
+include config_buffer::OnNewEpochRequirement<RandomnessConfig>;
+aborts_if false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/randomness_config_seqnum.md b/aptos-move/framework/aptos-framework/doc/randomness_config_seqnum.md index 3dc9ca128801b..e9efed50c38e8 100644 --- a/aptos-move/framework/aptos-framework/doc/randomness_config_seqnum.md +++ b/aptos-move/framework/aptos-framework/doc/randomness_config_seqnum.md @@ -18,6 +18,8 @@ a governance proposal is needed to set 0x1::config_buffer; @@ -117,7 +119,7 @@ Initialize the configuration. Used in genesis or governance. Only used in reconfigurations to apply the pending RandomnessConfig, if there is any. -
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
@@ -126,10 +128,15 @@ Only used in reconfigurations to apply the pending RandomnessConfig Implementation -
public(friend) fun on_new_epoch() acquires RandomnessConfigSeqNum {
+
public(friend) fun on_new_epoch(framework: &signer) acquires RandomnessConfigSeqNum {
+    system_addresses::assert_aptos_framework(framework);
     if (config_buffer::does_exist<RandomnessConfigSeqNum>()) {
         let new_config = config_buffer::extract<RandomnessConfigSeqNum>();
-        borrow_global_mut<RandomnessConfigSeqNum>(@aptos_framework).seq_num = new_config.seq_num;
+        if (exists<RandomnessConfigSeqNum>(@aptos_framework)) {
+            *borrow_global_mut<RandomnessConfigSeqNum>(@aptos_framework) = new_config;
+        } else {
+            move_to(framework, new_config);
+        }
     }
 }
 
@@ -138,5 +145,26 @@ Only used in reconfigurations to apply the pending RandomnessConfig + + +## Specification + + + + +### Function `on_new_epoch` + + +
public(friend) fun on_new_epoch(framework: &signer)
+
+ + + + +
requires @aptos_framework == std::signer::address_of(framework);
+include config_buffer::OnNewEpochRequirement<RandomnessConfigSeqNum>;
+aborts_if false;
+
+ [move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/reconfiguration_with_dkg.md b/aptos-move/framework/aptos-framework/doc/reconfiguration_with_dkg.md index 4a81dc0e84e46..e479eccd81f86 100644 --- a/aptos-move/framework/aptos-framework/doc/reconfiguration_with_dkg.md +++ b/aptos-move/framework/aptos-framework/doc/reconfiguration_with_dkg.md @@ -22,12 +22,15 @@ Reconfiguration with DKG helper functions. use 0x1::gas_schedule; use 0x1::jwk_consensus_config; use 0x1::jwks; +use 0x1::keyless_account; use 0x1::option; +use 0x1::randomness_api_v0_config; use 0x1::randomness_config; use 0x1::randomness_config_seqnum; use 0x1::reconfiguration; use 0x1::reconfiguration_state; use 0x1::stake; +use 0x1::system_addresses; use 0x1::validator_consensus_info; use 0x1::version;
@@ -84,7 +87,7 @@ Re-enable validator set changes. Run the default reconfiguration to enter the new epoch. -
public(friend) fun finish(account: &signer)
+
public(friend) fun finish(framework: &signer)
 
@@ -93,17 +96,20 @@ Run the default reconfiguration to enter the new epoch. Implementation -
public(friend) fun finish(account: &signer) {
-    dkg::try_clear_incomplete_session(account);
-    consensus_config::on_new_epoch();
-    execution_config::on_new_epoch();
-    gas_schedule::on_new_epoch();
-    std::version::on_new_epoch();
-    jwk_consensus_config::on_new_epoch();
-    jwks::on_new_epoch();
-    randomness_config_seqnum::on_new_epoch();
-    randomness_config::on_new_epoch();
-    features::on_new_epoch(account);
+
public(friend) fun finish(framework: &signer) {
+    system_addresses::assert_aptos_framework(framework);
+    dkg::try_clear_incomplete_session(framework);
+    consensus_config::on_new_epoch(framework);
+    execution_config::on_new_epoch(framework);
+    gas_schedule::on_new_epoch(framework);
+    std::version::on_new_epoch(framework);
+    features::on_new_epoch(framework);
+    jwk_consensus_config::on_new_epoch(framework);
+    jwks::on_new_epoch(framework);
+    keyless_account::on_new_epoch(framework);
+    randomness_config_seqnum::on_new_epoch(framework);
+    randomness_config::on_new_epoch(framework);
+    randomness_api_v0_config::on_new_epoch(framework);
     reconfiguration::reconfigure();
 }
 
@@ -179,14 +185,15 @@ Abort if no DKG is in progress. ### Function `finish` -
public(friend) fun finish(account: &signer)
+
public(friend) fun finish(framework: &signer)
 
-
pragma verify = false;
+
pragma verify_duration_estimate = 1500;
 include FinishRequirement;
+aborts_if false;
 
@@ -196,8 +203,8 @@ Abort if no DKG is in progress.
schema FinishRequirement {
-    account: signer;
-    requires signer::address_of(account) == @aptos_framework;
+    framework: signer;
+    requires signer::address_of(framework) == @aptos_framework;
     requires chain_status::is_operating();
     requires exists<CoinInfo<AptosCoin>>(@aptos_framework);
     include staking_config::StakingRewardsConfigRequirement;
@@ -210,8 +217,11 @@ Abort if no DKG is in progress.
     include config_buffer::OnNewEpochRequirement<consensus_config::ConsensusConfig>;
     include config_buffer::OnNewEpochRequirement<jwks::SupportedOIDCProviders>;
     include config_buffer::OnNewEpochRequirement<randomness_config::RandomnessConfig>;
+    include config_buffer::OnNewEpochRequirement<randomness_config_seqnum::RandomnessConfigSeqNum>;
+    include config_buffer::OnNewEpochRequirement<randomness_api_v0_config::RequiredGasDeposit>;
     include config_buffer::OnNewEpochRequirement<jwk_consensus_config::JWKConsensusConfig>;
-    aborts_if false;
+    include config_buffer::OnNewEpochRequirement<keyless_account::Configuration>;
+    include config_buffer::OnNewEpochRequirement<keyless_account::Groth16VerificationKey>;
 }
 
@@ -228,8 +238,10 @@ Abort if no DKG is in progress. -
pragma verify = false;
-include FinishRequirement;
+
pragma verify_duration_estimate = 1500;
+include FinishRequirement {
+    framework: account
+};
 requires dkg::has_incomplete_session();
 aborts_if false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/resource_account.md b/aptos-move/framework/aptos-framework/doc/resource_account.md index beee8959b49cb..fa171c0b03cdc 100644 --- a/aptos-move/framework/aptos-framework/doc/resource_account.md +++ b/aptos-move/framework/aptos-framework/doc/resource_account.md @@ -354,7 +354,10 @@ the SignerCapability. let resource_addr = signer::address_of(resource); let (resource_signer_cap, empty_container) = { let container = borrow_global_mut<Container>(source_addr); - assert!(simple_map::contains_key(&container.store, &resource_addr), error::invalid_argument(EUNAUTHORIZED_NOT_OWNER)); + assert!( + simple_map::contains_key(&container.store, &resource_addr), + error::invalid_argument(EUNAUTHORIZED_NOT_OWNER) + ); let (_resource_addr, signer_cap) = simple_map::remove(&mut container.store, &resource_addr); (signer_cap, simple_map::length(&container.store) == 0) }; @@ -499,13 +502,14 @@ the SignerCapability. -
let source_addr = signer::address_of(origin);
+
pragma verify = false;
+let source_addr = signer::address_of(origin);
 let resource_addr = account::spec_create_resource_address(source_addr, seed);
 let coin_store_resource = global<coin::CoinStore<AptosCoin>>(resource_addr);
 include aptos_account::WithdrawAbortsIf<AptosCoin>{from: origin, amount: fund_amount};
 include aptos_account::GuidAbortsIf<AptosCoin>{to: resource_addr};
 include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIfWithoutAccountLimit;
-aborts_if coin::is_account_registered<AptosCoin>(resource_addr) && coin_store_resource.frozen;
+aborts_if coin::spec_is_account_registered<AptosCoin>(resource_addr) && coin_store_resource.frozen;
 // This enforces high-level requirement 3:
 ensures exists<aptos_framework::coin::CoinStore<AptosCoin>>(resource_addr);
 
diff --git a/aptos-move/framework/aptos-framework/doc/stake.md b/aptos-move/framework/aptos-framework/doc/stake.md index f672a43521229..27b9ef365c3dc 100644 --- a/aptos-move/framework/aptos-framework/doc/stake.md +++ b/aptos-move/framework/aptos-framework/doc/stake.md @@ -1624,32 +1624,32 @@ security of the testnet. This will NOT be enabled in Mainnet. - + -Limit the maximum value of rewards_rate in order to avoid any arithmetic overflow. +Account is already registered as a validator candidate. -
const MAX_REWARDS_RATE: u64 = 1000000;
+
const EALREADY_REGISTERED: u64 = 8;
 
- + -Account is already a validator or pending validator. +Limit the maximum value of rewards_rate in order to avoid any arithmetic overflow. -
const EALREADY_ACTIVE_VALIDATOR: u64 = 4;
+
const MAX_REWARDS_RATE: u64 = 1000000;
 
- + -Account is already registered as a validator candidate. +Account is already a validator or pending validator. -
const EALREADY_REGISTERED: u64 = 8;
+
const EALREADY_ACTIVE_VALIDATOR: u64 = 4;
 
@@ -5059,7 +5059,9 @@ Returns validator's next epoch voting power, including pending_active, active, a -
aborts_if reconfiguration_state::spec_is_in_progress();
+
pragma verify_duration_estimate = 120;
+pragma aborts_if_is_partial;
+aborts_if reconfiguration_state::spec_is_in_progress();
 include ResourceRequirement;
 include AddStakeAbortsIfAndEnsures;
 
@@ -5283,7 +5285,8 @@ Returns validator's next epoch voting power, including pending_active, active, a -
aborts_if reconfiguration_state::spec_is_in_progress();
+
pragma verify = false;
+aborts_if reconfiguration_state::spec_is_in_progress();
 let addr = signer::address_of(owner);
 let ownership_cap = global<OwnerCapability>(addr);
 let pool_address = ownership_cap.pool_address;
@@ -5512,11 +5515,6 @@ Returns validator's next epoch voting power, including pending_active, active, a
     amount: u64;
     let owner_address = signer::address_of(owner);
     aborts_if !exists<OwnerCapability>(owner_address);
-    include coin::WithdrawAbortsIf<AptosCoin>{ account: owner };
-    let coin_store = global<coin::CoinStore<AptosCoin>>(owner_address);
-    let balance = coin_store.coin.value;
-    let post coin_post = global<coin::CoinStore<AptosCoin>>(owner_address).coin.value;
-    ensures coin_post == balance - amount;
     let owner_cap = global<OwnerCapability>(owner_address);
     include AddStakeWithCapAbortsIfAndEnsures { owner_cap };
 }
diff --git a/aptos-move/framework/aptos-framework/doc/staking_contract.md b/aptos-move/framework/aptos-framework/doc/staking_contract.md
index 9e979016b5071..0a97d91ee44e5 100644
--- a/aptos-move/framework/aptos-framework/doc/staking_contract.md
+++ b/aptos-move/framework/aptos-framework/doc/staking_contract.md
@@ -3159,7 +3159,8 @@ Staking_contract exists the stacker/operator pair.
 Staking_contract exists the stacker/operator pair.
 
 
-
pragma aborts_if_is_partial;
+
pragma verify_duration_estimate = 120;
+pragma aborts_if_is_partial;
 let staker_address = signer::address_of(staker);
 include ContractExistsAbortsIf { staker: staker_address, operator: old_operator };
 
@@ -3216,7 +3217,8 @@ Staking_contract exists the stacker/operator pair. Staking_contract exists the stacker/operator pair. -
pragma aborts_if_is_partial;
+
pragma verify_duration_estimate = 120;
+pragma aborts_if_is_partial;
 include ContractExistsAbortsIf;
 
@@ -3235,7 +3237,8 @@ The StakePool exists under the pool_address of StakingContract. The value of inactive and pending_inactive in the stake_pool is up to MAX_U64. -
pragma aborts_if_is_partial;
+
pragma verify_duration_estimate = 120;
+pragma aborts_if_is_partial;
 let pool_address = staking_contract.pool_address;
 let stake_pool = borrow_global<stake::StakePool>(pool_address);
 aborts_if !exists<stake::StakePool>(pool_address);
diff --git a/aptos-move/framework/aptos-framework/doc/transaction_context.md b/aptos-move/framework/aptos-framework/doc/transaction_context.md
index 6c7b65cb802c9..cc7d9010ffc74 100644
--- a/aptos-move/framework/aptos-framework/doc/transaction_context.md
+++ b/aptos-move/framework/aptos-framework/doc/transaction_context.md
@@ -6,6 +6,9 @@
 
 
 -  [Struct `AUID`](#0x1_transaction_context_AUID)
+-  [Struct `EntryFunctionPayload`](#0x1_transaction_context_EntryFunctionPayload)
+-  [Struct `MultisigPayload`](#0x1_transaction_context_MultisigPayload)
+-  [Constants](#@Constants_0)
 -  [Function `get_txn_hash`](#0x1_transaction_context_get_txn_hash)
 -  [Function `get_transaction_hash`](#0x1_transaction_context_get_transaction_hash)
 -  [Function `generate_unique_address`](#0x1_transaction_context_generate_unique_address)
@@ -13,58 +16,684 @@
 -  [Function `get_script_hash`](#0x1_transaction_context_get_script_hash)
 -  [Function `generate_auid`](#0x1_transaction_context_generate_auid)
 -  [Function `auid_address`](#0x1_transaction_context_auid_address)
--  [Specification](#@Specification_0)
-    -  [Function `get_txn_hash`](#@Specification_0_get_txn_hash)
-    -  [Function `get_transaction_hash`](#@Specification_0_get_transaction_hash)
-    -  [Function `generate_unique_address`](#@Specification_0_generate_unique_address)
-    -  [Function `generate_auid_address`](#@Specification_0_generate_auid_address)
-    -  [Function `get_script_hash`](#@Specification_0_get_script_hash)
+-  [Function `sender`](#0x1_transaction_context_sender)
+-  [Function `sender_internal`](#0x1_transaction_context_sender_internal)
+-  [Function `secondary_signers`](#0x1_transaction_context_secondary_signers)
+-  [Function `secondary_signers_internal`](#0x1_transaction_context_secondary_signers_internal)
+-  [Function `gas_payer`](#0x1_transaction_context_gas_payer)
+-  [Function `gas_payer_internal`](#0x1_transaction_context_gas_payer_internal)
+-  [Function `max_gas_amount`](#0x1_transaction_context_max_gas_amount)
+-  [Function `max_gas_amount_internal`](#0x1_transaction_context_max_gas_amount_internal)
+-  [Function `gas_unit_price`](#0x1_transaction_context_gas_unit_price)
+-  [Function `gas_unit_price_internal`](#0x1_transaction_context_gas_unit_price_internal)
+-  [Function `chain_id`](#0x1_transaction_context_chain_id)
+-  [Function `chain_id_internal`](#0x1_transaction_context_chain_id_internal)
+-  [Function `entry_function_payload`](#0x1_transaction_context_entry_function_payload)
+-  [Function `entry_function_payload_internal`](#0x1_transaction_context_entry_function_payload_internal)
+-  [Function `account_address`](#0x1_transaction_context_account_address)
+-  [Function `module_name`](#0x1_transaction_context_module_name)
+-  [Function `function_name`](#0x1_transaction_context_function_name)
+-  [Function `type_arg_names`](#0x1_transaction_context_type_arg_names)
+-  [Function `args`](#0x1_transaction_context_args)
+-  [Function `multisig_payload`](#0x1_transaction_context_multisig_payload)
+-  [Function `multisig_payload_internal`](#0x1_transaction_context_multisig_payload_internal)
+-  [Function `multisig_address`](#0x1_transaction_context_multisig_address)
+-  [Function `inner_entry_function_payload`](#0x1_transaction_context_inner_entry_function_payload)
+-  [Specification](#@Specification_1)
+    -  [Function `get_txn_hash`](#@Specification_1_get_txn_hash)
+    -  [Function `get_transaction_hash`](#@Specification_1_get_transaction_hash)
+    -  [Function `generate_unique_address`](#@Specification_1_generate_unique_address)
+    -  [Function `generate_auid_address`](#@Specification_1_generate_auid_address)
+    -  [Function `get_script_hash`](#@Specification_1_get_script_hash)
     -  [High-level Requirements](#high-level-req)
     -  [Module-level Specification](#module-level-spec)
-    -  [Function `auid_address`](#@Specification_0_auid_address)
+    -  [Function `auid_address`](#@Specification_1_auid_address)
+    -  [Function `sender_internal`](#@Specification_1_sender_internal)
+    -  [Function `secondary_signers_internal`](#@Specification_1_secondary_signers_internal)
+    -  [Function `gas_payer_internal`](#@Specification_1_gas_payer_internal)
+    -  [Function `max_gas_amount_internal`](#@Specification_1_max_gas_amount_internal)
+    -  [Function `gas_unit_price_internal`](#@Specification_1_gas_unit_price_internal)
+    -  [Function `chain_id_internal`](#@Specification_1_chain_id_internal)
+    -  [Function `entry_function_payload_internal`](#@Specification_1_entry_function_payload_internal)
+    -  [Function `multisig_payload_internal`](#@Specification_1_multisig_payload_internal)
+
+
+
use 0x1::error;
+use 0x1::features;
+use 0x1::option;
+use 0x1::string;
+
+ + + + + +## Struct `AUID` + +A wrapper denoting aptos unique identifer (AUID) +for storing an address + + +
struct AUID has drop, store
+
+ + + +
+Fields + + +
+
+unique_address: address +
+
+ +
+
+ + +
+ + + +## Struct `EntryFunctionPayload` + +Represents the entry function payload. + + +
struct EntryFunctionPayload has copy, drop
+
+ + + +
+Fields + + +
+
+account_address: address +
+
+ +
+
+module_name: string::String +
+
+ +
+
+function_name: string::String +
+
+ +
+
+ty_args_names: vector<string::String> +
+
+ +
+
+args: vector<vector<u8>> +
+
+ +
+
+ + +
+ + + +## Struct `MultisigPayload` + +Represents the multisig payload. + + +
struct MultisigPayload has copy, drop
+
+ + + +
+Fields + + +
+
+multisig_address: address +
+
+ +
+
+entry_function_payload: option::Option<transaction_context::EntryFunctionPayload> +
+
+ +
+
+ + +
+ + + +## Constants + + + + +The transaction context extension feature is not enabled. + + +
const ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED: u64 = 2;
+
+ + + + + +Transaction context is only available in the user transaction prologue, execution, or epilogue phases. + + +
const ETRANSACTION_CONTEXT_NOT_AVAILABLE: u64 = 1;
+
+ + + + + +## Function `get_txn_hash` + +Returns the transaction hash of the current transaction. + + +
fun get_txn_hash(): vector<u8>
+
+ + + +
+Implementation + + +
native fun get_txn_hash(): vector<u8>;
+
+ + + +
+ + + +## Function `get_transaction_hash` + +Returns the transaction hash of the current transaction. +Internally calls the private function get_txn_hash. +This function is created for to feature gate the get_txn_hash function. + + +
public fun get_transaction_hash(): vector<u8>
+
+ + + +
+Implementation + + +
public fun get_transaction_hash(): vector<u8> {
+    get_txn_hash()
+}
+
+ + + +
+ + + +## Function `generate_unique_address` + +Returns a universally unique identifier (of type address) generated +by hashing the transaction hash of this transaction and a sequence number +specific to this transaction. This function can be called any +number of times inside a single transaction. Each such call increments +the sequence number and generates a new unique address. +Uses Scheme in types/src/transaction/authenticator.rs for domain separation +from other ways of generating unique addresses. + + +
fun generate_unique_address(): address
+
+ + + +
+Implementation + + +
native fun generate_unique_address(): address;
+
+ + + +
+ + + +## Function `generate_auid_address` + +Returns a aptos unique identifier. Internally calls +the private function generate_unique_address. This function is +created for to feature gate the generate_unique_address function. + + +
public fun generate_auid_address(): address
+
+ + + +
+Implementation + + +
public fun generate_auid_address(): address {
+    generate_unique_address()
+}
+
+ + + +
+ + + +## Function `get_script_hash` + +Returns the script hash of the current entry function. + + +
public fun get_script_hash(): vector<u8>
+
+ + + +
+Implementation + + +
public native fun get_script_hash(): vector<u8>;
+
+ + + +
+ + + +## Function `generate_auid` + +This method runs generate_unique_address native function and returns +the generated unique address wrapped in the AUID class. + + +
public fun generate_auid(): transaction_context::AUID
+
+ + + +
+Implementation + + +
public fun generate_auid(): AUID {
+    return AUID {
+        unique_address: generate_unique_address()
+    }
+}
+
+ + + +
+ + + +## Function `auid_address` + +Returns the unique address wrapped in the given AUID struct. + + +
public fun auid_address(auid: &transaction_context::AUID): address
+
+ + + +
+Implementation + + +
public fun auid_address(auid: &AUID): address {
+    auid.unique_address
+}
+
+ + + +
+ + + +## Function `sender` + +Returns the sender's address for the current transaction. +This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + + +
public fun sender(): address
+
+ + + +
+Implementation + + +
public fun sender(): address {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    sender_internal()
+}
+
+ + + +
+ + + +## Function `sender_internal` + + + +
fun sender_internal(): address
+
+ + + +
+Implementation + + +
native fun sender_internal(): address;
+
+ + + +
+ + + +## Function `secondary_signers` + +Returns the list of the secondary signers for the current transaction. +If the current transaction has no secondary signers, this function returns an empty vector. +This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + + +
public fun secondary_signers(): vector<address>
+
+ + + +
+Implementation + + +
public fun secondary_signers(): vector<address> {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    secondary_signers_internal()
+}
+
+ + + +
+ + + +## Function `secondary_signers_internal` + + + +
fun secondary_signers_internal(): vector<address>
+
+ + + +
+Implementation + + +
native fun secondary_signers_internal(): vector<address>;
+
+ + + +
+ + + +## Function `gas_payer` + +Returns the gas payer address for the current transaction. +It is either the sender's address if no separate gas fee payer is specified for the current transaction, +or the address of the separate gas fee payer if one is specified. +This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + + +
public fun gas_payer(): address
+
+ + + +
+Implementation + + +
public fun gas_payer(): address {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    gas_payer_internal()
+}
+
+ + + +
+ + + +## Function `gas_payer_internal` + + + +
fun gas_payer_internal(): address
+
+ + + +
+Implementation + + +
native fun gas_payer_internal(): address;
+
+ + + +
+ + + +## Function `max_gas_amount` + +Returns the max gas amount in units which is specified for the current transaction. +This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + + +
public fun max_gas_amount(): u64
+
+ + + +
+Implementation + + +
public fun max_gas_amount(): u64 {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    max_gas_amount_internal()
+}
+
+ + + +
+ + + +## Function `max_gas_amount_internal` + + + +
fun max_gas_amount_internal(): u64
+
+ + + +
+Implementation + + +
native fun max_gas_amount_internal(): u64;
+
+ + + +
+ + + +## Function `gas_unit_price` + +Returns the gas unit price in Octas which is specified for the current transaction. +This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + + +
public fun gas_unit_price(): u64
+
+ + + +
+Implementation + + +
public fun gas_unit_price(): u64 {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    gas_unit_price_internal()
+}
+
+ + + +
+ + + +## Function `gas_unit_price_internal` + + + +
fun gas_unit_price_internal(): u64
+
+ + + +
+Implementation + + +
native fun gas_unit_price_internal(): u64;
+
+ + + +
+ + +## Function `chain_id` -
+Returns the chain ID specified for the current transaction. +This function aborts if called outside of the transaction prologue, execution, or epilogue phases. +
public fun chain_id(): u8
+
- -## Struct `AUID` -A wrapper denoting aptos unique identifer (AUID) -for storing an address +
+Implementation -
struct AUID has drop, store
+
public fun chain_id(): u8 {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    chain_id_internal()
+}
+
+ + + +
+ + + +## Function `chain_id_internal` + + + +
fun chain_id_internal(): u8
 
-Fields +Implementation -
-
-unique_address: address -
-
+
native fun chain_id_internal(): u8;
+
-
-
- + -## Function `get_txn_hash` +## Function `entry_function_payload` -Return the transaction hash of the current transaction. +Returns the entry function payload if the current transaction has such a payload. Otherwise, return None. +This function aborts if called outside of the transaction prologue, execution, or epilogue phases. -
fun get_txn_hash(): vector<u8>
+
public fun entry_function_payload(): option::Option<transaction_context::EntryFunctionPayload>
 
@@ -73,23 +702,23 @@ Return the transaction hash of the current transaction. Implementation -
native fun get_txn_hash(): vector<u8>;
+
public fun entry_function_payload(): Option<EntryFunctionPayload> {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    entry_function_payload_internal()
+}
 
- + -## Function `get_transaction_hash` +## Function `entry_function_payload_internal` -Return the transaction hash of the current transaction. -Internally calls the private function get_txn_hash. -This function is created for to feature gate the get_txn_hash function. -
public fun get_transaction_hash(): vector<u8>
+
fun entry_function_payload_internal(): option::Option<transaction_context::EntryFunctionPayload>
 
@@ -98,8 +727,32 @@ This function is created for to feature gate the get_txn_hash funct Implementation -
public fun get_transaction_hash(): vector<u8> {
-    get_txn_hash()
+
native fun entry_function_payload_internal(): Option<EntryFunctionPayload>;
+
+ + + + + + + +## Function `account_address` + +Returns the account address of the entry function payload. + + +
public fun account_address(payload: &transaction_context::EntryFunctionPayload): address
+
+ + + +
+Implementation + + +
public fun account_address(payload: &EntryFunctionPayload): address {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    payload.account_address
 }
 
@@ -107,20 +760,14 @@ This function is created for to feature gate the get_txn_hash funct
- + -## Function `generate_unique_address` +## Function `module_name` -Return a universally unique identifier (of type address) generated -by hashing the transaction hash of this transaction and a sequence number -specific to this transaction. This function can be called any -number of times inside a single transaction. Each such call increments -the sequence number and generates a new unique address. -Uses Scheme in types/src/transaction/authenticator.rs for domain separation -from other ways of generating unique addresses. +Returns the module name of the entry function payload. -
fun generate_unique_address(): address
+
public fun module_name(payload: &transaction_context::EntryFunctionPayload): string::String
 
@@ -129,23 +776,24 @@ from other ways of generating unique addresses. Implementation -
native fun generate_unique_address(): address;
+
public fun module_name(payload: &EntryFunctionPayload): String {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    payload.module_name
+}
 
- + -## Function `generate_auid_address` +## Function `function_name` -Return a aptos unique identifier. Internally calls -the private function generate_unique_address. This function is -created for to feature gate the generate_unique_address function. +Returns the function name of the entry function payload. -
public fun generate_auid_address(): address
+
public fun function_name(payload: &transaction_context::EntryFunctionPayload): string::String
 
@@ -154,8 +802,9 @@ created for to feature gate the generate_unique_address function. Implementation -
public fun generate_auid_address(): address {
-    generate_unique_address()
+
public fun function_name(payload: &EntryFunctionPayload): String {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    payload.function_name
 }
 
@@ -163,14 +812,14 @@ created for to feature gate the generate_unique_address function. - + -## Function `get_script_hash` +## Function `type_arg_names` -Return the script hash of the current entry function. +Returns the type arguments names of the entry function payload. -
public fun get_script_hash(): vector<u8>
+
public fun type_arg_names(payload: &transaction_context::EntryFunctionPayload): vector<string::String>
 
@@ -179,22 +828,24 @@ Return the script hash of the current entry function. Implementation -
public native fun get_script_hash(): vector<u8>;
+
public fun type_arg_names(payload: &EntryFunctionPayload): vector<String> {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    payload.ty_args_names
+}
 
- + -## Function `generate_auid` +## Function `args` -This method runs generate_unique_address native function and returns -the generated unique address wrapped in the AUID class. +Returns the arguments of the entry function payload. -
public fun generate_auid(): transaction_context::AUID
+
public fun args(payload: &transaction_context::EntryFunctionPayload): vector<vector<u8>>
 
@@ -203,10 +854,9 @@ the generated unique address wrapped in the AUID class. Implementation -
public fun generate_auid(): AUID {
-    return AUID {
-        unique_address: generate_unique_address()
-    }
+
public fun args(payload: &EntryFunctionPayload): vector<vector<u8>> {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    payload.args
 }
 
@@ -214,13 +864,15 @@ the generated unique address wrapped in the AUID class. - + -## Function `auid_address` +## Function `multisig_payload` +Returns the multisig payload if the current transaction has such a payload. Otherwise, return None. +This function aborts if called outside of the transaction prologue, execution, or epilogue phases. -
public fun auid_address(auid: &transaction_context::AUID): address
+
public fun multisig_payload(): option::Option<transaction_context::MultisigPayload>
 
@@ -229,8 +881,83 @@ the generated unique address wrapped in the AUID class. Implementation -
public fun auid_address(auid: &AUID): address {
-    auid.unique_address
+
public fun multisig_payload(): Option<MultisigPayload> {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    multisig_payload_internal()
+}
+
+ + + + + + + +## Function `multisig_payload_internal` + + + +
fun multisig_payload_internal(): option::Option<transaction_context::MultisigPayload>
+
+ + + +
+Implementation + + +
native fun multisig_payload_internal(): Option<MultisigPayload>;
+
+ + + +
+ + + +## Function `multisig_address` + +Returns the multisig account address of the multisig payload. + + +
public fun multisig_address(payload: &transaction_context::MultisigPayload): address
+
+ + + +
+Implementation + + +
public fun multisig_address(payload: &MultisigPayload): address {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    payload.multisig_address
+}
+
+ + + +
+ + + +## Function `inner_entry_function_payload` + +Returns the inner entry function payload of the multisig payload. + + +
public fun inner_entry_function_payload(payload: &transaction_context::MultisigPayload): option::Option<transaction_context::EntryFunctionPayload>
+
+ + + +
+Implementation + + +
public fun inner_entry_function_payload(payload: &MultisigPayload): Option<EntryFunctionPayload> {
+    assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED));
+    payload.entry_function_payload
 }
 
@@ -238,12 +965,12 @@ the generated unique address wrapped in the AUID class.
- + ## Specification - + ### Function `get_txn_hash` @@ -270,7 +997,7 @@ the generated unique address wrapped in the AUID class. - + ### Function `get_transaction_hash` @@ -290,7 +1017,7 @@ the generated unique address wrapped in the AUID class. - + ### Function `generate_unique_address` @@ -316,7 +1043,7 @@ the generated unique address wrapped in the AUID class. - + ### Function `generate_auid_address` @@ -334,7 +1061,7 @@ the generated unique address wrapped in the AUID class. - + ### Function `get_script_hash` @@ -414,7 +1141,7 @@ the generated unique address wrapped in the AUID class. - + ### Function `auid_address` @@ -430,4 +1157,132 @@ the generated unique address wrapped in the AUID class.
+ + + +### Function `sender_internal` + + +
fun sender_internal(): address
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `secondary_signers_internal` + + +
fun secondary_signers_internal(): vector<address>
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `gas_payer_internal` + + +
fun gas_payer_internal(): address
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `max_gas_amount_internal` + + +
fun max_gas_amount_internal(): u64
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `gas_unit_price_internal` + + +
fun gas_unit_price_internal(): u64
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `chain_id_internal` + + +
fun chain_id_internal(): u8
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `entry_function_payload_internal` + + +
fun entry_function_payload_internal(): option::Option<transaction_context::EntryFunctionPayload>
+
+ + + + +
pragma opaque;
+
+ + + + + +### Function `multisig_payload_internal` + + +
fun multisig_payload_internal(): option::Option<transaction_context::MultisigPayload>
+
+ + + + +
pragma opaque;
+
+ + [move-book]: https://aptos.dev/move/book/SUMMARY diff --git a/aptos-move/framework/aptos-framework/doc/transaction_fee.md b/aptos-move/framework/aptos-framework/doc/transaction_fee.md index 792b22d473927..11a3e38a95c57 100644 --- a/aptos-move/framework/aptos-framework/doc/transaction_fee.md +++ b/aptos-move/framework/aptos-framework/doc/transaction_fee.md @@ -992,13 +992,13 @@ Only called during genesis. AptosCoinCapabilities should be exists. -
aborts_if !exists<AptosCoinCapabilities>(@aptos_framework);
+
pragma verify = false;
+aborts_if !exists<AptosCoinCapabilities>(@aptos_framework);
 let account_addr = account;
 let amount = fee;
 let aptos_addr = type_info::type_of<AptosCoin>().account_address;
 let coin_store = global<CoinStore<AptosCoin>>(account_addr);
 let post post_coin_store = global<CoinStore<AptosCoin>>(account_addr);
-modifies global<CoinStore<AptosCoin>>(account_addr);
 aborts_if amount != 0 && !(exists<CoinInfo<AptosCoin>>(aptos_addr)
     && exists<CoinStore<AptosCoin>>(account_addr));
 aborts_if coin_store.coin.value < amount;
@@ -1031,13 +1031,11 @@ Only called during genesis.
 
 
 
-
pragma opaque;
+
pragma verify = false;
 let aptos_addr = type_info::type_of<AptosCoin>().account_address;
-modifies global<CoinInfo<AptosCoin>>(aptos_addr);
 aborts_if (refund != 0) && !exists<CoinInfo<AptosCoin>>(aptos_addr);
 include coin::CoinAddAbortsIf<AptosCoin> { amount: refund };
 aborts_if !exists<CoinStore<AptosCoin>>(account);
-modifies global<CoinStore<AptosCoin>>(account);
 aborts_if !exists<AptosCoinMintCapability>(@aptos_framework);
 let supply = coin::supply<AptosCoin>;
 let post post_supply = coin::supply<AptosCoin>;
@@ -1058,7 +1056,8 @@ Only called during genesis.
 
 
 
-
let collected_fees = global<CollectedFeesPerBlock>(@aptos_framework).amount;
+
pragma verify = false;
+let collected_fees = global<CollectedFeesPerBlock>(@aptos_framework).amount;
 let aggr = collected_fees.value;
 let coin_store = global<coin::CoinStore<AptosCoin>>(account);
 aborts_if !exists<CollectedFeesPerBlock>(@aptos_framework);
diff --git a/aptos-move/framework/aptos-framework/doc/transaction_validation.md b/aptos-move/framework/aptos-framework/doc/transaction_validation.md
index 6ba2db0546a03..2d8db158686fc 100644
--- a/aptos-move/framework/aptos-framework/doc/transaction_validation.md
+++ b/aptos-move/framework/aptos-framework/doc/transaction_validation.md
@@ -422,8 +422,10 @@ Called in epilogue to optionally released the amount held in prologue for specia
         coin::is_account_registered<AptosCoin>(gas_payer),
         error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT),
     );
-    let balance = coin::balance<AptosCoin>(gas_payer);
-    assert!(balance >= max_transaction_fee, error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT));
+    assert!(
+        coin::is_balance_at_least<AptosCoin>(gas_payer, max_transaction_fee),
+        error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT)
+    );
 }
 
@@ -817,7 +819,7 @@ Called by the Adapter // it's important to maintain the error code consistent with vm // to do failed transaction cleanup. assert!( - coin::balance<AptosCoin>(gas_payer) >= transaction_fee_amount, + coin::is_balance_at_least<AptosCoin>(gas_payer, transaction_fee_amount), error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), ); @@ -1064,7 +1066,8 @@ Give some constraints that may abort according to the conditions. -
include PrologueCommonAbortsIf;
+
pragma verify = false;
+include PrologueCommonAbortsIf;
 
@@ -1080,7 +1083,8 @@ Give some constraints that may abort according to the conditions. -
include PrologueCommonAbortsIf {
+
pragma verify = false;
+include PrologueCommonAbortsIf {
     gas_payer: signer::address_of(sender),
     txn_authentication_key: txn_public_key
 };
@@ -1142,6 +1146,7 @@ not equal the number of singers.
 
 
pragma verify_duration_estimate = 120;
 let gas_payer = signer::address_of(sender);
+pragma verify = false;
 include PrologueCommonAbortsIf {
     gas_payer,
     txn_sequence_number,
@@ -1234,7 +1239,8 @@ Abort according to the conditions.
 Skip transaction_fee::burn_fee verification.
 
 
-
include EpilogueGasPayerAbortsIf { gas_payer: signer::address_of(account) };
+
pragma verify = false;
+include EpilogueGasPayerAbortsIf { gas_payer: signer::address_of(account) };
 
@@ -1269,7 +1275,8 @@ Abort according to the conditions. Skip transaction_fee::burn_fee verification. -
include EpilogueGasPayerAbortsIf;
+
pragma verify = false;
+include EpilogueGasPayerAbortsIf;
 
@@ -1290,15 +1297,11 @@ Skip transaction_fee::burn_fee verification. aborts_if !(txn_gas_price * gas_used <= MAX_U64); let transaction_fee_amount = txn_gas_price * gas_used; let addr = signer::address_of(account); - let pre_balance = global<coin::CoinStore<AptosCoin>>(gas_payer).coin.value; - let post balance = global<coin::CoinStore<AptosCoin>>(gas_payer).coin.value; let pre_account = global<account::Account>(addr); let post account = global<account::Account>(addr); aborts_if !exists<CoinStore<AptosCoin>>(gas_payer); aborts_if !exists<Account>(addr); aborts_if !(global<Account>(addr).sequence_number < MAX_U64); - aborts_if pre_balance < transaction_fee_amount; - ensures balance == pre_balance - transaction_fee_amount + storage_fee_refunded; ensures account.sequence_number == pre_account.sequence_number + 1; let collect_fee_enabled = features::spec_is_enabled(features::COLLECT_AND_DISTRIBUTE_GAS_FEES); let collected_fees = global<CollectedFeesPerBlock>(@aptos_framework).amount; diff --git a/aptos-move/framework/aptos-framework/doc/version.md b/aptos-move/framework/aptos-framework/doc/version.md index 5a9ba0515b795..c201f455c86f1 100644 --- a/aptos-move/framework/aptos-framework/doc/version.md +++ b/aptos-move/framework/aptos-framework/doc/version.md @@ -221,7 +221,7 @@ Example usage: Only used in reconfigurations to apply the pending Version, if there is any. -
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
@@ -230,9 +230,15 @@ Only used in reconfigurations to apply the pending on_new_epoch() acquires Version { +
public(friend) fun on_new_epoch(framework: &signer) acquires Version {
+    system_addresses::assert_aptos_framework(framework);
     if (config_buffer::does_exist<Version>()) {
-        *borrow_global_mut<Version>(@aptos_framework) = config_buffer::extract<Version>();
+        let new_value = config_buffer::extract<Version>();
+        if (exists<Version>(@aptos_framework)) {
+            *borrow_global_mut<Version>(@aptos_framework) = new_value;
+        } else {
+            move_to(framework, new_value);
+        }
     }
 }
 
@@ -392,13 +398,15 @@ Abort if resource already exists in @aptos_framwork when initializi ### Function `on_new_epoch` -
public(friend) fun on_new_epoch()
+
public(friend) fun on_new_epoch(framework: &signer)
 
-
include config_buffer::OnNewEpochAbortsIf<Version>;
+
requires @aptos_framework == std::signer::address_of(framework);
+include config_buffer::OnNewEpochRequirement<Version>;
+aborts_if false;
 
diff --git a/aptos-move/framework/aptos-framework/doc/vesting.md b/aptos-move/framework/aptos-framework/doc/vesting.md index bc635e55b585c..39cae9501e774 100644 --- a/aptos-move/framework/aptos-framework/doc/vesting.md +++ b/aptos-move/framework/aptos-framework/doc/vesting.md @@ -4076,7 +4076,8 @@ This address should be deterministic for the same admin and vesting contract cre -
include VerifyAdminAbortsIf;
+
pragma verify_duration_estimate = 300;
+include VerifyAdminAbortsIf;
 let vesting_contract = global<VestingContract>(contract_address);
 let operator = vesting_contract.staking.operator;
 let staker = vesting_contract.signer_cap.account;
@@ -4123,8 +4124,9 @@ This address should be deterministic for the same admin and vesting contract cre
 
 
 
-
aborts_if !account::exists_at(new_beneficiary);
-aborts_if !coin::is_account_registered<AptosCoin>(new_beneficiary);
+
pragma aborts_if_is_partial;
+aborts_if !account::exists_at(new_beneficiary);
+aborts_if !coin::spec_is_account_registered<AptosCoin>(new_beneficiary);
 include VerifyAdminAbortsIf;
 let post vesting_contract = global<VestingContract>(contract_address);
 ensures simple_map::spec_contains_key(vesting_contract.beneficiaries,shareholder);
diff --git a/aptos-move/framework/aptos-framework/sources/aggregator/aggregator_factory.move b/aptos-move/framework/aptos-framework/sources/aggregator/aggregator_factory.move
index f13ceddaaff8a..7ec4dad805e2a 100644
--- a/aptos-move/framework/aptos-framework/sources/aggregator/aggregator_factory.move
+++ b/aptos-move/framework/aptos-framework/sources/aggregator/aggregator_factory.move
@@ -58,4 +58,9 @@ module aptos_framework::aggregator_factory {
     public fun initialize_aggregator_factory_for_test(aptos_framework: &signer) {
         initialize_aggregator_factory(aptos_framework);
     }
+
+    #[test_only]
+    public fun aggregator_factory_exists_for_testing(): bool {
+        exists(@aptos_framework)
+    }
 }
diff --git a/aptos-move/framework/aptos-framework/sources/aptos_account.move b/aptos-move/framework/aptos-framework/sources/aptos_account.move
index 1d5c1fda7f6ec..2ca24b901dec3 100644
--- a/aptos-move/framework/aptos-framework/sources/aptos_account.move
+++ b/aptos-move/framework/aptos-framework/sources/aptos_account.move
@@ -105,9 +105,9 @@ module aptos_framework::aptos_account {
         if (!account::exists_at(to)) {
             create_account(to);
             spec {
-                assert coin::is_account_registered(to);
+                assert coin::spec_is_account_registered(to);
                 assume aptos_std::type_info::type_of() == aptos_std::type_info::type_of() ==>
-                    coin::is_account_registered(to);
+                    coin::spec_is_account_registered(to);
             };
         };
         if (!coin::is_account_registered(to)) {
diff --git a/aptos-move/framework/aptos-framework/sources/aptos_account.spec.move b/aptos-move/framework/aptos-framework/sources/aptos_account.spec.move
index 702a51b75488d..acc8bf6f0a6d1 100644
--- a/aptos-move/framework/aptos-framework/sources/aptos_account.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/aptos_account.spec.move
@@ -67,10 +67,9 @@ spec aptos_framework::aptos_account {
     /// Limit the address of auth_key is not @vm_reserved / @aptos_framework / @aptos_toke.
     spec create_account(auth_key: address) {
         /// [high-level-req-1]
+        pragma aborts_if_is_partial;
         include CreateAccountAbortsIf;
         ensures exists(auth_key);
-        /// [high-level-req-2]
-        ensures exists>(auth_key);
     }
     spec schema CreateAccountAbortsIf {
         auth_key: address;
@@ -87,6 +86,8 @@ spec aptos_framework::aptos_account {
     }
 
     spec transfer(source: &signer, to: address, amount: u64) {
+        // TODO(fa_migration)
+        pragma verify = false;
         let account_addr_source = signer::address_of(source);
 
         // The 'from' addr is implictly not equal to 'to' addr
@@ -110,15 +111,17 @@ spec aptos_framework::aptos_account {
     /// Check if the address existed.
     /// Check if the AptosCoin under the address existed.
     spec assert_account_is_registered_for_apt(addr: address) {
+        pragma aborts_if_is_partial;
         aborts_if !account::exists_at(addr);
-        aborts_if !coin::is_account_registered(addr);
+        aborts_if !coin::spec_is_account_registered(addr);
     }
 
     spec set_allow_direct_coin_transfers(account: &signer, allow: bool) {
-        let addr = signer::address_of(account);
-        include !exists(addr) ==> account::NewEventHandleAbortsIf;
-        /// [high-level-req-4]
-        ensures global(addr).allow_arbitrary_coin_transfers == allow;
+        // TODO(fa_migration)
+        pragma verify = false;
+        // let addr = signer::address_of(account);
+        // include !exists(addr) ==> account::NewEventHandleAbortsIf;
+        // ensures global(addr).allow_arbitrary_coin_transfers == allow;
     }
 
     spec batch_transfer(source: &signer, recipients: vector
, amounts: vector) { @@ -217,13 +220,12 @@ spec aptos_framework::aptos_account { // register_coin properties aborts_if exists i in 0..len(recipients): - !coin::is_account_registered(recipients[i]) && !type_info::spec_is_struct(); - aborts_if exists i in 0..len(recipients): - !coin::is_account_registered(recipients[i]) && !can_receive_direct_coin_transfers(recipients[i]); - + !coin::spec_is_account_registered(recipients[i]) && !type_info::spec_is_struct(); } spec deposit_coins(to: address, coins: Coin) { + // TODO(fa_migration) + pragma verify = false; include CreateAccountTransferAbortsIf; include GuidAbortsIf; include RegistCoinAbortsIf; @@ -240,6 +242,8 @@ spec aptos_framework::aptos_account { } spec transfer_coins(from: &signer, to: address, amount: u64) { + // TODO(fa_migration) + pragma verify = false; let account_addr_source = signer::address_of(from); //The 'from' addr is implictly not equal to 'to' addr @@ -283,11 +287,9 @@ spec aptos_framework::aptos_account { spec schema RegistCoinAbortsIf { use aptos_std::type_info; to: address; - aborts_if !coin::is_account_registered(to) && !type_info::spec_is_struct(); - aborts_if exists(to) - && !coin::is_account_registered(to) && !can_receive_direct_coin_transfers(to); - aborts_if type_info::type_of() != type_info::type_of() - && !coin::is_account_registered(to) && !can_receive_direct_coin_transfers(to); + aborts_if !coin::spec_is_account_registered(to) && !type_info::spec_is_struct(); + aborts_if exists(to); + aborts_if type_info::type_of() != type_info::type_of(); } spec schema TransferEnsures { diff --git a/aptos-move/framework/aptos-framework/sources/aptos_coin.move b/aptos-move/framework/aptos-framework/sources/aptos_coin.move index c3e656e9c8ca4..18efcb49382e9 100644 --- a/aptos-move/framework/aptos-framework/sources/aptos_coin.move +++ b/aptos-move/framework/aptos-framework/sources/aptos_coin.move @@ -149,18 +149,56 @@ module aptos_framework::aptos_coin { index } + #[test_only] + use aptos_framework::account; #[test_only] use aptos_framework::aggregator_factory; + #[test_only] + use aptos_framework::fungible_asset::FungibleAsset; + + #[test_only] + public fun mint_apt_fa_for_test(amount: u64): FungibleAsset acquires MintCapStore { + ensure_initialized_with_apt_fa_metadata_for_test(); + coin::coin_to_fungible_asset( + coin::mint( + amount, + &borrow_global(@aptos_framework).mint_cap + ) + ) + } + + #[test_only] + public fun ensure_initialized_with_apt_fa_metadata_for_test() { + let aptos_framework = account::create_signer_for_test(@aptos_framework); + if (!exists(@aptos_framework)) { + if (!aggregator_factory::aggregator_factory_exists_for_testing()) { + aggregator_factory::initialize_aggregator_factory_for_test(&aptos_framework); + }; + let (burn_cap, mint_cap) = initialize(&aptos_framework); + coin::destroy_burn_cap(burn_cap); + coin::destroy_mint_cap(mint_cap); + }; + coin::create_coin_conversion_map(&aptos_framework); + coin::create_pairing(&aptos_framework); + } #[test_only] public fun initialize_for_test(aptos_framework: &signer): (BurnCapability, MintCapability) { aggregator_factory::initialize_aggregator_factory_for_test(aptos_framework); - initialize(aptos_framework) + let (burn_cap, mint_cap) = initialize(aptos_framework); + coin::create_coin_conversion_map(aptos_framework); + coin::create_pairing(aptos_framework); + (burn_cap, mint_cap) } // This is particularly useful if the aggregator_factory is already initialized via another call path. #[test_only] - public fun initialize_for_test_without_aggregator_factory(aptos_framework: &signer): (BurnCapability, MintCapability) { - initialize(aptos_framework) + public fun initialize_for_test_without_aggregator_factory( + aptos_framework: &signer + ): (BurnCapability, MintCapability) { + let (burn_cap, mint_cap) = initialize(aptos_framework); + coin::create_coin_conversion_map(aptos_framework); + coin::create_pairing(aptos_framework); + (burn_cap, mint_cap) } } diff --git a/aptos-move/framework/aptos-framework/sources/aptos_governance.spec.move b/aptos-move/framework/aptos-framework/sources/aptos_governance.spec.move index a4a8847e09a77..e7f493cee7bb4 100644 --- a/aptos-move/framework/aptos-framework/sources/aptos_governance.spec.move +++ b/aptos-move/framework/aptos-framework/sources/aptos_governance.spec.move @@ -143,7 +143,7 @@ spec aptos_framework::aptos_governance { let addr = signer::address_of(aptos_framework); aborts_if addr != @aptos_framework; include reconfiguration_with_dkg::FinishRequirement { - account: aptos_framework + framework: aptos_framework }; include stake::GetReconfigStartTimeRequirement; include transaction_fee::RequiresCollectedFeesPerValueLeqBlockAptosSupply; @@ -582,7 +582,7 @@ spec aptos_framework::aptos_governance { pragma verify = false; // TODO: set because of timeout (property proved). aborts_if !system_addresses::is_aptos_framework_address(signer::address_of(aptos_framework)); include reconfiguration_with_dkg::FinishRequirement { - account: aptos_framework + framework: aptos_framework }; include stake::GetReconfigStartTimeRequirement; @@ -840,7 +840,7 @@ spec aptos_framework::aptos_governance { pragma verify = false; // TODO: set because of timeout (property proved). let address = signer::address_of(aptos_framework); include reconfiguration_with_dkg::FinishRequirement { - account: aptos_framework + framework: aptos_framework }; } diff --git a/aptos-move/framework/aptos-framework/sources/coin.move b/aptos-move/framework/aptos-framework/sources/coin.move index 2e7a9aa6a4a0b..1b7238384ed73 100644 --- a/aptos-move/framework/aptos-framework/sources/coin.move +++ b/aptos-move/framework/aptos-framework/sources/coin.move @@ -2,17 +2,24 @@ module aptos_framework::coin { use std::string; use std::error; + use std::features; use std::option::{Self, Option}; use std::signer; + use aptos_std::table::{Self, Table}; use aptos_framework::account; use aptos_framework::aggregator_factory; use aptos_framework::aggregator::{Self, Aggregator}; use aptos_framework::event::{Self, EventHandle}; + use aptos_framework::guid; use aptos_framework::optional_aggregator::{Self, OptionalAggregator}; use aptos_framework::system_addresses; - use aptos_std::type_info; + use aptos_framework::fungible_asset::{Self, FungibleAsset, Metadata, MintRef, TransferRef, BurnRef}; + use aptos_framework::object::{Self, Object, object_address}; + use aptos_framework::primary_fungible_store; + use aptos_std::type_info::{Self, TypeInfo}; + use aptos_framework::create_signer; friend aptos_framework::aptos_coin; friend aptos_framework::genesis; @@ -43,9 +50,6 @@ module aptos_framework::coin { /// Cannot destroy non-zero coins const EDESTRUCTION_OF_NONZERO_TOKEN: u64 = 7; - /// Coin amount cannot be zero - const EZERO_COIN_AMOUNT: u64 = 9; - /// CoinStore is frozen. Coins cannot be deposited or withdrawn const EFROZEN: u64 = 10; @@ -61,6 +65,48 @@ module aptos_framework::coin { /// The value of aggregatable coin used for transaction fees redistribution does not fit in u64. const EAGGREGATABLE_COIN_VALUE_TOO_LARGE: u64 = 14; + /// Error regarding paired coin type of the fungible asset metadata. + const EPAIRED_COIN: u64 = 15; + + /// Error regarding paired fungible asset metadata of a coin type. + const EPAIRED_FUNGIBLE_ASSET: u64 = 16; + + /// The coin type from the map does not match the calling function type argument. + const ECOIN_TYPE_MISMATCH: u64 = 17; + + /// The feature of migration from coin to fungible asset is not enabled. + const ECOIN_TO_FUNGIBLE_ASSET_FEATURE_NOT_ENABLED: u64 = 18; + + /// PairedFungibleAssetRefs resource does not exist. + const EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND: u64 = 19; + + /// The MintRefReceipt does not match the MintRef to be returned. + const EMINT_REF_RECEIPT_MISMATCH: u64 = 20; + + /// The MintRef does not exist. + const EMINT_REF_NOT_FOUND: u64 = 21; + + /// The TransferRefReceipt does not match the TransferRef to be returned. + const ETRANSFER_REF_RECEIPT_MISMATCH: u64 = 22; + + /// The TransferRef does not exist. + const ETRANSFER_REF_NOT_FOUND: u64 = 23; + + /// The BurnRefReceipt does not match the BurnRef to be returned. + const EBURN_REF_RECEIPT_MISMATCH: u64 = 24; + + /// The BurnRef does not exist. + const EBURN_REF_NOT_FOUND: u64 = 25; + + /// The migration process from coin to fungible asset is not enabled yet. + const EMIGRATION_FRAMEWORK_NOT_ENABLED: u64 = 26; + + /// The coin converison map is not created yet. + const ECOIN_CONVERSION_MAP_NOT_FOUND: u64 = 27; + + /// APT pairing is not eanbled yet. + const EAPT_PAIRING_IS_NOT_ENABLED: u64 = 28; + // // Constants // @@ -125,6 +171,7 @@ module aptos_framework::coin { } #[event] + /// Module event emitted when some amount of a coin is deposited into an account. struct Deposit has drop, store { account: address, amount: u64, @@ -136,11 +183,31 @@ module aptos_framework::coin { } #[event] + /// Module event emitted when some amount of a coin is withdrawn from an account. struct Withdraw has drop, store { account: address, amount: u64, } + #[event] + /// Module event emitted when the event handles related to coin store is deleted. + struct CoinEventHandleDeletion has drop, store { + event_handle_creation_address: address, + deleted_deposit_event_handle_creation_number: u64, + deleted_withdraw_event_handle_creation_number: u64, + } + + #[event] + /// Module event emitted when a new pair of coin and fungible asset is created. + struct PairCreation has drop, store { + coin_type: TypeInfo, + fungible_asset_metadata_address: address, + } + + #[resource_group_member(group = aptos_framework::object::ObjectGroup)] + /// The flag the existence of which indicates the primary fungible store is created by the migration from CoinStore. + struct MigrationFlag has key {} + /// Capability required to mint coins. struct MintCapability has copy, store {} @@ -150,6 +217,290 @@ module aptos_framework::coin { /// Capability required to burn coins. struct BurnCapability has copy, store {} + /// The mapping between coin and fungible asset. + struct CoinConversionMap has key { + coin_to_fungible_asset_map: Table>, + } + + #[resource_group_member(group = aptos_framework::object::ObjectGroup)] + /// The paired coin type info stored in fungible asset metadata object. + struct PairedCoinType has key { + type: TypeInfo, + } + + #[resource_group_member(group = aptos_framework::object::ObjectGroup)] + /// The refs of the paired fungible asset. + struct PairedFungibleAssetRefs has key { + mint_ref_opt: Option, + transfer_ref_opt: Option, + burn_ref_opt: Option, + } + + /// The hot potato receipt for flash borrowing MintRef. + struct MintRefReceipt { + metadata: Object, + } + + /// The hot potato receipt for flash borrowing TransferRef. + struct TransferRefReceipt { + metadata: Object, + } + + /// The hot potato receipt for flash borrowing BurnRef. + struct BurnRefReceipt { + metadata: Object, + } + + #[view] + /// Get the paired fungible asset metadata object of a coin type. If not exist, return option::none(). + public fun paired_metadata(): Option> acquires CoinConversionMap { + if (exists(@aptos_framework) && features::coin_to_fungible_asset_migration_feature_enabled( + )) { + let map = &borrow_global(@aptos_framework).coin_to_fungible_asset_map; + let type = type_info::type_of(); + if (table::contains(map, type)) { + return option::some(*table::borrow(map, type)) + } + }; + option::none() + } + + public entry fun create_coin_conversion_map(aptos_framework: &signer) { + system_addresses::assert_aptos_framework(aptos_framework); + if (!exists(@aptos_framework)) { + move_to(aptos_framework, CoinConversionMap { + coin_to_fungible_asset_map: table::new(), + }) + }; + } + + /// Create APT pairing by passing `AptosCoin`. + public entry fun create_pairing( + aptos_framework: &signer + ) acquires CoinConversionMap, CoinInfo { + system_addresses::assert_aptos_framework(aptos_framework); + create_and_return_paired_metadata_if_not_exist(true); + } + + inline fun is_apt(): bool { + type_info::type_name() == string::utf8(b"0x1::aptos_coin::AptosCoin") + } + + inline fun create_and_return_paired_metadata_if_not_exist(allow_apt_creation: bool): Object { + assert!( + features::coin_to_fungible_asset_migration_feature_enabled(), + error::invalid_state(EMIGRATION_FRAMEWORK_NOT_ENABLED) + ); + assert!(exists(@aptos_framework), error::not_found(ECOIN_CONVERSION_MAP_NOT_FOUND)); + let map = borrow_global_mut(@aptos_framework); + let type = type_info::type_of(); + if (!table::contains(&map.coin_to_fungible_asset_map, type)) { + let is_apt = is_apt(); + assert!(!is_apt || allow_apt_creation, error::invalid_state(EAPT_PAIRING_IS_NOT_ENABLED)); + let metadata_object_cref = + if (is_apt) { + object::create_sticky_object_at_address(@aptos_framework, @aptos_fungible_asset) + } else { + object::create_sticky_object(coin_address()) + }; + primary_fungible_store::create_primary_store_enabled_fungible_asset( + &metadata_object_cref, + option::map(coin_supply(), |_| MAX_U128), + name(), + symbol(), + decimals(), + string::utf8(b""), + string::utf8(b""), + ); + + let metadata_object_signer = &object::generate_signer(&metadata_object_cref); + let type = type_info::type_of(); + move_to(metadata_object_signer, PairedCoinType { type }); + let metadata_obj = object::object_from_constructor_ref(&metadata_object_cref); + + table::add(&mut map.coin_to_fungible_asset_map, type, metadata_obj); + event::emit(PairCreation { + coin_type: type, + fungible_asset_metadata_address: object_address(&metadata_obj) + }); + + // Generates all three refs + let mint_ref = fungible_asset::generate_mint_ref(&metadata_object_cref); + let transfer_ref = fungible_asset::generate_transfer_ref(&metadata_object_cref); + let burn_ref = fungible_asset::generate_burn_ref(&metadata_object_cref); + move_to(metadata_object_signer, + PairedFungibleAssetRefs { + mint_ref_opt: option::some(mint_ref), + transfer_ref_opt: option::some(transfer_ref), + burn_ref_opt: option::some(burn_ref), + } + ); + }; + *table::borrow(&map.coin_to_fungible_asset_map, type) + } + + /// Get the paired fungible asset metadata object of a coin type, create if not exist. + public(friend) fun ensure_paired_metadata(): Object acquires CoinConversionMap, CoinInfo { + create_and_return_paired_metadata_if_not_exist(false) + } + + #[view] + /// Get the paired coin type of a fungible asset metadata object. + public fun paired_coin(metadata: Object): Option acquires PairedCoinType { + let metadata_addr = object::object_address(&metadata); + if (exists(metadata_addr)) { + option::some(borrow_global(metadata_addr).type) + } else { + option::none() + } + } + + /// Conversion from coin to fungible asset + public fun coin_to_fungible_asset( + coin: Coin + ): FungibleAsset acquires CoinConversionMap, CoinInfo { + let metadata = ensure_paired_metadata(); + let amount = burn_internal(coin); + fungible_asset::mint_internal(metadata, amount) + } + + /// Conversion from fungible asset to coin. Not public to push the migration to FA. + fun fungible_asset_to_coin( + fungible_asset: FungibleAsset + ): Coin acquires CoinInfo, PairedCoinType { + let metadata_addr = object::object_address(&fungible_asset::metadata_from_asset(&fungible_asset)); + assert!( + object::object_exists(metadata_addr), + error::not_found(EPAIRED_COIN) + ); + let coin_type_info = borrow_global(metadata_addr).type; + assert!(coin_type_info == type_info::type_of(), error::invalid_argument(ECOIN_TYPE_MISMATCH)); + let amount = fungible_asset::burn_internal(fungible_asset); + mint_internal(amount) + } + + inline fun assert_paired_metadata_exists(): Object { + let metadata_opt = paired_metadata(); + assert!(option::is_some(&metadata_opt), error::not_found(EPAIRED_FUNGIBLE_ASSET)); + option::destroy_some(metadata_opt) + } + + #[view] + /// Check whether `MintRef` has not been taken. + public fun paired_mint_ref_exists(): bool acquires CoinConversionMap, PairedFungibleAssetRefs { + let metadata = assert_paired_metadata_exists(); + let metadata_addr = object_address(&metadata); + assert!(exists(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)); + option::is_some(&borrow_global(metadata_addr).mint_ref_opt) + } + + /// Get the `MintRef` of paired fungible asset of a coin type from `MintCapability`. + public fun get_paired_mint_ref( + _: &MintCapability + ): (MintRef, MintRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs { + let metadata = assert_paired_metadata_exists(); + let metadata_addr = object_address(&metadata); + assert!(exists(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)); + let mint_ref_opt = &mut borrow_global_mut(metadata_addr).mint_ref_opt; + assert!(option::is_some(mint_ref_opt), error::not_found(EMINT_REF_NOT_FOUND)); + (option::extract(mint_ref_opt), MintRefReceipt { metadata }) + } + + /// Return the `MintRef` with the hot potato receipt. + public fun return_paired_mint_ref(mint_ref: MintRef, receipt: MintRefReceipt) acquires PairedFungibleAssetRefs { + let MintRefReceipt { metadata } = receipt; + assert!( + fungible_asset::mint_ref_metadata(&mint_ref) == metadata, + error::invalid_argument(EMINT_REF_RECEIPT_MISMATCH) + ); + let metadata_addr = object_address(&metadata); + let mint_ref_opt = &mut borrow_global_mut(metadata_addr).mint_ref_opt; + option::fill(mint_ref_opt, mint_ref); + } + + #[view] + /// Check whether `TransferRef` still exists. + public fun paired_transfer_ref_exists(): bool acquires CoinConversionMap, PairedFungibleAssetRefs { + let metadata = assert_paired_metadata_exists(); + let metadata_addr = object_address(&metadata); + assert!(exists(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)); + option::is_some(&borrow_global(metadata_addr).transfer_ref_opt) + } + + /// Get the TransferRef of paired fungible asset of a coin type from `FreezeCapability`. + public fun get_paired_transfer_ref( + _: &FreezeCapability + ): (TransferRef, TransferRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs { + let metadata = assert_paired_metadata_exists(); + let metadata_addr = object_address(&metadata); + assert!(exists(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)); + let transfer_ref_opt = &mut borrow_global_mut(metadata_addr).transfer_ref_opt; + assert!(option::is_some(transfer_ref_opt), error::not_found(ETRANSFER_REF_NOT_FOUND)); + (option::extract(transfer_ref_opt), TransferRefReceipt { metadata }) + } + + /// Return the `TransferRef` with the hot potato receipt. + public fun return_paired_transfer_ref( + transfer_ref: TransferRef, + receipt: TransferRefReceipt + ) acquires PairedFungibleAssetRefs { + let TransferRefReceipt { metadata } = receipt; + assert!( + fungible_asset::transfer_ref_metadata(&transfer_ref) == metadata, + error::invalid_argument(ETRANSFER_REF_RECEIPT_MISMATCH) + ); + let metadata_addr = object_address(&metadata); + let transfer_ref_opt = &mut borrow_global_mut(metadata_addr).transfer_ref_opt; + option::fill(transfer_ref_opt, transfer_ref); + } + + #[view] + /// Check whether `BurnRef` has not been taken. + public fun paired_burn_ref_exists(): bool acquires CoinConversionMap, PairedFungibleAssetRefs { + let metadata = assert_paired_metadata_exists(); + let metadata_addr = object_address(&metadata); + assert!(exists(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)); + option::is_some(&borrow_global(metadata_addr).burn_ref_opt) + } + + /// Get the `BurnRef` of paired fungible asset of a coin type from `BurnCapability`. + public fun get_paired_burn_ref( + _: &BurnCapability + ): (BurnRef, BurnRefReceipt) acquires CoinConversionMap, PairedFungibleAssetRefs { + let metadata = assert_paired_metadata_exists(); + let metadata_addr = object_address(&metadata); + assert!(exists(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)); + let burn_ref_opt = &mut borrow_global_mut(metadata_addr).burn_ref_opt; + assert!(option::is_some(burn_ref_opt), error::not_found(EBURN_REF_NOT_FOUND)); + (option::extract(burn_ref_opt), BurnRefReceipt { metadata }) + } + + /// Return the `BurnRef` with the hot potato receipt. + public fun return_paired_burn_ref( + burn_ref: BurnRef, + receipt: BurnRefReceipt + ) acquires PairedFungibleAssetRefs { + let BurnRefReceipt { metadata } = receipt; + assert!( + fungible_asset::burn_ref_metadata(&burn_ref) == metadata, + error::invalid_argument(EBURN_REF_RECEIPT_MISMATCH) + ); + let metadata_addr = object_address(&metadata); + let burn_ref_opt = &mut borrow_global_mut(metadata_addr).burn_ref_opt; + option::fill(burn_ref_opt, burn_ref); + } + + inline fun borrow_paired_burn_ref( + _: &BurnCapability + ): &BurnRef acquires CoinConversionMap, PairedFungibleAssetRefs { + let metadata = assert_paired_metadata_exists(); + let metadata_addr = object_address(&metadata); + assert!(exists(metadata_addr), error::internal(EPAIRED_FUNGIBLE_ASSET_REFS_NOT_FOUND)); + let burn_ref_opt = &mut borrow_global_mut(metadata_addr).burn_ref_opt; + assert!(option::is_some(burn_ref_opt), error::not_found(EBURN_REF_NOT_FOUND)); + option::borrow(burn_ref_opt) + } + // // Total supply config // @@ -228,17 +579,98 @@ module aptos_framework::coin { account_addr: address, amount: u64, dst_coin: &mut AggregatableCoin, - ) acquires CoinStore { + ) acquires CoinStore, CoinConversionMap, CoinInfo, PairedCoinType { // Skip collecting if amount is zero. if (amount == 0) { return }; - let coin_store = borrow_global_mut>(account_addr); - let coin = extract(&mut coin_store.coin, amount); + let (coin_amount_to_collect, fa_amount_to_collect) = calculate_amount_to_withdraw( + account_addr, + amount + ); + let coin = if (coin_amount_to_collect > 0) { + let coin_store = borrow_global_mut>(account_addr); + extract(&mut coin_store.coin, coin_amount_to_collect) + } else { + zero() + }; + if (fa_amount_to_collect > 0) { + let store_addr = primary_fungible_store::primary_store_address( + account_addr, + option::destroy_some(paired_metadata()) + ); + let fa = fungible_asset::withdraw_internal(store_addr, fa_amount_to_collect); + merge(&mut coin, fungible_asset_to_coin(fa)); + }; merge_aggregatable_coin(dst_coin, coin); } + inline fun calculate_amount_to_withdraw( + account_addr: address, + amount: u64 + ): (u64, u64) { + let coin_balance = coin_balance(account_addr); + if (coin_balance >= amount) { + (amount, 0) + } else { + let metadata = paired_metadata(); + if (option::is_none(&metadata) || !primary_fungible_store::primary_store_exists( + account_addr, + option::destroy_some(metadata) + )) + abort error::invalid_argument(EINSUFFICIENT_BALANCE) + else + (coin_balance, amount - coin_balance) + } + } + + fun maybe_convert_to_fungible_store(account: address) acquires CoinStore, CoinConversionMap, CoinInfo { + if (!features::coin_to_fungible_asset_migration_feature_enabled()) { + abort error::unavailable(ECOIN_TO_FUNGIBLE_ASSET_FEATURE_NOT_ENABLED) + }; + let metadata = ensure_paired_metadata(); + let store = primary_fungible_store::ensure_primary_store_exists(account, metadata); + let store_address = object::object_address(&store); + if (exists>(account)) { + let CoinStore { coin, frozen, deposit_events, withdraw_events } = move_from>( + account + ); + event::emit( + CoinEventHandleDeletion { + event_handle_creation_address: guid::creator_address( + event::guid(&deposit_events) + ), + deleted_deposit_event_handle_creation_number: guid::creation_num(event::guid(&deposit_events)), + deleted_withdraw_event_handle_creation_number: guid::creation_num(event::guid(&withdraw_events)) + } + ); + event::destroy_handle(deposit_events); + event::destroy_handle(withdraw_events); + if (coin.value == 0) { + destroy_zero(coin); + } else { + fungible_asset::deposit(store, coin_to_fungible_asset(coin)); + }; + // Note: + // It is possible the primary fungible store may already exist before this function call. + // In this case, if the account owns a frozen CoinStore and an unfrozen primary fungible store, this + // function would convert and deposit the rest coin into the primary store and freeze it to make the + // `frozen` semantic as consistent as possible. + fungible_asset::set_frozen_flag_internal(store, frozen); + }; + if (!exists(store_address)) { + move_to(&create_signer::create_signer(store_address), MigrationFlag {}); + } + } + + /// Voluntarily migrate to fungible store for `CoinType` if not yet. + public entry fun migrate_to_fungible_store( + account: &signer + ) acquires CoinStore, CoinConversionMap, CoinInfo { + maybe_convert_to_fungible_store(signer::address_of(account)); + } + // // Getter functions // @@ -250,13 +682,42 @@ module aptos_framework::coin { } #[view] - /// Returns the balance of `owner` for provided `CoinType`. - public fun balance(owner: address): u64 acquires CoinStore { - assert!( - is_account_registered(owner), - error::not_found(ECOIN_STORE_NOT_PUBLISHED), - ); - borrow_global>(owner).coin.value + /// Returns the balance of `owner` for provided `CoinType` and its paired FA if exists. + public fun balance(owner: address): u64 acquires CoinConversionMap, CoinStore { + let paired_metadata = paired_metadata(); + coin_balance(owner) + if (option::is_some(&paired_metadata)) { + primary_fungible_store::balance( + owner, + option::extract(&mut paired_metadata) + ) + } else { 0 } + } + + #[view] + /// Returns whether the balance of `owner` for provided `CoinType` and its paired FA is >= `amount`. + public fun is_balance_at_least(owner: address, amount: u64): bool acquires CoinConversionMap, CoinStore { + let coin_balance = coin_balance(owner); + if (coin_balance >= amount) { + return true + }; + + let paired_metadata = paired_metadata(); + let left_amount = amount - coin_balance; + if (option::is_some(&paired_metadata)) { + primary_fungible_store::is_balance_at_least( + owner, + option::extract(&mut paired_metadata), + left_amount + ) + } else { false } + } + + inline fun coin_balance(owner: address): u64 { + if (exists>(owner)) { + borrow_global>(owner).coin.value + } else { + 0 + } } #[view] @@ -267,7 +728,9 @@ module aptos_framework::coin { #[view] /// Returns `true` is account_addr has frozen the CoinStore or if it's not registered at all - public fun is_coin_store_frozen(account_addr: address): bool acquires CoinStore { + public fun is_coin_store_frozen( + account_addr: address + ): bool acquires CoinStore, CoinConversionMap { if (!is_account_registered(account_addr)) { return true }; @@ -278,8 +741,15 @@ module aptos_framework::coin { #[view] /// Returns `true` if `account_addr` is registered to receive `CoinType`. - public fun is_account_registered(account_addr: address): bool { - exists>(account_addr) + public fun is_account_registered(account_addr: address): bool acquires CoinConversionMap { + if (exists>(account_addr)) { + true + } else { + let paired_metadata_opt = paired_metadata(); + (option::is_some( + &paired_metadata_opt + ) && migrated_primary_fungible_store_exists(account_addr, option::destroy_some(paired_metadata_opt))) + } } #[view] @@ -304,7 +774,22 @@ module aptos_framework::coin { #[view] /// Returns the amount of coin in existence. - public fun supply(): Option acquires CoinInfo { + public fun supply(): Option acquires CoinInfo, CoinConversionMap { + let coin_supply = coin_supply(); + let metadata = paired_metadata(); + if (option::is_some(&metadata)) { + let fungible_asset_supply = fungible_asset::supply(option::extract(&mut metadata)); + if (option::is_some(&coin_supply)) { + let supply = option::borrow_mut(&mut coin_supply); + *supply = *supply + option::destroy_some(fungible_asset_supply); + }; + }; + coin_supply + } + + #[view] + /// Returns the amount of coin in existence. + public fun coin_supply(): Option acquires CoinInfo { let maybe_supply = &borrow_global>(coin_address()).supply; if (option::is_some(maybe_supply)) { // We do track supply, in this case read from optional aggregator. @@ -315,28 +800,14 @@ module aptos_framework::coin { option::none() } } - // // Public functions // /// Burn `coin` with capability. /// The capability `_cap` should be passed as a reference to `BurnCapability`. - public fun burn( - coin: Coin, - _cap: &BurnCapability, - ) acquires CoinInfo { - spec { - update supply = supply - coin.value; - }; - let Coin { value: amount } = coin; - assert!(amount > 0, error::invalid_argument(EZERO_COIN_AMOUNT)); - - let maybe_supply = &mut borrow_global_mut>(coin_address()).supply; - if (option::is_some(maybe_supply)) { - let supply = option::borrow_mut(maybe_supply); - optional_aggregator::sub(supply, (amount as u128)); - } + public fun burn(coin: Coin, _cap: &BurnCapability) acquires CoinInfo { + burn_internal(coin); } /// Burn `coin` from the specified `account` with capability. @@ -348,51 +819,93 @@ module aptos_framework::coin { account_addr: address, amount: u64, burn_cap: &BurnCapability, - ) acquires CoinInfo, CoinStore { + ) acquires CoinInfo, CoinStore, CoinConversionMap, PairedFungibleAssetRefs { // Skip burning if amount is zero. This shouldn't error out as it's called as part of transaction fee burning. if (amount == 0) { return }; - let coin_store = borrow_global_mut>(account_addr); - let coin_to_burn = extract(&mut coin_store.coin, amount); - burn(coin_to_burn, burn_cap); + let (coin_amount_to_burn, fa_amount_to_burn) = calculate_amount_to_withdraw( + account_addr, + amount + ); + if (coin_amount_to_burn > 0) { + let coin_store = borrow_global_mut>(account_addr); + let coin_to_burn = extract(&mut coin_store.coin, coin_amount_to_burn); + burn(coin_to_burn, burn_cap); + }; + if (fa_amount_to_burn > 0) { + fungible_asset::burn_from( + borrow_paired_burn_ref(burn_cap), + primary_fungible_store::primary_store(account_addr, option::destroy_some(paired_metadata())), + fa_amount_to_burn + ); + }; } /// Deposit the coin balance into the recipient's account and emit an event. - public fun deposit(account_addr: address, coin: Coin) acquires CoinStore { - assert!( - is_account_registered(account_addr), - error::not_found(ECOIN_STORE_NOT_PUBLISHED), - ); - - let coin_store = borrow_global_mut>(account_addr); - assert!( - !coin_store.frozen, - error::permission_denied(EFROZEN), - ); - if (std::features::module_event_migration_enabled()) { - event::emit(Deposit { account: account_addr, amount: coin.value }); - }; - event::emit_event( - &mut coin_store.deposit_events, - DepositEvent { amount: coin.value }, - ); + public fun deposit( + account_addr: address, + coin: Coin + ) acquires CoinStore, CoinConversionMap, CoinInfo { + if (exists>(account_addr)) { + let coin_store = borrow_global_mut>(account_addr); + assert!( + !coin_store.frozen, + error::permission_denied(EFROZEN), + ); + if (std::features::module_event_migration_enabled()) { + event::emit(Deposit { account: account_addr, amount: coin.value }); + }; + event::emit_event( + &mut coin_store.deposit_events, + DepositEvent { amount: coin.value }, + ); + merge(&mut coin_store.coin, coin); + } else { + let metadata = paired_metadata(); + if (option::is_some(&metadata) && migrated_primary_fungible_store_exists( + account_addr, + option::destroy_some(metadata) + )) { + primary_fungible_store::deposit(account_addr, coin_to_fungible_asset(coin)); + } else { + abort error::not_found(ECOIN_STORE_NOT_PUBLISHED) + }; + } + } - merge(&mut coin_store.coin, coin); + inline fun migrated_primary_fungible_store_exists( + account_address: address, + metadata: Object + ): bool { + let primary_store_address = primary_fungible_store::primary_store_address(account_address, metadata); + fungible_asset::store_exists(primary_store_address) && exists(primary_store_address) } /// Deposit the coin balance into the recipient's account without checking if the account is frozen. /// This is for internal use only and doesn't emit an DepositEvent. - public(friend) fun force_deposit(account_addr: address, coin: Coin) acquires CoinStore { - assert!( - is_account_registered(account_addr), - error::not_found(ECOIN_STORE_NOT_PUBLISHED), - ); - - let coin_store = borrow_global_mut>(account_addr); - - merge(&mut coin_store.coin, coin); + public(friend) fun force_deposit( + account_addr: address, + coin: Coin + ) acquires CoinStore, CoinConversionMap, CoinInfo { + if (exists>(account_addr)) { + let coin_store = borrow_global_mut>(account_addr); + merge(&mut coin_store.coin, coin); + } else { + let metadata = paired_metadata(); + if (option::is_some(&metadata) && migrated_primary_fungible_store_exists( + account_addr, + option::destroy_some(metadata) + )) { + let fa = coin_to_fungible_asset(coin); + let metadata = fungible_asset::asset_metadata(&fa); + let store = primary_fungible_store::primary_store(account_addr, metadata); + fungible_asset::deposit_internal(store, fa); + } else { + abort error::not_found(ECOIN_STORE_NOT_PUBLISHED) + } + } } /// Destroys a zero-value coin. Calls will fail if the `value` in the passed-in `token` is non-zero @@ -566,34 +1079,10 @@ module aptos_framework::coin { amount: u64, _cap: &MintCapability, ): Coin acquires CoinInfo { - if (amount == 0) { - return Coin { - value: 0 - } - }; - - let maybe_supply = &mut borrow_global_mut>(coin_address()).supply; - if (option::is_some(maybe_supply)) { - let supply = option::borrow_mut(maybe_supply); - spec { - use aptos_framework::optional_aggregator; - use aptos_framework::aggregator; - assume optional_aggregator::is_parallelizable(supply) ==> (aggregator::spec_aggregator_get_val( - option::borrow(supply.aggregator) - ) - + amount <= aggregator::spec_get_limit(option::borrow(supply.aggregator))); - assume !optional_aggregator::is_parallelizable(supply) ==> - (option::borrow(supply.integer).value + amount <= option::borrow(supply.integer).limit); - }; - optional_aggregator::add(supply, (amount as u128)); - }; - spec { - update supply = supply + amount; - }; - Coin { value: amount } + mint_internal(amount) } - public fun register(account: &signer) { + public fun register(account: &signer) acquires CoinConversionMap { let account_addr = signer::address_of(account); // Short-circuit and do nothing if account is already registered for CoinType. if (is_account_registered(account_addr)) { @@ -615,7 +1104,7 @@ module aptos_framework::coin { from: &signer, to: address, amount: u64, - ) acquires CoinStore { + ) acquires CoinStore, CoinConversionMap, CoinInfo, PairedCoinType { let coin = withdraw(from, amount); deposit(to, coin); } @@ -629,28 +1118,39 @@ module aptos_framework::coin { public fun withdraw( account: &signer, amount: u64, - ): Coin acquires CoinStore { + ): Coin acquires CoinStore, CoinConversionMap, CoinInfo, PairedCoinType { let account_addr = signer::address_of(account); - assert!( - is_account_registered(account_addr), - error::not_found(ECOIN_STORE_NOT_PUBLISHED), - ); - let coin_store = borrow_global_mut>(account_addr); - assert!( - !coin_store.frozen, - error::permission_denied(EFROZEN), + let (coin_amount_to_withdraw, fa_amount_to_withdraw) = calculate_amount_to_withdraw( + account_addr, + amount ); - - if (std::features::module_event_migration_enabled()) { - event::emit(Withdraw { account: account_addr, amount }); + let withdrawn_coin = if (coin_amount_to_withdraw > 0) { + let coin_store = borrow_global_mut>(account_addr); + assert!( + !coin_store.frozen, + error::permission_denied(EFROZEN), + ); + if (std::features::module_event_migration_enabled()) { + event::emit(Withdraw { account: account_addr, amount: coin_amount_to_withdraw }); + }; + event::emit_event( + &mut coin_store.withdraw_events, + WithdrawEvent { amount: coin_amount_to_withdraw }, + ); + extract(&mut coin_store.coin, coin_amount_to_withdraw) + } else { + zero() }; - event::emit_event( - &mut coin_store.withdraw_events, - WithdrawEvent { amount }, - ); - - extract(&mut coin_store.coin, amount) + if (fa_amount_to_withdraw > 0) { + let fa = primary_fungible_store::withdraw( + account, + option::destroy_some(paired_metadata()), + fa_amount_to_withdraw + ); + merge(&mut withdrawn_coin, fungible_asset_to_coin(fa)); + }; + withdrawn_coin } /// Create a new `Coin` with a value of `0`. @@ -678,6 +1178,49 @@ module aptos_framework::coin { let BurnCapability {} = burn_cap; } + fun mint_internal(amount: u64): Coin acquires CoinInfo { + if (amount == 0) { + return Coin { + value: 0 + } + }; + + let maybe_supply = &mut borrow_global_mut>(coin_address()).supply; + if (option::is_some(maybe_supply)) { + let supply = option::borrow_mut(maybe_supply); + spec { + use aptos_framework::optional_aggregator; + use aptos_framework::aggregator; + assume optional_aggregator::is_parallelizable(supply) ==> (aggregator::spec_aggregator_get_val( + option::borrow(supply.aggregator) + ) + + amount <= aggregator::spec_get_limit(option::borrow(supply.aggregator))); + assume !optional_aggregator::is_parallelizable(supply) ==> + (option::borrow(supply.integer).value + amount <= option::borrow(supply.integer).limit); + }; + optional_aggregator::add(supply, (amount as u128)); + }; + spec { + update supply = supply + amount; + }; + Coin { value: amount } + } + + fun burn_internal(coin: Coin): u64 acquires CoinInfo { + spec { + update supply = supply - coin.value; + }; + let Coin { value: amount } = coin; + if (amount != 0) { + let maybe_supply = &mut borrow_global_mut>(coin_address()).supply; + if (option::is_some(maybe_supply)) { + let supply = option::borrow_mut(maybe_supply); + optional_aggregator::sub(supply, (amount as u128)); + }; + }; + amount + } + #[test_only] struct FakeMoney {} @@ -688,6 +1231,31 @@ module aptos_framework::coin { mint_cap: MintCapability, } + #[test_only] + struct FakeMoneyRefs has key { + mint_ref: MintRef, + transfer_ref: TransferRef, + burn_ref: BurnRef, + } + + #[test_only] + fun create_coin_store(account: &signer) { + if (!exists>(signer::address_of(account))) { + let coin_store = CoinStore { + coin: Coin { value: 0 }, + frozen: false, + deposit_events: account::new_event_handle(account), + withdraw_events: account::new_event_handle(account), + }; + move_to(account, coin_store); + } + } + + #[test_only] + fun coin_store_exists(account: address): bool { + exists>(account) + } + #[test_only] fun initialize_fake_money( account: &signer, @@ -705,7 +1273,7 @@ module aptos_framework::coin { } #[test_only] - fun initialize_and_register_fake_money( + public fun initialize_and_register_fake_money( account: &signer, decimals: u8, monitor_supply: bool, @@ -715,7 +1283,8 @@ module aptos_framework::coin { decimals, monitor_supply ); - register(account); + create_coin_store(account); + create_coin_conversion_map(account); (burn_cap, freeze_cap, mint_cap) } @@ -724,10 +1293,10 @@ module aptos_framework::coin { source: &signer, destination: &signer, amount: u64 - ) acquires CoinInfo, CoinStore { + ) acquires CoinInfo, CoinStore, CoinConversionMap { let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(source, 18, true); - register(destination); + create_coin_store(destination); let coins_minted = mint(amount, &mint_cap); deposit(signer::address_of(source), coins_minted); move_to(source, FakeMoneyCapabilities { @@ -741,7 +1310,7 @@ module aptos_framework::coin { public entry fun end_to_end( source: signer, destination: signer, - ) acquires CoinInfo, CoinStore { + ) acquires CoinInfo, CoinStore, CoinConversionMap, PairedCoinType { let source_addr = signer::address_of(&source); account::create_account_for_test(source_addr); let destination_addr = signer::address_of(&destination); @@ -750,11 +1319,8 @@ module aptos_framework::coin { let name = string::utf8(b"Fake money"); let symbol = string::utf8(b"FMD"); - aggregator_factory::initialize_aggregator_factory_for_test(&source); - let (burn_cap, freeze_cap, mint_cap) = initialize( + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money( &source, - name, - symbol, 18, true ); @@ -768,7 +1334,13 @@ module aptos_framework::coin { let coins_minted = mint(100, &mint_cap); deposit(source_addr, coins_minted); + maybe_convert_to_fungible_store(source_addr); + assert!(!coin_store_exists(source_addr), 0); + assert!(coin_store_exists(destination_addr), 0); + transfer(&source, destination_addr, 50); + maybe_convert_to_fungible_store(destination_addr); + assert!(!coin_store_exists(destination_addr), 0); assert!(balance(source_addr) == 50, 4); assert!(balance(destination_addr) == 50, 5); @@ -790,7 +1362,7 @@ module aptos_framework::coin { public entry fun end_to_end_no_supply( source: signer, destination: signer, - ) acquires CoinInfo, CoinStore { + ) acquires CoinInfo, CoinStore, CoinConversionMap, PairedCoinType { let source_addr = signer::address_of(&source); account::create_account_for_test(source_addr); let destination_addr = signer::address_of(&destination); @@ -840,11 +1412,10 @@ module aptos_framework::coin { } #[test(source = @0x1, destination = @0x2)] - #[expected_failure(abort_code = 0x60005, location = Self)] - public entry fun fail_transfer( + public entry fun transfer_to_migrated_destination( source: signer, destination: signer, - ) acquires CoinInfo, CoinStore { + ) acquires CoinInfo, CoinStore, CoinConversionMap, PairedCoinType { let source_addr = signer::address_of(&source); account::create_account_for_test(source_addr); let destination_addr = signer::address_of(&destination); @@ -855,7 +1426,12 @@ module aptos_framework::coin { let coins_minted = mint(100, &mint_cap); deposit(source_addr, coins_minted); + maybe_convert_to_fungible_store(source_addr); + assert!(!coin_store_exists(source_addr), 0); + maybe_convert_to_fungible_store(destination_addr); transfer(&source, destination_addr, 50); + assert!(balance(destination_addr) == 50, 2); + assert!(!coin_store_exists(destination_addr), 0); move_to(&source, FakeMoneyCapabilities { burn_cap, @@ -864,16 +1440,39 @@ module aptos_framework::coin { }); } - #[test(source = @0x1, destination = @0x2)] + #[test(source = @0x1)] public entry fun test_burn_from_with_capability( source: signer, - ) acquires CoinInfo, CoinStore { + ) acquires CoinInfo, CoinStore, CoinConversionMap, PairedFungibleAssetRefs { let source_addr = signer::address_of(&source); account::create_account_for_test(source_addr); let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(&source, 1, true); let coins_minted = mint(100, &mint_cap); deposit(source_addr, coins_minted); + let fa_minted = coin_to_fungible_asset(mint(200, &mint_cap)); + primary_fungible_store::deposit(source_addr, fa_minted); + + // Burn coin only with both stores + burn_from(source_addr, 50, &burn_cap); + assert!(balance(source_addr) == 250, 0); + assert!(coin_balance(source_addr) == 50, 0); + + // Burn coin and fa with both stores + burn_from(source_addr, 100, &burn_cap); + assert!(balance(source_addr) == 150, 0); + assert!(primary_fungible_store::balance(source_addr, ensure_paired_metadata()) == 150, 0); + + // Burn fa only with both stores + burn_from(source_addr, 100, &burn_cap); + assert!(balance(source_addr) == 50, 0); + assert!(primary_fungible_store::balance(source_addr, ensure_paired_metadata()) == 50, 0); + + // Burn fa only with only fungible store + let coins_minted = mint(50, &mint_cap); + deposit(source_addr, coins_minted); + maybe_convert_to_fungible_store(source_addr); + assert!(!coin_store_exists(source_addr), 0); assert!(balance(source_addr) == 100, 0); assert!(*option::borrow(&supply()) == 100, 1); @@ -908,7 +1507,7 @@ module aptos_framework::coin { #[test(source = @0x1)] public entry fun test_extract( source: signer, - ) acquires CoinInfo, CoinStore { + ) acquires CoinInfo, CoinStore, CoinConversionMap { let source_addr = signer::address_of(&source); account::create_account_for_test(source_addr); let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(&source, 1, true); @@ -946,23 +1545,14 @@ module aptos_framework::coin { } #[test(account = @0x1)] - public fun test_is_coin_store_frozen(account: signer) acquires CoinStore { + public fun test_is_coin_store_frozen(account: signer) acquires CoinStore, CoinConversionMap, CoinInfo { let account_addr = signer::address_of(&account); - // An non registered account is has a frozen coin store by default - assert!(is_coin_store_frozen(account_addr), 1); - account::create_account_for_test(account_addr); let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(&account, 18, true); - - assert!(!is_coin_store_frozen(account_addr), 1); - - // freeze account - freeze_coin_store(account_addr, &freeze_cap); - assert!(is_coin_store_frozen(account_addr), 1); - - // unfreeze account - unfreeze_coin_store(account_addr, &freeze_cap); + assert!(coin_store_exists(account_addr), 1); assert!(!is_coin_store_frozen(account_addr), 1); + maybe_convert_to_fungible_store(account_addr); + assert!(!coin_store_exists(account_addr), 1); move_to(&account, FakeMoneyCapabilities { burn_cap, @@ -979,7 +1569,9 @@ module aptos_framework::coin { } #[test(account = @0x1)] - public entry fun burn_frozen(account: signer) acquires CoinInfo, CoinStore { + public entry fun burn_frozen( + account: signer + ) acquires CoinInfo, CoinStore, CoinConversionMap, PairedFungibleAssetRefs { let account_addr = signer::address_of(&account); account::create_account_for_test(account_addr); let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(&account, 18, true); @@ -988,7 +1580,10 @@ module aptos_framework::coin { deposit(account_addr, coins_minted); freeze_coin_store(account_addr, &freeze_cap); - burn_from(account_addr, 100, &burn_cap); + burn_from(account_addr, 90, &burn_cap); + maybe_convert_to_fungible_store(account_addr); + assert!(primary_fungible_store::is_frozen(account_addr, ensure_paired_metadata()), 1); + assert!(primary_fungible_store::balance(account_addr, ensure_paired_metadata()) == 10, 1); move_to(&account, FakeMoneyCapabilities { burn_cap, @@ -998,14 +1593,17 @@ module aptos_framework::coin { } #[test(account = @0x1)] - #[expected_failure(abort_code = 0x5000A, location = Self)] - public entry fun withdraw_frozen(account: signer) acquires CoinInfo, CoinStore { + #[expected_failure(abort_code = 0x50003, location = aptos_framework::fungible_asset)] + public entry fun withdraw_frozen(account: signer) acquires CoinInfo, CoinStore, CoinConversionMap, PairedCoinType { let account_addr = signer::address_of(&account); account::create_account_for_test(account_addr); let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(&account, 18, true); + let coins_minted = mint(100, &mint_cap); + deposit(account_addr, coins_minted); freeze_coin_store(account_addr, &freeze_cap); - let coin = withdraw(&account, 10); + maybe_convert_to_fungible_store(account_addr); + let coin = withdraw(&account, 90); burn(coin, &burn_cap); move_to(&account, FakeMoneyCapabilities { @@ -1017,7 +1615,7 @@ module aptos_framework::coin { #[test(account = @0x1)] #[expected_failure(abort_code = 0x5000A, location = Self)] - public entry fun deposit_frozen(account: signer) acquires CoinInfo, CoinStore { + public entry fun deposit_frozen(account: signer) acquires CoinInfo, CoinStore, CoinConversionMap { let account_addr = signer::address_of(&account); account::create_account_for_test(account_addr); let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(&account, 18, true); @@ -1034,7 +1632,9 @@ module aptos_framework::coin { } #[test(account = @0x1)] - public entry fun deposit_widthdraw_unfrozen(account: signer) acquires CoinInfo, CoinStore { + public entry fun deposit_withdraw_unfrozen( + account: signer + ) acquires CoinInfo, CoinStore, CoinConversionMap, PairedCoinType { let account_addr = signer::address_of(&account); account::create_account_for_test(account_addr); let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(&account, 18, true); @@ -1088,6 +1688,7 @@ module aptos_framework::coin { }); } + #[test(framework = @aptos_framework, other = @0x123)] #[expected_failure(abort_code = 0x50003, location = aptos_framework::system_addresses)] fun test_supply_initialize_fails(framework: signer, other: signer) { @@ -1176,48 +1777,41 @@ module aptos_framework::coin { aggregator::destroy(value); } - #[test(framework = @aptos_framework)] - public entry fun test_register_twice_should_not_fail(framework: &signer) { - let framework_addr = signer::address_of(framework); - account::create_account_for_test(framework_addr); - let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(framework, 1, true); - - // Registering twice should not fail. - assert!(is_account_registered(@0x1), 0); - register(framework); - assert!(is_account_registered(@0x1), 1); - - move_to(framework, FakeMoneyCapabilities { - burn_cap, - freeze_cap, - mint_cap, - }); - } - #[test(framework = @aptos_framework)] public entry fun test_collect_from_and_drain( framework: signer, - ) acquires CoinInfo, CoinStore { + ) acquires CoinInfo, CoinStore, CoinConversionMap, PairedCoinType { let framework_addr = signer::address_of(&framework); account::create_account_for_test(framework_addr); let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(&framework, 1, true); + // Collect from coin store only. let coins_minted = mint(100, &mint_cap); deposit(framework_addr, coins_minted); - assert!(balance(framework_addr) == 100, 0); - assert!(*option::borrow(&supply()) == 100, 0); - let aggregatable_coin = initialize_aggregatable_coin(&framework); - collect_into_aggregatable_coin(framework_addr, 10, &mut aggregatable_coin); + collect_into_aggregatable_coin(framework_addr, 50, &mut aggregatable_coin); + + let fa_minted = coin_to_fungible_asset(mint(100, &mint_cap)); + primary_fungible_store::deposit(framework_addr, fa_minted); + assert!(balance(framework_addr) == 150, 0); + assert!(*option::borrow(&supply()) == 200, 0); + + // Collect from coin store and fungible store. + collect_into_aggregatable_coin(framework_addr, 100, &mut aggregatable_coin); + + assert!(balance(framework_addr) == 50, 0); + maybe_convert_to_fungible_store(framework_addr); + // Collect from fungible store only. + collect_into_aggregatable_coin(framework_addr, 30, &mut aggregatable_coin); // Check that aggregatable coin has the right amount. let collected_coin = drain_aggregatable_coin(&mut aggregatable_coin); assert!(is_aggregatable_coin_zero(&aggregatable_coin), 0); - assert!(value(&collected_coin) == 10, 0); + assert!(value(&collected_coin) == 180, 0); // Supply of coins should be unchanged, but the balance on the account should decrease. - assert!(balance(framework_addr) == 90, 0); - assert!(*option::borrow(&supply()) == 100, 0); + assert!(balance(framework_addr) == 20, 0); + assert!(*option::borrow(&supply()) == 200, 0); burn(collected_coin, &burn_cap); destroy_aggregatable_coin_for_test(aggregatable_coin); @@ -1227,4 +1821,329 @@ module aptos_framework::coin { mint_cap, }); } + + #[test_only] + fun deposit_to_coin_store(account_addr: address, coin: Coin) acquires CoinStore { + assert!( + coin_store_exists(account_addr), + error::not_found(ECOIN_STORE_NOT_PUBLISHED), + ); + + let coin_store = borrow_global_mut>(account_addr); + assert!( + !coin_store.frozen, + error::permission_denied(EFROZEN), + ); + + event::emit_event( + &mut coin_store.deposit_events, + DepositEvent { amount: coin.value }, + ); + + merge(&mut coin_store.coin, coin); + } + + #[test(account = @aptos_framework)] + fun test_conversion_basic( + account: &signer + ) acquires CoinConversionMap, CoinInfo, CoinStore, PairedCoinType, PairedFungibleAssetRefs { + let account_addr = signer::address_of(account); + account::create_account_for_test(account_addr); + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(account, 1, true); + + assert!(fungible_asset::name(ensure_paired_metadata()) == name(), 0); + assert!(fungible_asset::symbol(ensure_paired_metadata()) == symbol(), 0); + assert!(fungible_asset::decimals(ensure_paired_metadata()) == decimals(), 0); + + let minted_coin = mint(100, &mint_cap); + let converted_fa = coin_to_fungible_asset(minted_coin); + + // check and get refs + assert!(paired_mint_ref_exists(), 0); + assert!(paired_transfer_ref_exists(), 0); + assert!(paired_burn_ref_exists(), 0); + let (mint_ref, mint_ref_receipt) = get_paired_mint_ref(&mint_cap); + let (transfer_ref, transfer_ref_receipt) = get_paired_transfer_ref(&freeze_cap); + let (burn_ref, burn_ref_receipt) = get_paired_burn_ref(&burn_cap); + assert!(!paired_mint_ref_exists(), 0); + assert!(!paired_transfer_ref_exists(), 0); + assert!(!paired_burn_ref_exists(), 0); + + let minted_fa = fungible_asset::mint(&mint_ref, 100); + assert!(&converted_fa == &minted_fa, 0); + + let coin = fungible_asset_to_coin(converted_fa); + assert!(value(&coin) == 100, 0); + + deposit_to_coin_store(account_addr, coin); + assert!(coin_store_exists(account_addr), 0); + primary_fungible_store::deposit(account_addr, minted_fa); + assert!(balance(account_addr) == 200, 0); + + let withdrawn_coin = withdraw(account, 1); + maybe_convert_to_fungible_store(account_addr); + assert!(!coin_store_exists(account_addr), 0); + assert!(balance(account_addr) == 199, 0); + assert!(primary_fungible_store::balance(account_addr, ensure_paired_metadata()) == 199, 0); + + let fa = coin_to_fungible_asset(withdrawn_coin); + fungible_asset::burn(&burn_ref, fa); + + // Return and check the refs + return_paired_mint_ref(mint_ref, mint_ref_receipt); + return_paired_transfer_ref(transfer_ref, transfer_ref_receipt); + return_paired_burn_ref(burn_ref, burn_ref_receipt); + assert!(paired_mint_ref_exists(), 0); + assert!(paired_transfer_ref_exists(), 0); + assert!(paired_burn_ref_exists(), 0); + + move_to(account, FakeMoneyCapabilities { + burn_cap, + freeze_cap, + mint_cap, + }); + } + + #[test(account = @aptos_framework, aaron = @0xcafe)] + fun test_balance_with_both_stores( + account: &signer, + aaron: &signer + ) acquires CoinConversionMap, CoinInfo, CoinStore { + let account_addr = signer::address_of(account); + let aaron_addr = signer::address_of(aaron); + account::create_account_for_test(account_addr); + account::create_account_for_test(aaron_addr); + create_coin_store(aaron); + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(account, 1, true); + let coin = mint(100, &mint_cap); + let fa = coin_to_fungible_asset(mint(100, &mint_cap)); + primary_fungible_store::deposit(aaron_addr, fa); + deposit_to_coin_store(aaron_addr, coin); + assert!(coin_balance(aaron_addr) == 100, 0); + assert!(balance(aaron_addr) == 200, 0); + maybe_convert_to_fungible_store(aaron_addr); + assert!(balance(aaron_addr) == 200, 0); + assert!(coin_balance(aaron_addr) == 0, 0); + + move_to(account, FakeMoneyCapabilities { + burn_cap, + freeze_cap, + mint_cap, + }); + } + + #[test(account = @aptos_framework)] + fun test_deposit( + account: &signer, + ) acquires CoinConversionMap, CoinInfo, CoinStore { + let account_addr = signer::address_of(account); + account::create_account_for_test(account_addr); + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(account, 1, true); + let coin = mint(100, &mint_cap); + deposit(account_addr, coin); + assert!(coin_store_exists(account_addr), 0); + assert!(primary_fungible_store::balance(account_addr, ensure_paired_metadata()) == 0, 0); + assert!(balance(account_addr) == 100, 0); + + maybe_convert_to_fungible_store(account_addr); + let coin = mint(100, &mint_cap); + deposit(account_addr, coin); + assert!(!coin_store_exists(account_addr), 0); + assert!(balance(account_addr) == 200, 0); + assert!(primary_fungible_store::balance(account_addr, ensure_paired_metadata()) == 200, 0); + + move_to(account, FakeMoneyCapabilities { + burn_cap, + freeze_cap, + mint_cap, + }); + } + + #[test(account = @aptos_framework)] + fun test_withdraw( + account: &signer, + ) acquires CoinConversionMap, CoinInfo, CoinStore, PairedCoinType { + let account_addr = signer::address_of(account); + account::create_account_for_test(account_addr); + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(account, 1, true); + let coin = mint(200, &mint_cap); + deposit_to_coin_store(account_addr, coin); + assert!(coin_balance(account_addr) == 200, 0); + assert!(balance(account_addr) == 200, 0); + + // Withdraw from coin store only. + let coin = withdraw(account, 100); + assert!(coin_balance(account_addr) == 100, 0); + assert!(balance(account_addr) == 100, 0); + + let fa = coin_to_fungible_asset(coin); + primary_fungible_store::deposit(account_addr, fa); + assert!(coin_store_exists(account_addr), 0); + assert!(primary_fungible_store::balance(account_addr, ensure_paired_metadata()) == 100, 0); + assert!(balance(account_addr) == 200, 0); + + // Withdraw from both coin store and fungible store. + let coin = withdraw(account, 150); + assert!(coin_balance(account_addr) == 0, 0); + assert!(primary_fungible_store::balance(account_addr, ensure_paired_metadata()) == 50, 0); + + deposit_to_coin_store(account_addr, coin); + maybe_convert_to_fungible_store(account_addr); + assert!(!coin_store_exists(account_addr), 0); + assert!(balance(account_addr) == 200, 0); + assert!(primary_fungible_store::balance(account_addr, ensure_paired_metadata()) == 200, 0); + + // Withdraw from fungible store only. + let coin = withdraw(account, 150); + assert!(balance(account_addr) == 50, 0); + burn(coin, &burn_cap); + + move_to(account, FakeMoneyCapabilities { + burn_cap, + freeze_cap, + mint_cap, + }); + } + + #[test(account = @aptos_framework)] + fun test_supply( + account: &signer, + ) acquires CoinConversionMap, CoinInfo, PairedCoinType, PairedFungibleAssetRefs { + account::create_account_for_test(signer::address_of(account)); + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(account, 1, true); + let coin = mint(100, &mint_cap); + ensure_paired_metadata(); + let (mint_ref, mint_ref_receipt) = get_paired_mint_ref(&mint_cap); + let (burn_ref, burn_ref_receipt) = get_paired_burn_ref(&burn_cap); + let fungible_asset = fungible_asset::mint(&mint_ref, 50); + assert!(supply() == option::some(150), 0); + assert!(coin_supply() == option::some(100), 0); + assert!(fungible_asset::supply(ensure_paired_metadata()) == option::some(50), 0); + let fa_from_coin = coin_to_fungible_asset(coin); + assert!(supply() == option::some(150), 0); + assert!(coin_supply() == option::some(0), 0); + assert!(fungible_asset::supply(ensure_paired_metadata()) == option::some(150), 0); + + let coin_from_fa = fungible_asset_to_coin(fungible_asset); + assert!(supply() == option::some(150), 0); + assert!(coin_supply() == option::some(50), 0); + assert!(fungible_asset::supply(ensure_paired_metadata()) == option::some(100), 0); + burn(coin_from_fa, &burn_cap); + fungible_asset::burn(&burn_ref, fa_from_coin); + assert!(supply() == option::some(0), 0); + return_paired_mint_ref(mint_ref, mint_ref_receipt); + return_paired_burn_ref(burn_ref, burn_ref_receipt); + move_to(account, FakeMoneyCapabilities { + burn_cap, + freeze_cap, + mint_cap, + }); + } + + #[test(account = @aptos_framework, aaron = @0xaa10, bob = @0xb0b)] + #[expected_failure(abort_code = 0x60005, location = Self)] + fun test_force_deposit( + account: &signer, + aaron: &signer, + bob: &signer + ) acquires CoinConversionMap, CoinInfo, CoinStore { + let account_addr = signer::address_of(account); + let aaron_addr = signer::address_of(aaron); + let bob_addr = signer::address_of(bob); + account::create_account_for_test(account_addr); + account::create_account_for_test(aaron_addr); + account::create_account_for_test(bob_addr); + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(account, 1, true); + maybe_convert_to_fungible_store(aaron_addr); + deposit(aaron_addr, mint(1, &mint_cap)); + + force_deposit(account_addr, mint(100, &mint_cap)); + force_deposit(aaron_addr, mint(50, &mint_cap)); + assert!( + primary_fungible_store::balance(aaron_addr, option::extract(&mut paired_metadata())) == 51, + 0 + ); + assert!(coin_balance(account_addr) == 100, 0); + force_deposit(bob_addr, mint(1, &mint_cap)); + move_to(account, FakeMoneyCapabilities { + burn_cap, + freeze_cap, + mint_cap, + }); + } + + #[test(account = @aptos_framework, aaron = @0xaa10, bob = @0xb0b)] + fun test_is_account_registered( + account: &signer, + aaron: &signer, + bob: &signer, + ) acquires CoinConversionMap, CoinInfo, CoinStore { + let account_addr = signer::address_of(account); + let aaron_addr = signer::address_of(aaron); + let bob_addr = signer::address_of(bob); + account::create_account_for_test(account_addr); + account::create_account_for_test(aaron_addr); + account::create_account_for_test(bob_addr); + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(account, 1, true); + + assert!(coin_store_exists(account_addr), 0); + assert!(is_account_registered(account_addr), 0); + + assert!(!coin_store_exists(aaron_addr), 0); + assert!(!is_account_registered(aaron_addr), 0); + + maybe_convert_to_fungible_store(aaron_addr); + let coin = mint(100, &mint_cap); + deposit(aaron_addr, coin); + + assert!(!coin_store_exists(aaron_addr), 0); + assert!(is_account_registered(aaron_addr), 0); + + maybe_convert_to_fungible_store(account_addr); + assert!(!coin_store_exists(account_addr), 0); + assert!(is_account_registered(account_addr), 0); + + // Deposit FA to bob to created primary fungible store without `MigrationFlag`. + primary_fungible_store::deposit(bob_addr, coin_to_fungible_asset(mint(100, &mint_cap))); + assert!(!coin_store_exists(bob_addr), 0); + register(bob); + assert!(coin_store_exists(bob_addr), 0); + maybe_convert_to_fungible_store(bob_addr); + assert!(!coin_store_exists(bob_addr), 0); + register(bob); + assert!(!coin_store_exists(bob_addr), 0); + + move_to(account, FakeMoneyCapabilities { + burn_cap, + freeze_cap, + mint_cap, + }); + } + + #[test(account = @aptos_framework, aaron = @0xaa10)] + fun test_migration_with_existing_primary_fungible_store( + account: &signer, + ) acquires CoinConversionMap, CoinInfo, CoinStore, PairedCoinType { + account::create_account_for_test(signer::address_of(account)); + let account_addr = signer::address_of(account); + let (burn_cap, freeze_cap, mint_cap) = initialize_and_register_fake_money(account, 1, true); + + let coin = mint(100, &mint_cap); + primary_fungible_store::deposit(account_addr, coin_to_fungible_asset(coin)); + assert!(coin_balance(account_addr) == 0, 0); + assert!(balance(account_addr) == 100, 0); + let coin = withdraw(account, 50); + assert!(!migrated_primary_fungible_store_exists(account_addr, ensure_paired_metadata()), 0); + maybe_convert_to_fungible_store(account_addr); + assert!(migrated_primary_fungible_store_exists(account_addr, ensure_paired_metadata()), 0); + deposit(account_addr, coin); + assert!(coin_balance(account_addr) == 0, 0); + assert!(balance(account_addr) == 100, 0); + + move_to(account, FakeMoneyCapabilities { + burn_cap, + freeze_cap, + mint_cap, + }); + } } diff --git a/aptos-move/framework/aptos-framework/sources/coin.spec.move b/aptos-move/framework/aptos-framework/sources/coin.spec.move index d477dd1f3fec8..2564bc0daa8c6 100644 --- a/aptos-move/framework/aptos-framework/sources/coin.spec.move +++ b/aptos-move/framework/aptos-framework/sources/coin.spec.move @@ -63,16 +63,15 @@ spec aptos_framework::coin { global supply: num; global aggregate_supply: num; apply TotalSupplyTracked to * except - initialize, initialize_internal, initialize_with_parallelizable_supply; - /// [high-level-req-4] - /// [high-level-req-9] - apply TotalSupplyNoChange to * except mint, - burn, burn_from, initialize, initialize_internal, initialize_with_parallelizable_supply; + initialize, initialize_internal, initialize_with_parallelizable_supply; + // TODO(fa_migration) + // apply TotalSupplyNoChange to * except mint, + // burn, burn_from, initialize, initialize_internal, initialize_with_parallelizable_supply; } spec fun spec_fun_supply_tracked(val: u64, supply: Option): bool { option::spec_is_some(supply) ==> val == optional_aggregator::optional_aggregator_value - (option::spec_borrow(supply)) + (option::spec_borrow(supply)) } spec schema TotalSupplyTracked { @@ -103,6 +102,11 @@ spec aptos_framework::coin { spec mint { let addr = type_info::type_of().account_address; modifies global>(addr); + } + + spec mint_internal { + let addr = type_info::type_of().account_address; + modifies global>(addr); aborts_if (amount != 0) && !exists>(addr); ensures supply == old(supply) + amount; ensures result.value == amount; @@ -136,7 +140,8 @@ spec aptos_framework::coin { } spec balance(owner: address): u64 { - /// [high-level-req-6.1] + // TODO(fa_migration) + pragma verify = false; aborts_if !exists>(owner); ensures result == global>(owner).coin.value; } @@ -147,8 +152,7 @@ spec aptos_framework::coin { } spec is_account_registered(account_addr: address): bool { - /// [high-level-req-5] - /// [high-level-req-7.2] + pragma aborts_if_is_partial; aborts_if false; } @@ -156,20 +160,45 @@ spec aptos_framework::coin { global>(type_info::type_of().account_address).supply } + spec fun spec_paired_metadata(): Option> { + if (exists(@aptos_framework)) { + let map = global(@aptos_framework).coin_to_fungible_asset_map; + if (table::spec_contains(map, type_info::type_of())) { + let metadata = table::spec_get(map, type_info::type_of()); + option::spec_some(metadata) + } else { + option::spec_none() + } + } else { + option::spec_none() + } + } + + spec fun spec_is_account_registered(account_addr: address): bool { + let paired_metadata_opt = spec_paired_metadata(); + exists>(account_addr) || (option::spec_is_some( + paired_metadata_opt + ) && primary_fungible_store::spec_primary_store_exists(account_addr, option::spec_borrow(paired_metadata_opt))) + } + spec schema CoinSubAbortsIf { use aptos_framework::optional_aggregator; amount: u64; - let addr = type_info::type_of().account_address; + let addr = type_info::type_of().account_address; let maybe_supply = global>(addr).supply; - include (option::is_some(maybe_supply)) ==> optional_aggregator::SubAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount }; + include (option::is_some( + maybe_supply + )) ==> optional_aggregator::SubAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount }; } spec schema CoinAddAbortsIf { use aptos_framework::optional_aggregator; amount: u64; - let addr = type_info::type_of().account_address; + let addr = type_info::type_of().account_address; let maybe_supply = global>(addr).supply; - include (option::is_some(maybe_supply)) ==> optional_aggregator::AddAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount }; + include (option::is_some( + maybe_supply + )) ==> optional_aggregator::AddAbortsIf { optional_aggregator: option::borrow(maybe_supply), value: amount }; } spec schema AbortsIfNotExistCoinInfo { @@ -192,6 +221,11 @@ spec aptos_framework::coin { } spec supply(): Option { + // TODO(fa_migration) + pragma verify = false; + } + + spec coin_supply(): Option { let coin_addr = type_info::type_of().account_address; /// [high-level-req-7.5] aborts_if !exists>(coin_addr); @@ -207,10 +241,12 @@ spec aptos_framework::coin { } spec burn( - coin: Coin, - _cap: &BurnCapability, + coin: Coin, + _cap: &BurnCapability, ) { - let addr = type_info::type_of().account_address; + // TODO(fa_migration) + pragma verify = false; + let addr = type_info::type_of().account_address; modifies global>(addr); include AbortsIfNotExistCoinInfo; aborts_if coin.value == 0; @@ -218,11 +254,20 @@ spec aptos_framework::coin { ensures supply == old(supply) - coin.value; } + spec burn_internal(coin: Coin): u64 { + // TODO(fa_migration) + pragma verify = false; + let addr = type_info::type_of().account_address; + modifies global>(addr); + } + spec burn_from( - account_addr: address, - amount: u64, - burn_cap: &BurnCapability, + account_addr: address, + amount: u64, + burn_cap: &BurnCapability, ) { + // TODO(fa_migration) + pragma verify = false; let addr = type_info::type_of().account_address; let coin_store = global>(account_addr); let post post_coin_store = global>(account_addr); @@ -257,10 +302,33 @@ spec aptos_framework::coin { /// `account_addr` is not frozen. spec deposit(account_addr: address, coin: Coin) { + // TODO(fa_migration) + pragma verify = false; modifies global>(account_addr); /// [high-level-req-8.3] include DepositAbortsIf; - ensures global>(account_addr).coin.value == old(global>(account_addr)).coin.value + coin.value; + ensures global>(account_addr).coin.value == old( + global>(account_addr) + ).coin.value + coin.value; + } + + spec coin_to_fungible_asset(coin: Coin): FungibleAsset { + // TODO(fa_migration) + pragma verify = false; + let addr = type_info::type_of().account_address; + modifies global>(addr); + } + + spec fungible_asset_to_coin(fungible_asset: FungibleAsset): Coin { + // TODO(fa_migration) + pragma verify = false; + } + + spec maybe_convert_to_fungible_store(account: address) { + // TODO(fa_migration) + pragma verify = false; + modifies global>(account); + modifies global>(account); } spec schema DepositAbortsIf { @@ -271,9 +339,13 @@ spec aptos_framework::coin { } spec force_deposit(account_addr: address, coin: Coin) { + // TODO(fa_migration) + pragma verify = false; modifies global>(account_addr); aborts_if !exists>(account_addr); - ensures global>(account_addr).coin.value == old(global>(account_addr)).coin.value + coin.value; + ensures global>(account_addr).coin.value == old( + global>(account_addr) + ).coin.value + coin.value; } /// The value of `zero_coin` must be 0. @@ -293,10 +365,12 @@ spec aptos_framework::coin { } spec freeze_coin_store( - account_addr: address, - _freeze_cap: &FreezeCapability, + account_addr: address, + _freeze_cap: &FreezeCapability, ) { - pragma opaque; + // TODO(fa_migration) + pragma verify = false; + // pragma opaque; modifies global>(account_addr); /// [high-level-req-6.3] aborts_if !exists>(account_addr); @@ -305,10 +379,12 @@ spec aptos_framework::coin { } spec unfreeze_coin_store( - account_addr: address, - _freeze_cap: &FreezeCapability, + account_addr: address, + _freeze_cap: &FreezeCapability, ) { - pragma opaque; + // TODO(fa_migration) + pragma verify = false; + // pragma opaque; modifies global>(account_addr); /// [high-level-req-6.4] aborts_if !exists>(account_addr); @@ -358,17 +434,17 @@ spec aptos_framework::coin { // `account` must be `@aptos_framework`. spec initialize_with_parallelizable_supply( - account: &signer, - name: string::String, - symbol: string::String, - decimals: u8, - monitor_supply: bool, + account: &signer, + name: string::String, + symbol: string::String, + decimals: u8, + monitor_supply: bool, ): (BurnCapability, FreezeCapability, MintCapability) { use aptos_framework::aggregator_factory; let addr = signer::address_of(account); aborts_if addr != @aptos_framework; aborts_if monitor_supply && !exists(@aptos_framework); - include InitializeInternalSchema{ + include InitializeInternalSchema { name: name.bytes, symbol: symbol.bytes }; @@ -390,14 +466,14 @@ spec aptos_framework::coin { } spec initialize_internal( - account: &signer, - name: string::String, - symbol: string::String, - decimals: u8, - monitor_supply: bool, - parallelizable: bool, + account: &signer, + name: string::String, + symbol: string::String, + decimals: u8, + monitor_supply: bool, + parallelizable: bool, ): (BurnCapability, FreezeCapability, MintCapability) { - include InitializeInternalSchema{ + include InitializeInternalSchema { name: name.bytes, symbol: symbol.bytes }; @@ -433,24 +509,27 @@ spec aptos_framework::coin { /// An account can only be registered once. /// Updating `Account.guid_creation_num` will not overflow. spec register(account: &signer) { - let account_addr = signer::address_of(account); - let acc = global(account_addr); - aborts_if !exists>(account_addr) && acc.guid_creation_num + 2 >= account::MAX_GUID_CREATION_NUM; - aborts_if !exists>(account_addr) && acc.guid_creation_num + 2 > MAX_U64; - /// [high-level-req-5] - aborts_if !exists>(account_addr) && !exists(account_addr); - aborts_if !exists>(account_addr) && !type_info::spec_is_struct(); - ensures exists>(account_addr); + // TODO(fa_migration) + pragma verify = false; + // let account_addr = signer::address_of(account); + // let acc = global(account_addr); + // aborts_if !exists>(account_addr) && acc.guid_creation_num + 2 >= account::MAX_GUID_CREATION_NUM; + // aborts_if !exists>(account_addr) && acc.guid_creation_num + 2 > MAX_U64; + // aborts_if !exists>(account_addr) && !exists(account_addr); + // aborts_if !exists>(account_addr) && !type_info::spec_is_struct(); + // ensures exists>(account_addr); } /// `from` and `to` account not frozen. /// `from` and `to` not the same address. /// `from` account sufficient balance. spec transfer( - from: &signer, - to: address, - amount: u64, + from: &signer, + to: address, + amount: u64, ) { + // TODO(fa_migration) + pragma verify = false; let account_addr_from = signer::address_of(from); let coin_store_from = global>(account_addr_from); let post coin_store_post_from = global>(account_addr_from); @@ -466,16 +545,18 @@ spec aptos_framework::coin { aborts_if coin_store_from.coin.value < amount; ensures account_addr_from != to ==> coin_store_post_from.coin.value == - coin_store_from.coin.value - amount; + coin_store_from.coin.value - amount; ensures account_addr_from != to ==> coin_store_post_to.coin.value == coin_store_to.coin.value + amount; ensures account_addr_from == to ==> coin_store_post_from.coin.value == coin_store_from.coin.value; } /// Account is not frozen and sufficient balance. spec withdraw( - account: &signer, - amount: u64, + account: &signer, + amount: u64, ): Coin { + // TODO(fa_migration) + pragma verify = false; include WithdrawAbortsIf; modifies global>(account_addr); let account_addr = signer::address_of(account); @@ -483,7 +564,7 @@ spec aptos_framework::coin { let balance = coin_store.coin.value; let post coin_post = global>(account_addr).coin.value; ensures coin_post == balance - amount; - ensures result == Coin{value: amount}; + ensures result == Coin { value: amount }; } spec schema WithdrawAbortsIf { account: &signer; @@ -499,7 +580,7 @@ spec aptos_framework::coin { } spec initialize_aggregatable_coin(aptos_framework: &signer): AggregatableCoin { - include system_addresses::AbortsIfNotAptosFramework{account: aptos_framework}; + include system_addresses::AbortsIfNotAptosFramework { account: aptos_framework }; include aggregator_factory::CreateAggregatorInternalAbortsIf; } @@ -520,10 +601,12 @@ spec aptos_framework::coin { + coin.value > aggregator::spec_get_limit(aggr); aborts_if aggregator::spec_aggregator_get_val(aggr) + coin.value > MAX_U128; - ensures aggregator::spec_aggregator_get_val(aggr)+ coin.value == aggregator::spec_aggregator_get_val(p_aggr); + ensures aggregator::spec_aggregator_get_val(aggr) + coin.value == aggregator::spec_aggregator_get_val(p_aggr); } spec collect_into_aggregatable_coin(account_addr: address, amount: u64, dst_coin: &mut AggregatableCoin) { + // TODO(fa_migration) + pragma verify = false; let aggr = dst_coin.value; let post p_aggr = dst_coin.value; let coin_store = global>(account_addr); @@ -534,7 +617,7 @@ spec aptos_framework::coin { + amount > aggregator::spec_get_limit(aggr); aborts_if amount > 0 && aggregator::spec_aggregator_get_val(aggr) + amount > MAX_U128; - ensures aggregator::spec_aggregator_get_val(aggr)+ amount == aggregator::spec_aggregator_get_val(p_aggr); + ensures aggregator::spec_aggregator_get_val(aggr) + amount == aggregator::spec_aggregator_get_val(p_aggr); ensures coin_store.coin.value - amount == p_coin_store.coin.value; } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/config_buffer.move b/aptos-move/framework/aptos-framework/sources/configs/config_buffer.move index 26dfcd602a26e..bbcba84263540 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/config_buffer.move +++ b/aptos-move/framework/aptos-framework/sources/configs/config_buffer.move @@ -23,6 +23,8 @@ module aptos_framework::config_buffer { friend aptos_framework::gas_schedule; friend aptos_framework::jwks; friend aptos_framework::jwk_consensus_config; + friend aptos_framework::keyless_account; + friend aptos_framework::randomness_api_v0_config; friend aptos_framework::randomness_config; friend aptos_framework::randomness_config_seqnum; friend aptos_framework::version; diff --git a/aptos-move/framework/aptos-framework/sources/configs/config_buffer.spec.move b/aptos-move/framework/aptos-framework/sources/configs/config_buffer.spec.move index 41b6aff976386..26e80269eecf5 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/config_buffer.spec.move +++ b/aptos-move/framework/aptos-framework/sources/configs/config_buffer.spec.move @@ -48,7 +48,6 @@ spec aptos_framework::config_buffer { spec schema OnNewEpochAbortsIf { use aptos_std::type_info; let type_name = type_info::type_name(); - aborts_if spec_fun_does_exist(type_name) && !exists(@aptos_framework); let configs = global(@aptos_framework); // TODO(#12015) include spec_fun_does_exist(type_name) ==> any::UnpackAbortsIf { @@ -59,7 +58,6 @@ spec aptos_framework::config_buffer { spec schema OnNewEpochRequirement { use aptos_std::type_info; let type_name = type_info::type_name(); - requires spec_fun_does_exist(type_name) ==> exists(@aptos_framework); let configs = global(@aptos_framework); // TODO(#12015) include spec_fun_does_exist(type_name) ==> any::UnpackRequirement { diff --git a/aptos-move/framework/aptos-framework/sources/configs/consensus_config.move b/aptos-move/framework/aptos-framework/sources/configs/consensus_config.move index 1ea04b0218c55..e81049477c8c9 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/consensus_config.move +++ b/aptos-move/framework/aptos-framework/sources/configs/consensus_config.move @@ -56,9 +56,15 @@ module aptos_framework::consensus_config { } /// Only used in reconfigurations to apply the pending `ConsensusConfig`, if there is any. - public(friend) fun on_new_epoch() acquires ConsensusConfig { + public(friend) fun on_new_epoch(framework: &signer) acquires ConsensusConfig { + system_addresses::assert_aptos_framework(framework); if (config_buffer::does_exist()) { - *borrow_global_mut(@aptos_framework) = config_buffer::extract(); + let new_config = config_buffer::extract(); + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = new_config; + } else { + move_to(framework, new_config); + }; } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/consensus_config.spec.move b/aptos-move/framework/aptos-framework/sources/configs/consensus_config.spec.move index d1952e56c5470..f0360989f47a6 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/consensus_config.spec.move +++ b/aptos-move/framework/aptos-framework/sources/configs/consensus_config.spec.move @@ -75,8 +75,10 @@ spec aptos_framework::consensus_config { include config_buffer::SetForNextEpochAbortsIf; } - spec on_new_epoch() { - include config_buffer::OnNewEpochAbortsIf; + spec on_new_epoch(framework: &signer) { + requires @aptos_framework == std::signer::address_of(framework); + include config_buffer::OnNewEpochRequirement; + aborts_if false; } spec validator_txn_enabled(): bool { diff --git a/aptos-move/framework/aptos-framework/sources/configs/execution_config.move b/aptos-move/framework/aptos-framework/sources/configs/execution_config.move index 29e3c3f80c6cf..6322a6cfe1420 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/execution_config.move +++ b/aptos-move/framework/aptos-framework/sources/configs/execution_config.move @@ -52,10 +52,15 @@ module aptos_framework::execution_config { } /// Only used in reconfigurations to apply the pending `ExecutionConfig`, if there is any. - public(friend) fun on_new_epoch() acquires ExecutionConfig { + public(friend) fun on_new_epoch(framework: &signer) acquires ExecutionConfig { + system_addresses::assert_aptos_framework(framework); if (config_buffer::does_exist()) { let config = config_buffer::extract(); - *borrow_global_mut(@aptos_framework) = config; + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = config; + } else { + move_to(framework, config); + }; } } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/execution_config.spec.move b/aptos-move/framework/aptos-framework/sources/configs/execution_config.spec.move index 44531b0796f07..4b04d757f2fdb 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/execution_config.spec.move +++ b/aptos-move/framework/aptos-framework/sources/configs/execution_config.spec.move @@ -36,7 +36,9 @@ spec aptos_framework::execution_config { include config_buffer::SetForNextEpochAbortsIf; } - spec on_new_epoch() { - include config_buffer::OnNewEpochAbortsIf; + spec on_new_epoch(framework: &signer) { + requires @aptos_framework == std::signer::address_of(framework); + include config_buffer::OnNewEpochRequirement; + aborts_if false; } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/gas_schedule.move b/aptos-move/framework/aptos-framework/sources/configs/gas_schedule.move index 1fa6bf53f6c68..87d6cf4c72adc 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/gas_schedule.move +++ b/aptos-move/framework/aptos-framework/sources/configs/gas_schedule.move @@ -100,11 +100,15 @@ module aptos_framework::gas_schedule { } /// Only used in reconfigurations to apply the pending `GasScheduleV2`, if there is any. - public(friend) fun on_new_epoch() acquires GasScheduleV2 { + public(friend) fun on_new_epoch(framework: &signer) acquires GasScheduleV2 { + system_addresses::assert_aptos_framework(framework); if (config_buffer::does_exist()) { - let new_gas_schedule: GasScheduleV2 = config_buffer::extract(); - let gas_schedule = borrow_global_mut(@aptos_framework); - *gas_schedule = new_gas_schedule; + let new_gas_schedule = config_buffer::extract(); + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = new_gas_schedule; + } else { + move_to(framework, new_gas_schedule); + } } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/gas_schedule.spec.move b/aptos-move/framework/aptos-framework/sources/configs/gas_schedule.spec.move index 2f1b596b3bd73..1d59784d22504 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/gas_schedule.spec.move +++ b/aptos-move/framework/aptos-framework/sources/configs/gas_schedule.spec.move @@ -107,8 +107,10 @@ spec aptos_framework::gas_schedule { aborts_if exists(@aptos_framework) && new_gas_schedule.feature_version < cur_gas_schedule.feature_version; } - spec on_new_epoch() { - include config_buffer::OnNewEpochAbortsIf; + spec on_new_epoch(framework: &signer) { + requires @aptos_framework == std::signer::address_of(framework); + include config_buffer::OnNewEpochRequirement; + aborts_if false; } spec set_storage_gas_config(aptos_framework: &signer, config: storage_gas::StorageGasConfig) { diff --git a/aptos-move/framework/aptos-framework/sources/configs/jwk_consensus_config.move b/aptos-move/framework/aptos-framework/sources/configs/jwk_consensus_config.move index 2d9c4a917ae26..bba0276e785d6 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/jwk_consensus_config.move +++ b/aptos-move/framework/aptos-framework/sources/configs/jwk_consensus_config.move @@ -65,10 +65,15 @@ module aptos_framework::jwk_consensus_config { } /// Only used in reconfigurations to apply the pending `JWKConsensusConfig`, if there is any. - public(friend) fun on_new_epoch() acquires JWKConsensusConfig { + public(friend) fun on_new_epoch(framework: &signer) acquires JWKConsensusConfig { + system_addresses::assert_aptos_framework(framework); if (config_buffer::does_exist()) { let new_config = config_buffer::extract(); - borrow_global_mut(@aptos_framework).variant = new_config.variant; + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = new_config; + } else { + move_to(framework, new_config); + }; } } @@ -122,11 +127,11 @@ module aptos_framework::jwk_consensus_config { new_oidc_provider(utf8(b"Alice"), utf8(b"https://alice.io")), ]); set_for_next_epoch(&framework, config); - on_new_epoch(); + on_new_epoch(&framework); assert!(enabled(), 1); set_for_next_epoch(&framework, new_off()); - on_new_epoch(); + on_new_epoch(&framework); assert!(!enabled(), 2) } diff --git a/aptos-move/framework/aptos-framework/sources/configs/jwk_consensus_config.spec.move b/aptos-move/framework/aptos-framework/sources/configs/jwk_consensus_config.spec.move index 581b5d5ab8ac5..087c5f3baf36a 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/jwk_consensus_config.spec.move +++ b/aptos-move/framework/aptos-framework/sources/configs/jwk_consensus_config.spec.move @@ -1,8 +1,7 @@ spec aptos_framework::jwk_consensus_config { - - spec module { - use aptos_framework::chain_status; - invariant [suspendable] chain_status::is_operating() ==> exists(@aptos_framework); + spec on_new_epoch(framework: &signer) { + requires @aptos_framework == std::signer::address_of(framework); + include config_buffer::OnNewEpochRequirement; + aborts_if false; } - } diff --git a/aptos-move/framework/aptos-framework/sources/configs/randomness_api_v0_config.move b/aptos-move/framework/aptos-framework/sources/configs/randomness_api_v0_config.move new file mode 100644 index 0000000000000..5a609fc8901a3 --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/configs/randomness_api_v0_config.move @@ -0,0 +1,37 @@ +module aptos_framework::randomness_api_v0_config { + use std::option::Option; + use aptos_framework::chain_status; + use aptos_framework::config_buffer; + use aptos_framework::system_addresses; + friend aptos_framework::reconfiguration_with_dkg; + + struct RequiredGasDeposit has key, drop, store { + gas_amount: Option, + } + + /// Only used in genesis. + fun initialize(framework: &signer, required_amount: RequiredGasDeposit) { + system_addresses::assert_aptos_framework(framework); + chain_status::assert_genesis(); + move_to(framework, required_amount) + } + + /// This can be called by on-chain governance to update `RequiredGasDeposit` for the next epoch. + public fun set_for_next_epoch(framework: &signer, gas_amount: Option) { + system_addresses::assert_aptos_framework(framework); + config_buffer::upsert(RequiredGasDeposit { gas_amount }); + } + + /// Only used in reconfigurations to apply the pending `RequiredGasDeposit`, if there is any. + public fun on_new_epoch(framework: &signer) acquires RequiredGasDeposit { + system_addresses::assert_aptos_framework(framework); + if (config_buffer::does_exist()) { + let new_config = config_buffer::extract(); + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = new_config; + } else { + move_to(framework, new_config); + } + } + } +} diff --git a/aptos-move/framework/aptos-framework/sources/configs/randomness_api_v0_config.spec.move b/aptos-move/framework/aptos-framework/sources/configs/randomness_api_v0_config.spec.move new file mode 100644 index 0000000000000..048d023195a10 --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/configs/randomness_api_v0_config.spec.move @@ -0,0 +1,5 @@ +spec aptos_framework::randomness_api_v0_config { + spec module { + pragma verify = false; + } +} diff --git a/aptos-move/framework/aptos-framework/sources/configs/randomness_config.move b/aptos-move/framework/aptos-framework/sources/configs/randomness_config.move index c50ca01085213..24916393e8451 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/randomness_config.move +++ b/aptos-move/framework/aptos-framework/sources/configs/randomness_config.move @@ -56,10 +56,15 @@ module aptos_framework::randomness_config { } /// Only used in reconfigurations to apply the pending `RandomnessConfig`, if there is any. - public(friend) fun on_new_epoch() acquires RandomnessConfig { + public(friend) fun on_new_epoch(framework: &signer) acquires RandomnessConfig { + system_addresses::assert_aptos_framework(framework); if (config_buffer::does_exist()) { let new_config = config_buffer::extract(); - borrow_global_mut(@aptos_framework).variant = new_config.variant; + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = new_config; + } else { + move_to(framework, new_config); + } } } @@ -137,12 +142,12 @@ module aptos_framework::randomness_config { fixed_point64::create_from_rational(2, 3) ); set_for_next_epoch(&framework, config); - on_new_epoch(); + on_new_epoch(&framework); assert!(enabled(), 1); // Disabling. set_for_next_epoch(&framework, new_off()); - on_new_epoch(); + on_new_epoch(&framework); assert!(!enabled(), 2); } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/randomness_config.spec.move b/aptos-move/framework/aptos-framework/sources/configs/randomness_config.spec.move index e8353ca18dab7..a0f0cc35a174d 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/randomness_config.spec.move +++ b/aptos-move/framework/aptos-framework/sources/configs/randomness_config.spec.move @@ -1,9 +1,11 @@ spec aptos_framework::randomness_config { - spec module { - use aptos_framework::chain_status; - invariant [suspendable] chain_status::is_operating() ==> exists(@aptos_framework); - } spec current { aborts_if false; } + + spec on_new_epoch(framework: &signer) { + requires @aptos_framework == std::signer::address_of(framework); + include config_buffer::OnNewEpochRequirement; + aborts_if false; + } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/randomness_config_seqnum.move b/aptos-move/framework/aptos-framework/sources/configs/randomness_config_seqnum.move index 24980abc41b01..174b7fdda8388 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/randomness_config_seqnum.move +++ b/aptos-move/framework/aptos-framework/sources/configs/randomness_config_seqnum.move @@ -35,10 +35,15 @@ module aptos_framework::randomness_config_seqnum { } /// Only used in reconfigurations to apply the pending `RandomnessConfig`, if there is any. - public(friend) fun on_new_epoch() acquires RandomnessConfigSeqNum { + public(friend) fun on_new_epoch(framework: &signer) acquires RandomnessConfigSeqNum { + system_addresses::assert_aptos_framework(framework); if (config_buffer::does_exist()) { let new_config = config_buffer::extract(); - borrow_global_mut(@aptos_framework).seq_num = new_config.seq_num; + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = new_config; + } else { + move_to(framework, new_config); + } } } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/randomness_config_seqnum.spec.move b/aptos-move/framework/aptos-framework/sources/configs/randomness_config_seqnum.spec.move new file mode 100644 index 0000000000000..8a043d4fab0fd --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/configs/randomness_config_seqnum.spec.move @@ -0,0 +1,7 @@ +spec aptos_framework::randomness_config_seqnum { + spec on_new_epoch(framework: &signer) { + requires @aptos_framework == std::signer::address_of(framework); + include config_buffer::OnNewEpochRequirement; + aborts_if false; + } +} diff --git a/aptos-move/framework/aptos-framework/sources/configs/version.move b/aptos-move/framework/aptos-framework/sources/configs/version.move index eb01cac9639b9..fa90eb44ea8a0 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/version.move +++ b/aptos-move/framework/aptos-framework/sources/configs/version.move @@ -64,9 +64,15 @@ module aptos_framework::version { } /// Only used in reconfigurations to apply the pending `Version`, if there is any. - public(friend) fun on_new_epoch() acquires Version { + public(friend) fun on_new_epoch(framework: &signer) acquires Version { + system_addresses::assert_aptos_framework(framework); if (config_buffer::does_exist()) { - *borrow_global_mut(@aptos_framework) = config_buffer::extract(); + let new_value = config_buffer::extract(); + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = new_value; + } else { + move_to(framework, new_value); + } } } diff --git a/aptos-move/framework/aptos-framework/sources/configs/version.spec.move b/aptos-move/framework/aptos-framework/sources/configs/version.spec.move index e5975d0f04bc7..5ce2685d1158b 100644 --- a/aptos-move/framework/aptos-framework/sources/configs/version.spec.move +++ b/aptos-move/framework/aptos-framework/sources/configs/version.spec.move @@ -73,8 +73,10 @@ spec aptos_framework::version { aborts_if !exists(@aptos_framework); } - spec on_new_epoch() { - include config_buffer::OnNewEpochAbortsIf; + spec on_new_epoch(framework: &signer) { + requires @aptos_framework == std::signer::address_of(framework); + include config_buffer::OnNewEpochRequirement; + aborts_if false; } /// This module turns on `aborts_if_is_strict`, so need to add spec for test function `initialize_for_test`. diff --git a/aptos-move/framework/aptos-framework/sources/create_signer.move b/aptos-move/framework/aptos-framework/sources/create_signer.move index 154c68b32ac54..7aa57733f62aa 100644 --- a/aptos-move/framework/aptos-framework/sources/create_signer.move +++ b/aptos-move/framework/aptos-framework/sources/create_signer.move @@ -11,6 +11,7 @@ module aptos_framework::create_signer { friend aptos_framework::account; friend aptos_framework::aptos_account; + friend aptos_framework::coin; friend aptos_framework::genesis; friend aptos_framework::multisig_account; friend aptos_framework::object; diff --git a/aptos-move/framework/aptos-framework/sources/delegation_pool.move b/aptos-move/framework/aptos-framework/sources/delegation_pool.move index 25c61461e2ef7..b6dc4b21823c8 100644 --- a/aptos-move/framework/aptos-framework/sources/delegation_pool.move +++ b/aptos-move/framework/aptos-framework/sources/delegation_pool.move @@ -346,6 +346,7 @@ module aptos_framework::delegation_pool { allowlist: SmartTable, } + #[event] struct AddStakeEvent has drop, store { pool_address: address, delegator_address: address, @@ -353,24 +354,28 @@ module aptos_framework::delegation_pool { add_stake_fee: u64, } + #[event] struct ReactivateStakeEvent has drop, store { pool_address: address, delegator_address: address, amount_reactivated: u64, } + #[event] struct UnlockStakeEvent has drop, store { pool_address: address, delegator_address: address, amount_unlocked: u64, } + #[event] struct WithdrawStakeEvent has drop, store { pool_address: address, delegator_address: address, amount_withdrawn: u64, } + #[event] struct DistributeCommissionEvent has drop, store { pool_address: address, operator: address, @@ -387,6 +392,7 @@ module aptos_framework::delegation_pool { commission_pending_inactive: u64, } + #[event] struct VoteEvent has drop, store { voter: address, proposal_id: u64, @@ -395,12 +401,14 @@ module aptos_framework::delegation_pool { should_pass: bool, } + #[event] struct CreateProposalEvent has drop, store { proposal_id: u64, voter: address, delegation_pool: address, } + #[event] struct DelegateVotingPowerEvent has drop, store { pool_address: address, delegator: address, @@ -490,7 +498,9 @@ module aptos_framework::delegation_pool { #[view] /// Return the operator commission percentage set on the delegation pool `pool_address`. - public fun operator_commission_percentage(pool_address: address): u64 acquires DelegationPool, NextCommissionPercentage { + public fun operator_commission_percentage( + pool_address: address + ): u64 acquires DelegationPool, NextCommissionPercentage { assert_delegation_pool_exists(pool_address); if (is_next_commission_percentage_effective(pool_address)) { operator_commission_percentage_next_lockup_cycle(pool_address) @@ -501,7 +511,9 @@ module aptos_framework::delegation_pool { #[view] /// Return the operator commission percentage for the next lockup cycle. - public fun operator_commission_percentage_next_lockup_cycle(pool_address: address): u64 acquires DelegationPool, NextCommissionPercentage { + public fun operator_commission_percentage_next_lockup_cycle( + pool_address: address + ): u64 acquires DelegationPool, NextCommissionPercentage { assert_delegation_pool_exists(pool_address); if (exists(pool_address)) { borrow_global(pool_address).commission_percentage_next_lockup_cycle @@ -568,7 +580,10 @@ module aptos_framework::delegation_pool { #[view] /// Return total stake owned by `delegator_address` within delegation pool `pool_address` /// in each of its individual states: (`active`,`inactive`,`pending_inactive`) - public fun get_stake(pool_address: address, delegator_address: address): (u64, u64, u64) acquires DelegationPool, BeneficiaryForOperator { + public fun get_stake( + pool_address: address, + delegator_address: address + ): (u64, u64, u64) acquires DelegationPool, BeneficiaryForOperator { assert_delegation_pool_exists(pool_address); let pool = borrow_global(pool_address); let ( @@ -630,7 +645,10 @@ module aptos_framework::delegation_pool { /// To mitigate this, some of the added stake is extracted and fed back into the pool as placeholder /// for the rewards the remaining stake would have earned if active: /// extracted-fee = (amount - extracted-fee) * reward-rate% * (100% - operator-commission%) - public fun get_add_stake_fee(pool_address: address, amount: u64): u64 acquires DelegationPool, NextCommissionPercentage { + public fun get_add_stake_fee( + pool_address: address, + amount: u64 + ): u64 acquires DelegationPool, NextCommissionPercentage { if (stake::is_current_epoch_validator(pool_address)) { let (rewards_rate, rewards_rate_denominator) = staking_config::get_reward_rate(&staking_config::get()); if (rewards_rate_denominator > 0) { @@ -655,7 +673,10 @@ module aptos_framework::delegation_pool { #[view] /// Return the total voting power of a delegator in a delegation pool. This function syncs DelegationPool to the /// latest state. - public fun calculate_and_update_voter_total_voting_power(pool_address: address, voter: address): u64 acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { + public fun calculate_and_update_voter_total_voting_power( + pool_address: address, + voter: address + ): u64 acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { assert_partial_governance_voting_enabled(pool_address); // Delegation pool need to be synced to explain rewards(which could change the coin amount) and // commission(which could cause share transfer). @@ -669,7 +690,11 @@ module aptos_framework::delegation_pool { #[view] /// Return the remaining voting power of a delegator in a delegation pool on a proposal. This function syncs DelegationPool to the /// latest state. - public fun calculate_and_update_remaining_voting_power(pool_address: address, voter_address: address, proposal_id: u64): u64 acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { + public fun calculate_and_update_remaining_voting_power( + pool_address: address, + voter_address: address, + proposal_id: u64 + ): u64 acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { assert_partial_governance_voting_enabled(pool_address); // If the whole stake pool has no voting power(e.g. it has already voted before partial // governance voting flag is enabled), the delegator also has no voting power. @@ -685,7 +710,10 @@ module aptos_framework::delegation_pool { #[view] /// Return the latest delegated voter of a delegator in a delegation pool. This function syncs DelegationPool to the /// latest state. - public fun calculate_and_update_delegator_voter(pool_address: address, delegator_address: address): address acquires DelegationPool, GovernanceRecords { + public fun calculate_and_update_delegator_voter( + pool_address: address, + delegator_address: address + ): address acquires DelegationPool, GovernanceRecords { assert_partial_governance_voting_enabled(pool_address); calculate_and_update_delegator_voter_internal( borrow_global(pool_address), @@ -793,7 +821,8 @@ module aptos_framework::delegation_pool { move_to(owner, DelegationPoolOwnership { pool_address }); // All delegation pool enable partial governance voting by default once the feature flag is enabled. - if (features::partial_governance_voting_enabled() && features::delegation_pool_partial_governance_voting_enabled()) { + if (features::partial_governance_voting_enabled( + ) && features::delegation_pool_partial_governance_voting_enabled()) { enable_partial_governance_voting(pool_address); } } @@ -814,7 +843,10 @@ module aptos_framework::delegation_pool { pool_address: address, ) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { assert!(features::partial_governance_voting_enabled(), error::invalid_state(EDISABLED_FUNCTION)); - assert!(features::delegation_pool_partial_governance_voting_enabled(), error::invalid_state(EDISABLED_FUNCTION)); + assert!( + features::delegation_pool_partial_governance_voting_enabled(), + error::invalid_state(EDISABLED_FUNCTION) + ); assert_delegation_pool_exists(pool_address); // synchronize delegation and stake pools before any user operation. synchronize_delegation_pool(pool_address); @@ -841,13 +873,23 @@ module aptos_framework::delegation_pool { /// 2. The delegation pool's lockup period ends after the voting period of the proposal. /// 3. The voter still has spare voting power on this proposal. /// 4. The delegation pool never votes on the proposal before enabling partial governance voting. - public entry fun vote(voter: &signer, pool_address: address, proposal_id: u64, voting_power: u64, should_pass: bool) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { + public entry fun vote( + voter: &signer, + pool_address: address, + proposal_id: u64, + voting_power: u64, + should_pass: bool + ) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { assert_partial_governance_voting_enabled(pool_address); // synchronize delegation and stake pools before any user operation. synchronize_delegation_pool(pool_address); let voter_address = signer::address_of(voter); - let remaining_voting_power = calculate_and_update_remaining_voting_power(pool_address, voter_address, proposal_id); + let remaining_voting_power = calculate_and_update_remaining_voting_power( + pool_address, + voter_address, + proposal_id + ); if (voting_power > remaining_voting_power) { voting_power = remaining_voting_power; }; @@ -862,6 +904,18 @@ module aptos_framework::delegation_pool { let pool_signer = retrieve_stake_pool_owner(borrow_global(pool_address)); aptos_governance::partial_vote(&pool_signer, pool_address, proposal_id, voting_power, should_pass); + if (features::module_event_migration_enabled()) { + event::emit( + VoteEvent { + voter: voter_address, + proposal_id, + delegation_pool: pool_address, + num_votes: voting_power, + should_pass, + } + ); + }; + event::emit_event( &mut governance_records.vote_events, VoteEvent { @@ -908,6 +962,17 @@ module aptos_framework::delegation_pool { ); let governance_records = borrow_global_mut(pool_address); + + if (features::module_event_migration_enabled()) { + event::emit( + CreateProposalEvent { + proposal_id, + voter: voter_addr, + delegation_pool: pool_address, + } + ); + }; + event::emit_event( &mut governance_records.create_proposal_events, CreateProposalEvent { @@ -941,7 +1006,10 @@ module aptos_framework::delegation_pool { fun assert_partial_governance_voting_enabled(pool_address: address) { assert_delegation_pool_exists(pool_address); - assert!(partial_governance_voting_enabled(pool_address), error::invalid_state(EPARTIAL_GOVERNANCE_VOTING_NOT_ENABLED)); + assert!( + partial_governance_voting_enabled(pool_address), + error::invalid_state(EPARTIAL_GOVERNANCE_VOTING_NOT_ENABLED) + ); } fun assert_allowlisting_enabled(pool_address: address) { @@ -1041,7 +1109,11 @@ module aptos_framework::delegation_pool { } /// Borrow the mutable used voting power of a voter on a proposal. - inline fun borrow_mut_used_voting_power(governance_records: &mut GovernanceRecords, voter: address, proposal_id: u64): &mut u64 { + inline fun borrow_mut_used_voting_power( + governance_records: &mut GovernanceRecords, + voter: address, + proposal_id: u64 + ): &mut u64 { let votes = &mut governance_records.votes; let key = VotingRecordKey { proposal_id, @@ -1053,7 +1125,7 @@ module aptos_framework::delegation_pool { /// Update VoteDelegation of a delegator to up-to-date then borrow_mut it. fun update_and_borrow_mut_delegator_vote_delegation( pool: &DelegationPool, - governance_records :&mut GovernanceRecords, + governance_records: &mut GovernanceRecords, delegator: address ): &mut VoteDelegation { let pool_address = get_pool_address(pool); @@ -1082,7 +1154,7 @@ module aptos_framework::delegation_pool { /// Update DelegatedVotes of a voter to up-to-date then borrow_mut it. fun update_and_borrow_mut_delegated_votes( pool: &DelegationPool, - governance_records :&mut GovernanceRecords, + governance_records: &mut GovernanceRecords, voter: address ): &mut DelegatedVotes { let pool_address = get_pool_address(pool); @@ -1129,13 +1201,21 @@ module aptos_framework::delegation_pool { } /// Update VoteDelegation of a delegator to up-to-date then return the latest voter. - fun calculate_and_update_delegator_voter_internal(pool: &DelegationPool, governance_records: &mut GovernanceRecords, delegator: address): address { + fun calculate_and_update_delegator_voter_internal( + pool: &DelegationPool, + governance_records: &mut GovernanceRecords, + delegator: address + ): address { let vote_delegation = update_and_borrow_mut_delegator_vote_delegation(pool, governance_records, delegator); vote_delegation.voter } /// Update DelegatedVotes of a voter to up-to-date then return the total voting power of this voter. - fun calculate_and_update_delegated_votes(pool: &DelegationPool, governance_records: &mut GovernanceRecords, voter: address): u64 { + fun calculate_and_update_delegated_votes( + pool: &DelegationPool, + governance_records: &mut GovernanceRecords, + voter: address + ): u64 { let delegated_votes = update_and_borrow_mut_delegated_votes(pool, governance_records, voter); calculate_total_voting_power(pool, delegated_votes) } @@ -1162,7 +1242,10 @@ module aptos_framework::delegation_pool { /// beneficiary. To ensure payment to the current beneficiary, one should first call `synchronize_delegation_pool` /// before switching the beneficiary. An operator can set one beneficiary for delegation pools, not a separate /// one for each pool. - public entry fun set_beneficiary_for_operator(operator: &signer, new_beneficiary: address) acquires BeneficiaryForOperator { + public entry fun set_beneficiary_for_operator( + operator: &signer, + new_beneficiary: address + ) acquires BeneficiaryForOperator { assert!(features::operator_beneficiary_change_enabled(), std::error::invalid_state( EOPERATOR_BENEFICIARY_CHANGE_NOT_SUPPORTED )); @@ -1234,7 +1317,10 @@ module aptos_framework::delegation_pool { new_voter: address ) acquires DelegationPoolOwnership, DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { // No one can change delegated_voter once the partial governance voting feature is enabled. - assert!(!features::delegation_pool_partial_governance_voting_enabled(), error::invalid_state(EDEPRECATED_FUNCTION)); + assert!( + !features::delegation_pool_partial_governance_voting_enabled(), + error::invalid_state(EDEPRECATED_FUNCTION) + ); let pool_address = get_owned_pool_address(signer::address_of(owner)); // synchronize delegation and stake pools before any user operation synchronize_delegation_pool(pool_address); @@ -1257,10 +1343,10 @@ module aptos_framework::delegation_pool { let delegation_pool = borrow_global(pool_address); let governance_records = borrow_global_mut(pool_address); let delegator_vote_delegation = update_and_borrow_mut_delegator_vote_delegation( - delegation_pool, - governance_records, - delegator_address - ); + delegation_pool, + governance_records, + delegator_address + ); let pending_voter: address = delegator_vote_delegation.pending_voter; // No need to update if the voter doesn't really change. @@ -1286,6 +1372,14 @@ module aptos_framework::delegation_pool { new_delegated_votes.active_shares_next_lockup + active_shares; }; + if (features::module_event_migration_enabled()) { + event::emit(DelegateVotingPowerEvent { + pool_address, + delegator: delegator_address, + voter: new_voter, + }) + }; + event::emit_event(&mut governance_records.delegate_voting_power_events, DelegateVotingPowerEvent { pool_address, delegator: delegator_address, @@ -1412,6 +1506,17 @@ module aptos_framework::delegation_pool { // in order to appreciate all shares on the active pool atomically buy_in_active_shares(pool, NULL_SHAREHOLDER, add_stake_fee); + if (features::module_event_migration_enabled()) { + event::emit( + AddStakeEvent { + pool_address, + delegator_address, + amount_added: amount, + add_stake_fee, + }, + ); + }; + event::emit_event( &mut pool.add_stake_events, AddStakeEvent { @@ -1465,6 +1570,16 @@ module aptos_framework::delegation_pool { buy_in_pending_inactive_shares(pool, delegator_address, amount); assert_min_pending_inactive_balance(pool, delegator_address); + if (features::module_event_migration_enabled()) { + event::emit( + UnlockStakeEvent { + pool_address, + delegator_address, + amount_unlocked: amount, + }, + ); + }; + event::emit_event( &mut pool.unlock_stake_events, UnlockStakeEvent { @@ -1505,6 +1620,16 @@ module aptos_framework::delegation_pool { buy_in_active_shares(pool, delegator_address, amount); assert_min_active_balance(pool, delegator_address); + if (features::module_event_migration_enabled()) { + event::emit( + ReactivateStakeEvent { + pool_address, + delegator_address, + amount_reactivated: amount, + }, + ); + }; + event::emit_event( &mut pool.reactivate_stake_events, ReactivateStakeEvent { @@ -1516,14 +1641,22 @@ module aptos_framework::delegation_pool { } /// Withdraw `amount` of owned inactive stake from the delegation pool at `pool_address`. - public entry fun withdraw(delegator: &signer, pool_address: address, amount: u64) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { + public entry fun withdraw( + delegator: &signer, + pool_address: address, + amount: u64 + ) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { assert!(amount > 0, error::invalid_argument(EWITHDRAW_ZERO_STAKE)); // synchronize delegation and stake pools before any user operation synchronize_delegation_pool(pool_address); withdraw_internal(borrow_global_mut(pool_address), signer::address_of(delegator), amount); } - fun withdraw_internal(pool: &mut DelegationPool, delegator_address: address, amount: u64) acquires GovernanceRecords { + fun withdraw_internal( + pool: &mut DelegationPool, + delegator_address: address, + amount: u64 + ) acquires GovernanceRecords { // TODO: recycle storage when a delegator fully exits the delegation pool. // short-circuit if amount to withdraw is 0 so no event is emitted if (amount == 0) { return }; @@ -1572,6 +1705,16 @@ module aptos_framework::delegation_pool { let (_, inactive, _, _) = stake::get_stake(pool_address); pool.total_coins_inactive = inactive; + if (features::module_event_migration_enabled()) { + event::emit( + WithdrawStakeEvent { + pool_address, + delegator_address, + amount_withdrawn: amount, + }, + ); + }; + event::emit_event( &mut pool.withdraw_stake_events, WithdrawStakeEvent { @@ -1621,7 +1764,7 @@ module aptos_framework::delegation_pool { pool: &mut DelegationPool, shareholder: address, coins_amount: u64, - ): u128 acquires GovernanceRecords{ + ): u128 acquires GovernanceRecords { let new_shares = pool_u64::amount_to_shares(&pool.active_shares, coins_amount); // No need to buy 0 shares. if (new_shares == 0) { return 0 }; @@ -1734,7 +1877,12 @@ module aptos_framework::delegation_pool { let pool_address = get_pool_address(pool); // Only redeem shares from the pending_inactive pool at `lockup_cycle` == current OLC. if (partial_governance_voting_enabled(pool_address) && lockup_cycle.index == pool.observed_lockup_cycle.index) { - update_governanace_records_for_redeem_pending_inactive_shares(pool, pool_address, shares_to_redeem, shareholder); + update_governanace_records_for_redeem_pending_inactive_shares( + pool, + pool_address, + shares_to_redeem, + shareholder + ); }; let inactive_shares = table::borrow_mut(&mut pool.inactive_shares, lockup_cycle); @@ -1811,7 +1959,9 @@ module aptos_framework::delegation_pool { /// Synchronize delegation and stake pools: distribute yet-undetected rewards to the corresponding internal /// shares pools, assign commission to operator and eventually prepare delegation pool for a new lockup cycle. - public entry fun synchronize_delegation_pool(pool_address: address) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { + public entry fun synchronize_delegation_pool( + pool_address: address + ) acquires DelegationPool, GovernanceRecords, BeneficiaryForOperator, NextCommissionPercentage { assert_delegation_pool_exists(pool_address); let pool = borrow_global_mut(pool_address); let ( @@ -1847,7 +1997,11 @@ module aptos_framework::delegation_pool { // reward operator its commission out of uncommitted active rewards (`add_stake` fees already excluded) buy_in_active_shares(pool, beneficiary_for_operator(stake::get_operator(pool_address)), commission_active); // reward operator its commission out of uncommitted pending_inactive rewards - buy_in_pending_inactive_shares(pool, beneficiary_for_operator(stake::get_operator(pool_address)), commission_pending_inactive); + buy_in_pending_inactive_shares( + pool, + beneficiary_for_operator(stake::get_operator(pool_address)), + commission_pending_inactive + ); event::emit_event( &mut pool.distribute_commission_events, @@ -1886,28 +2040,39 @@ module aptos_framework::delegation_pool { }; if (is_next_commission_percentage_effective(pool_address)) { - pool.operator_commission_percentage = borrow_global(pool_address).commission_percentage_next_lockup_cycle; + pool.operator_commission_percentage = borrow_global( + pool_address + ).commission_percentage_next_lockup_cycle; } } inline fun assert_and_update_proposal_used_voting_power( - governance_records: &mut GovernanceRecords, pool_address : address, proposal_id : u64, voting_power: u64 + governance_records: &mut GovernanceRecords, pool_address: address, proposal_id: u64, voting_power: u64 ) { let stake_pool_remaining_voting_power = aptos_governance::get_remaining_voting_power(pool_address, proposal_id); - let stake_pool_used_voting_power = aptos_governance::get_voting_power(pool_address) - stake_pool_remaining_voting_power; - let proposal_used_voting_power = smart_table::borrow_mut_with_default(&mut governance_records.votes_per_proposal, proposal_id, 0); + let stake_pool_used_voting_power = aptos_governance::get_voting_power( + pool_address + ) - stake_pool_remaining_voting_power; + let proposal_used_voting_power = smart_table::borrow_mut_with_default( + &mut governance_records.votes_per_proposal, + proposal_id, + 0 + ); // A edge case: Before enabling partial governance voting on a delegation pool, the delegation pool has // a voter which can vote with all voting power of this delegation pool. If the voter votes on a proposal after // partial governance voting flag is enabled, the delegation pool doesn't have enough voting power on this // proposal for all the delegators. To be fair, no one can vote on this proposal through this delegation pool. // To detect this case, check if the stake pool had used voting power not through delegation_pool module. - assert!(stake_pool_used_voting_power == *proposal_used_voting_power, error::invalid_argument(EALREADY_VOTED_BEFORE_ENABLE_PARTIAL_VOTING)); + assert!( + stake_pool_used_voting_power == *proposal_used_voting_power, + error::invalid_argument(EALREADY_VOTED_BEFORE_ENABLE_PARTIAL_VOTING) + ); *proposal_used_voting_power = *proposal_used_voting_power + voting_power; } fun update_governance_records_for_buy_in_active_shares( pool: &DelegationPool, pool_address: address, new_shares: u128, shareholder: address - ) acquires GovernanceRecords{ + ) acquires GovernanceRecords { // of += ----> // of += // of += @@ -2084,7 +2249,11 @@ module aptos_framework::delegation_pool { voting_power_increase_limit, ); reconfiguration::initialize_for_test(aptos_framework); - features::change_feature_flags_for_testing(aptos_framework, vector[DELEGATION_POOLS, MODULE_EVENT, OPERATOR_BENEFICIARY_CHANGE, COMMISSION_CHANGE_DELEGATION_POOL], vector[]); + features::change_feature_flags_for_testing( + aptos_framework, + vector[DELEGATION_POOLS, MODULE_EVENT, OPERATOR_BENEFICIARY_CHANGE, COMMISSION_CHANGE_DELEGATION_POOL], + vector[] + ); } #[test_only] @@ -2376,7 +2545,11 @@ module aptos_framework::delegation_pool { reward_period_start_time_in_sec, fixed_point64::create_from_rational(50, 100), ); - features::change_feature_flags_for_testing(aptos_framework, vector[features::get_periodical_reward_rate_decrease_feature()], vector[]); + features::change_feature_flags_for_testing( + aptos_framework, + vector[features::get_periodical_reward_rate_decrease_feature()], + vector[] + ); // add more stake from delegator 1 stake::mint(delegator1, 20000 * ONE_APT); @@ -2385,7 +2558,13 @@ module aptos_framework::delegation_pool { fee = get_add_stake_fee(pool_address, 20000 * ONE_APT); add_stake(delegator1, pool_address, 20000 * ONE_APT); - assert_delegation(delegator1_address, pool_address, delegator1_active + 20000 * ONE_APT - fee, 0, delegator1_pending_inactive); + assert_delegation( + delegator1_address, + pool_address, + delegator1_active + 20000 * ONE_APT - fee, + 0, + delegator1_pending_inactive + ); // delegator 1 unlocks his entire newly added stake unlock(delegator1, pool_address, 20000 * ONE_APT - fee); @@ -3620,7 +3799,13 @@ module aptos_framework::delegation_pool { assert_delegation(new_operator_address, pool_address, 26050290, 0, 26050290); } - #[test(aptos_framework = @aptos_framework, operator1 = @0x123, delegator = @0x010, beneficiary = @0x020, operator2 = @0x030)] + #[test( + aptos_framework = @aptos_framework, + operator1 = @0x123, + delegator = @0x010, + beneficiary = @0x020, + operator2 = @0x030 + )] public entry fun test_set_beneficiary_for_operator( aptos_framework: &signer, operator1: &signer, @@ -3756,7 +3941,7 @@ module aptos_framework::delegation_pool { } #[test(aptos_framework = @aptos_framework, operator = @0x123, delegator = @0x010)] - #[expected_failure(abort_code=196629, location = Self)] + #[expected_failure(abort_code = 196629, location = Self)] public entry fun test_last_minute_commission_rate_change_failed( aptos_framework: &signer, operator: &signer, @@ -3932,7 +4117,8 @@ module aptos_framework::delegation_pool { aptos_governance::initialize_partial_voting(aptos_framework); features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting( + )], vector[]); initialize_test_validator(validator, 100 * ONE_APT, true, false); @@ -3952,13 +4138,13 @@ module aptos_framework::delegation_pool { let execution_hash = vector::empty(); vector::push_back(&mut execution_hash, 1); create_proposal( - delegator1, - pool_address, - execution_hash, - b"", - b"", - true, - ); + delegator1, + pool_address, + execution_hash, + b"", + b"", + true, + ); } #[test(aptos_framework = @aptos_framework, validator = @0x123, delegator1 = @0x010)] @@ -3977,7 +4163,8 @@ module aptos_framework::delegation_pool { aptos_governance::initialize_partial_voting(aptos_framework); features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting( + )], vector[]); initialize_test_validator(validator, 100 * ONE_APT, true, false); @@ -4006,7 +4193,14 @@ module aptos_framework::delegation_pool { ); } - #[test(aptos_framework = @aptos_framework, validator = @0x123, delegator1 = @0x010, delegator2 = @0x020, voter1 = @0x030, voter2 = @0x040)] + #[test( + aptos_framework = @aptos_framework, + validator = @0x123, + delegator1 = @0x010, + delegator2 = @0x020, + voter1 = @0x030, + voter2 = @0x040 + )] public entry fun test_voting_power_change( aptos_framework: &signer, validator: &signer, @@ -4025,7 +4219,8 @@ module aptos_framework::delegation_pool { aptos_governance::initialize_partial_voting(aptos_framework); features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting( + )], vector[] ); @@ -4194,7 +4389,8 @@ module aptos_framework::delegation_pool { // Enable partial governance voting feature flag. features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting( + )], vector[] ); // Voter doens't change until enabling partial governance voting on this delegation pool. @@ -4221,7 +4417,14 @@ module aptos_framework::delegation_pool { assert!(calculate_and_update_voter_total_voting_power(pool_address, delegator1_address) == 0, 1); } - #[test(aptos_framework = @aptos_framework, validator = @0x123, delegator1 = @0x010, delegator2 = @0x020, voter1 = @0x030, voter2 = @0x040)] + #[test( + aptos_framework = @aptos_framework, + validator = @0x123, + delegator1 = @0x010, + delegator2 = @0x020, + voter1 = @0x030, + voter2 = @0x040 + )] public entry fun test_voting_power_change_for_rewards( aptos_framework: &signer, validator: &signer, @@ -4249,7 +4452,8 @@ module aptos_framework::delegation_pool { aptos_governance::initialize_partial_voting(aptos_framework); features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting( + )], vector[] ); @@ -4311,7 +4515,14 @@ module aptos_framework::delegation_pool { assert!(calculate_and_update_voter_total_voting_power(pool_address, delegator2_address) == 0, 1); } - #[test(aptos_framework = @aptos_framework, validator = @0x123, delegator1 = @0x010, delegator2 = @0x020, voter1 = @0x030, voter2 = @0x040)] + #[test( + aptos_framework = @aptos_framework, + validator = @0x123, + delegator1 = @0x010, + delegator2 = @0x020, + voter1 = @0x030, + voter2 = @0x040 + )] public entry fun test_voting_power_change_already_voted_before_partial( aptos_framework: &signer, validator: &signer, @@ -4356,7 +4567,8 @@ module aptos_framework::delegation_pool { // Enable partial governance voting feature flag. features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting( + )], vector[] ); // Voter doens't change until enabling partial governance voting on this delegation pool. @@ -4373,9 +4585,18 @@ module aptos_framework::delegation_pool { assert!(calculate_and_update_remaining_voting_power(pool_address, validator_address, proposal1_id) == 0, 1); assert!(calculate_and_update_remaining_voting_power(pool_address, delegator1_address, proposal1_id) == 0, 1); assert!(calculate_and_update_remaining_voting_power(pool_address, delegator2_address, proposal1_id) == 0, 1); - assert!(calculate_and_update_remaining_voting_power(pool_address, validator_address, proposal2_id) == 100 * ONE_APT, 1); - assert!(calculate_and_update_remaining_voting_power(pool_address, delegator1_address, proposal2_id) == 10 * ONE_APT, 1); - assert!(calculate_and_update_remaining_voting_power(pool_address, delegator2_address, proposal2_id) == 90 * ONE_APT, 1); + assert!( + calculate_and_update_remaining_voting_power(pool_address, validator_address, proposal2_id) == 100 * ONE_APT, + 1 + ); + assert!( + calculate_and_update_remaining_voting_power(pool_address, delegator1_address, proposal2_id) == 10 * ONE_APT, + 1 + ); + assert!( + calculate_and_update_remaining_voting_power(pool_address, delegator2_address, proposal2_id) == 90 * ONE_APT, + 1 + ); // Delegator1 tries to use 50 APT to vote on proposal2, but it only has 10 APT. So only 10 APT voting power is used. vote(delegator1, pool_address, proposal2_id, 50 * ONE_APT, true); @@ -4384,13 +4605,19 @@ module aptos_framework::delegation_pool { add_stake(delegator1, pool_address, 60 * ONE_APT); assert!(calculate_and_update_voter_total_voting_power(pool_address, delegator1_address) == 70 * ONE_APT, 1); vote(delegator1, pool_address, proposal2_id, 25 * ONE_APT, true); - assert!(calculate_and_update_remaining_voting_power(pool_address, delegator1_address, proposal2_id) == 35 * ONE_APT, 1); + assert!( + calculate_and_update_remaining_voting_power(pool_address, delegator1_address, proposal2_id) == 35 * ONE_APT, + 1 + ); vote(delegator1, pool_address, proposal2_id, 30 * ONE_APT, false); - assert!(calculate_and_update_remaining_voting_power(pool_address, delegator1_address, proposal2_id) == 5 * ONE_APT, 1); + assert!( + calculate_and_update_remaining_voting_power(pool_address, delegator1_address, proposal2_id) == 5 * ONE_APT, + 1 + ); } #[test(aptos_framework = @aptos_framework, validator = @0x123, delegator1 = @0x010, voter1 = @0x030)] - #[expected_failure(abort_code=0x10010, location = Self)] + #[expected_failure(abort_code = 0x10010, location = Self)] public entry fun test_vote_should_failed_if_already_voted_before_enable_partial_voting_flag( aptos_framework: &signer, validator: &signer, @@ -4416,7 +4643,8 @@ module aptos_framework::delegation_pool { // Enable partial governance voting feature flag. features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting( + )], vector[] ); // Enable partial governance voting on this delegation pool. @@ -4426,7 +4654,7 @@ module aptos_framework::delegation_pool { } #[test(aptos_framework = @aptos_framework, validator = @0x123, delegator1 = @0x010, voter1 = @0x030)] - #[expected_failure(abort_code=0x10011, location = Self)] + #[expected_failure(abort_code = 0x10011, location = Self)] public entry fun test_vote_should_failed_if_already_voted_before_enable_partial_voting_on_pool( aptos_framework: &signer, validator: &signer, @@ -4450,7 +4678,8 @@ module aptos_framework::delegation_pool { // Enable partial governance voting feature flag. features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting( + )], vector[] ); @@ -4465,7 +4694,7 @@ module aptos_framework::delegation_pool { } #[test(aptos_framework = @aptos_framework, validator = @0x123, delegator1 = @0x010)] - #[expected_failure(abort_code=0x10010, location = Self)] + #[expected_failure(abort_code = 0x10010, location = Self)] public entry fun test_vote_should_failed_if_no_stake( aptos_framework: &signer, validator: &signer, @@ -4998,7 +5227,8 @@ module aptos_framework::delegation_pool { if (enable_partial_voting) { features::change_feature_flags_for_testing( aptos_framework, - vector[features::get_partial_governance_voting(), features::get_delegation_pool_partial_governance_voting()], + vector[features::get_partial_governance_voting( + ), features::get_delegation_pool_partial_governance_voting()], vector[]); enable_partial_governance_voting(pool_address); }; diff --git a/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.move b/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.move new file mode 100644 index 0000000000000..53fe8eddd4628 --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.move @@ -0,0 +1,192 @@ +/// This defines the fungible asset module that can issue fungible asset of any `Metadata` object. The +/// metadata object can be any object that equipped with `Metadata` resource. +/// +/// The dispatchable_fungible_asset wraps the existing fungible_asset module and adds the ability for token issuer +/// to customize the logic for withdraw and deposit operations. For example: +/// +/// - Deflation token: a fixed percentage of token will be destructed upon transfer. +/// - Transfer allowlist: token can only be transfered to addresses in the allow list. +/// - Predicated transfer: transfer can only happen when some certain predicate has been met. +/// - Loyalty token: a fixed loyalty will be paid to a designated address when a fungible asset transfer happens +/// +/// The api listed here intended to be an in-place replacement for defi applications that uses fungible_asset api directly +/// and is safe for non-dispatchable (aka vanilla) fungible assets as well. +/// +/// See AIP-73 for further discussion +/// +module aptos_framework::dispatchable_fungible_asset { + use aptos_framework::fungible_asset::{Self, FungibleAsset, TransferRef}; + use aptos_framework::function_info::{Self, FunctionInfo}; + use aptos_framework::object::{Self, ConstructorRef, Object}; + + use std::error; + use std::features; + use std::option::{Self, Option}; + + /// TransferRefStore doesn't exist on the fungible asset type. + const ESTORE_NOT_FOUND: u64 = 1; + /// Recipient is not getting the guaranteed value; + const EAMOUNT_MISMATCH: u64 = 2; + /// Feature is not activated yet on the network. + const ENOT_ACTIVATED: u64 = 3; + /// Dispatch target is not loaded. + const ENOT_LOADED: u64 = 4; + + #[resource_group_member(group = aptos_framework::object::ObjectGroup)] + struct TransferRefStore has key { + transfer_ref: TransferRef + } + + public fun register_dispatch_functions( + constructor_ref: &ConstructorRef, + withdraw_function: Option, + deposit_function: Option, + derived_balance_function: Option, + ) { + fungible_asset::register_dispatch_functions( + constructor_ref, + withdraw_function, + deposit_function, + derived_balance_function, + ); + let store_obj = &object::generate_signer(constructor_ref); + move_to( + store_obj, + TransferRefStore { + transfer_ref: fungible_asset::generate_transfer_ref(constructor_ref), + } + ); + } + + /// Withdraw `amount` of the fungible asset from `store` by the owner. + /// + /// The semantics of deposit will be governed by the function specified in DispatchFunctionStore. + public fun withdraw( + owner: &signer, + store: Object, + amount: u64, + ): FungibleAsset acquires TransferRefStore { + let func_opt = fungible_asset::withdraw_dispatch_function(store); + if (option::is_some(&func_opt)) { + assert!( + features::dispatchable_fungible_asset_enabled(), + error::aborted(ENOT_ACTIVATED) + ); + let start_balance = fungible_asset::balance(store); + let func = option::borrow(&func_opt); + function_info::load_module_from_function(func); + let fa = dispatchable_withdraw( + store, + amount, + borrow_transfer_ref(store), + func, + ); + let end_balance = fungible_asset::balance(store); + assert!(amount <= start_balance - end_balance, error::aborted(EAMOUNT_MISMATCH)); + fa + } else { + fungible_asset::withdraw_non_dispatch(owner, store, amount) + } + } + + /// Deposit `amount` of the fungible asset to `store`. + /// + /// The semantics of deposit will be governed by the function specified in DispatchFunctionStore. + public fun deposit(store: Object, fa: FungibleAsset) acquires TransferRefStore { + let func_opt = fungible_asset::deposit_dispatch_function(store); + if (option::is_some(&func_opt)) { + assert!( + features::dispatchable_fungible_asset_enabled(), + error::aborted(ENOT_ACTIVATED) + ); + let func = option::borrow(&func_opt); + function_info::load_module_from_function(func); + dispatchable_deposit( + store, + fa, + borrow_transfer_ref(store), + func + ) + } else { + fungible_asset::deposit_non_dispatch(store, fa) + } + } + + /// Transfer an `amount` of fungible asset from `from_store`, which should be owned by `sender`, to `receiver`. + /// Note: it does not move the underlying object. + public entry fun transfer( + sender: &signer, + from: Object, + to: Object, + amount: u64, + ) acquires TransferRefStore { + let fa = withdraw(sender, from, amount); + deposit(to, fa); + } + + /// Transfer an `amount` of fungible asset from `from_store`, which should be owned by `sender`, to `receiver`. + /// The recipient is guranteed to receive asset greater than the expected amount. + /// Note: it does not move the underlying object. + public entry fun transfer_assert_minimum_deposit( + sender: &signer, + from: Object, + to: Object, + amount: u64, + expected: u64 + ) acquires TransferRefStore { + let start = fungible_asset::balance(to); + let fa = withdraw(sender, from, amount); + deposit(to, fa); + let end = fungible_asset::balance(to); + assert!(end - start >= expected, error::aborted(EAMOUNT_MISMATCH)); + } + + #[view] + /// Get the derived value of store using the overloaded hook. + /// + /// The semantics of value will be governed by the function specified in DispatchFunctionStore. + public fun derived_balance(store: Object): u64 { + let func_opt = fungible_asset::derived_balance_dispatch_function(store); + if (option::is_some(&func_opt)) { + assert!( + features::dispatchable_fungible_asset_enabled(), + error::aborted(ENOT_ACTIVATED) + ); + let func = option::borrow(&func_opt); + function_info::load_module_from_function(func); + dispatchable_derived_balance(store, func) + } else { + fungible_asset::balance(store) + } + } + + inline fun borrow_transfer_ref(metadata: Object): &TransferRef acquires TransferRefStore { + let metadata_addr = object::object_address( + &fungible_asset::store_metadata(metadata) + ); + assert!( + exists(metadata_addr), + error::not_found(ESTORE_NOT_FOUND) + ); + &borrow_global(metadata_addr).transfer_ref + } + + native fun dispatchable_withdraw( + store: Object, + amount: u64, + transfer_ref: &TransferRef, + function: &FunctionInfo, + ): FungibleAsset; + + native fun dispatchable_deposit( + store: Object, + fa: FungibleAsset, + transfer_ref: &TransferRef, + function: &FunctionInfo, + ); + + native fun dispatchable_derived_balance( + store: Object, + function: &FunctionInfo, + ): u64; +} diff --git a/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.spec.move b/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.spec.move new file mode 100644 index 0000000000000..5932673f6041c --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/dispatchable_fungible_asset.spec.move @@ -0,0 +1,17 @@ +spec aptos_framework::dispatchable_fungible_asset { + spec module { + pragma verify = false; + } + + spec dispatchable_withdraw { + pragma opaque; + } + + spec dispatchable_deposit { + pragma opaque; + } + + spec dispatchable_derived_balance{ + pragma opaque; + } +} diff --git a/aptos-move/framework/aptos-framework/sources/dkg.spec.move b/aptos-move/framework/aptos-framework/sources/dkg.spec.move index d0de80b0db807..5453ac33ae24a 100644 --- a/aptos-move/framework/aptos-framework/sources/dkg.spec.move +++ b/aptos-move/framework/aptos-framework/sources/dkg.spec.move @@ -23,8 +23,9 @@ spec aptos_framework::dkg { spec finish(transcript: vector) { use std::option; - aborts_if !exists(@aptos_framework); - aborts_if option::is_none(global(@aptos_framework).in_progress); + requires exists(@aptos_framework); + requires option::is_some(global(@aptos_framework).in_progress); + aborts_if false; } spec fun has_incomplete_session(): bool { diff --git a/aptos-move/framework/aptos-framework/sources/function_info.move b/aptos-move/framework/aptos-framework/sources/function_info.move new file mode 100644 index 0000000000000..c7f78c11d081c --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/function_info.move @@ -0,0 +1,100 @@ +/// The `function_info` module defines the `FunctionInfo` type which simulates a function pointer. +module aptos_framework::function_info { + use std::error; + use std::features; + use std::signer; + use std::string::{Self, String}; + + friend aptos_framework::fungible_asset; + friend aptos_framework::dispatchable_fungible_asset; + + /// String is not a valid Move identifier + const EINVALID_IDENTIFIER: u64 = 1; + /// Function specified in the FunctionInfo doesn't exist on chain. + const EINVALID_FUNCTION: u64 = 2; + /// Feature hasn't been activated yet. + const ENOT_ACTIVATED: u64 = 3; + + /// A `String` holds a sequence of bytes which is guaranteed to be in utf8 format. + struct FunctionInfo has copy, drop, store { + module_address: address, + module_name: String, + function_name: String, + } + + /// Creates a new function info from names. + public fun new_function_info( + module_signer: &signer, + module_name: String, + function_name: String, + ): FunctionInfo { + new_function_info_from_address( + signer::address_of(module_signer), + module_name, + function_name, + ) + } + + public(friend) fun new_function_info_from_address( + module_address: address, + module_name: String, + function_name: String, + ): FunctionInfo { + assert!( + is_identifier(string::bytes(&module_name)), + EINVALID_IDENTIFIER + ); + assert!( + is_identifier(string::bytes(&function_name)), + EINVALID_IDENTIFIER + ); + FunctionInfo { + module_address, + module_name, + function_name, + } + } + + /// Check if the dispatch target function meets the type requirements of the disptach entry point. + /// + /// framework_function is the dispatch native function defined in the aptos_framework. + /// dispatch_target is the function passed in by the user. + /// + /// dispatch_target should have the same signature (same argument type, same generics constraint) except + /// that the framework_function will have a `&FunctionInfo` in the last argument that will instruct the VM which + /// function to jump to. + /// + /// dispatch_target also needs to be public so the type signature will remain unchanged. + public(friend) fun check_dispatch_type_compatibility( + framework_function: &FunctionInfo, + dispatch_target: &FunctionInfo, + ): bool { + assert!( + features::dispatchable_fungible_asset_enabled(), + error::aborted(ENOT_ACTIVATED) + ); + load_function_impl(dispatch_target); + check_dispatch_type_compatibility_impl(framework_function, dispatch_target) + } + + /// Load up a function into VM's loader and charge for its dependencies + /// + /// It is **critical** to make sure that this function is invoked before `check_dispatch_type_compatibility` + /// or performing any other dispatching logic to ensure: + /// 1. We properly charge gas for the function to dispatch. + /// 2. The function is loaded in the cache so that we can perform further type checking/dispatching logic. + /// + /// Calling `check_dispatch_type_compatibility_impl` or dispatch without loading up the module would yield an error + /// if such module isn't accessed previously in the transaction. + public(friend) fun load_module_from_function(f: &FunctionInfo) { + load_function_impl(f) + } + + native fun check_dispatch_type_compatibility_impl(lhs: &FunctionInfo, r: &FunctionInfo): bool; + native fun is_identifier(s: &vector): bool; + native fun load_function_impl(f: &FunctionInfo); + + // Test only dependencies so we can invoke those friend functions. + #[test_only] + friend aptos_framework::function_info_tests; +} diff --git a/aptos-move/framework/aptos-framework/sources/function_info.spec.move b/aptos-move/framework/aptos-framework/sources/function_info.spec.move new file mode 100644 index 0000000000000..06beb9cc209c1 --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/function_info.spec.move @@ -0,0 +1,13 @@ +spec aptos_framework::function_info { + spec module { + pragma verify = false; + } + + spec check_dispatch_type_compatibility_impl { + pragma opaque; + } + + spec load_function_impl{ + pragma opaque; + } +} diff --git a/aptos-move/framework/aptos-framework/sources/fungible_asset.move b/aptos-move/framework/aptos-framework/sources/fungible_asset.move index 218dbe9f7c37a..48e513377a570 100644 --- a/aptos-move/framework/aptos-framework/sources/fungible_asset.move +++ b/aptos-move/framework/aptos-framework/sources/fungible_asset.move @@ -3,6 +3,7 @@ module aptos_framework::fungible_asset { use aptos_framework::aggregator_v2::{Self, Aggregator}; use aptos_framework::event; + use aptos_framework::function_info::{Self, FunctionInfo}; use aptos_framework::object::{Self, Object, ConstructorRef, DeleteRef, ExtendRef}; use std::string; use std::features; @@ -12,6 +13,11 @@ module aptos_framework::fungible_asset { use std::signer; use std::string::String; + friend aptos_framework::coin; + friend aptos_framework::primary_fungible_store; + + friend aptos_framework::dispatchable_fungible_asset; + /// Amount cannot be zero. const EAMOUNT_CANNOT_BE_ZERO: u64 = 1; /// The transfer ref and the fungible asset do not match. @@ -56,6 +62,20 @@ module aptos_framework::fungible_asset { const ESUPPLY_NOT_FOUND: u64 = 21; /// Flag for Concurrent Supply not enabled const ECONCURRENT_SUPPLY_NOT_ENABLED: u64 = 22; + /// Flag for the existence of fungible store. + const EFUNGIBLE_STORE_EXISTENCE: u64 = 23; + /// Account is not the owner of metadata object. + const ENOT_METADATA_OWNER: u64 = 24; + /// Provided withdraw function type doesn't meet the signature requirement. + const EWITHDRAW_FUNCTION_SIGNATURE_MISMATCH: u64 = 25; + /// Provided deposit function type doesn't meet the signature requirement. + const EDEPOSIT_FUNCTION_SIGNATURE_MISMATCH: u64 = 26; + /// Provided derived_balance function type doesn't meet the signature requirement. + const EDERIVED_BALANCE_FUNCTION_SIGNATURE_MISMATCH: u64 = 27; + /// Invalid withdraw/deposit on dispatchable token. + const EINVALID_DISPATCHABLE_OPERATIONS: u64 = 28; + /// Trying to re-register dispatch hook on a fungible asset. + const EALREADY_REGISTERED: u64 = 29; // // Constants @@ -111,6 +131,13 @@ module aptos_framework::fungible_asset { frozen: bool, } + #[resource_group_member(group = aptos_framework::object::ObjectGroup)] + struct DispatchFunctionStore has key { + withdraw_function: Option, + deposit_function: Option, + derived_balance_function: Option, + } + /// FungibleAsset can be passed into function for type safety and to guarantee a specific amount. /// FungibleAsset is ephemeral and cannot be stored directly. It must be deposited back into a store. struct FungibleAsset { @@ -207,6 +234,97 @@ module aptos_framework::fungible_asset { object::object_from_constructor_ref(constructor_ref) } + /// Create a fungible asset store whose transfer rule would be overloaded by the provided function. + public(friend) fun register_dispatch_functions( + constructor_ref: &ConstructorRef, + withdraw_function: Option, + deposit_function: Option, + derived_balance_function: Option, + ) { + // Verify that caller type matches callee type so wrongly typed function cannot be registered. + option::for_each_ref(&withdraw_function, |withdraw_function| { + let dispatcher_withdraw_function_info = function_info::new_function_info_from_address( + @aptos_framework, + string::utf8(b"dispatchable_fungible_asset"), + string::utf8(b"dispatchable_withdraw"), + ); + + assert!( + function_info::check_dispatch_type_compatibility( + &dispatcher_withdraw_function_info, + withdraw_function + ), + error::invalid_argument( + EWITHDRAW_FUNCTION_SIGNATURE_MISMATCH + ) + ); + }); + + option::for_each_ref(&deposit_function, |deposit_function| { + let dispatcher_deposit_function_info = function_info::new_function_info_from_address( + @aptos_framework, + string::utf8(b"dispatchable_fungible_asset"), + string::utf8(b"dispatchable_deposit"), + ); + // Verify that caller type matches callee type so wrongly typed function cannot be registered. + assert!( + function_info::check_dispatch_type_compatibility( + &dispatcher_deposit_function_info, + deposit_function + ), + error::invalid_argument( + EDEPOSIT_FUNCTION_SIGNATURE_MISMATCH + ) + ); + }); + + option::for_each_ref(&derived_balance_function, |balance_function| { + let dispatcher_derived_balance_function_info = function_info::new_function_info_from_address( + @aptos_framework, + string::utf8(b"dispatchable_fungible_asset"), + string::utf8(b"dispatchable_derived_balance"), + ); + // Verify that caller type matches callee type so wrongly typed function cannot be registered. + assert!( + function_info::check_dispatch_type_compatibility( + &dispatcher_derived_balance_function_info, + balance_function + ), + error::invalid_argument( + EDERIVED_BALANCE_FUNCTION_SIGNATURE_MISMATCH + ) + ); + }); + + // Cannot register hook for APT. + assert!( + object::address_from_constructor_ref(constructor_ref) != @aptos_fungible_asset, + error::invalid_argument(EALREADY_REGISTERED) + ); + assert!( + !object::can_generate_delete_ref(constructor_ref), + error::invalid_argument(EOBJECT_IS_DELETABLE) + ); + assert!( + !exists( + object::address_from_constructor_ref(constructor_ref) + ), + error::already_exists(EALREADY_REGISTERED) + ); + + let store_obj = &object::generate_signer(constructor_ref); + + // Store the overload function hook. + move_to( + store_obj, + DispatchFunctionStore { + withdraw_function, + deposit_function, + derived_balance_function, + } + ); + } + /// Creates a mint ref that can be used to mint fungible assets from the given fungible object's constructor ref. /// This can only be called at object creation time as constructor_ref is only available then. public fun generate_mint_ref(constructor_ref: &ConstructorRef): MintRef { @@ -315,6 +433,17 @@ module aptos_framework::fungible_asset { } } + #[view] + /// Check whether the balance of a given store is >= `amount`. + public fun is_balance_at_least(store: Object, amount: u64): bool acquires FungibleStore { + let store_addr = object::object_address(&store); + if (store_exists(store_addr)) { + borrow_store_resource(&store).balance >= amount + } else { + amount == 0 + } + } + #[view] /// Return whether a store is frozen. /// @@ -323,6 +452,64 @@ module aptos_framework::fungible_asset { store_exists(object::object_address(&store)) && borrow_store_resource(&store).frozen } + #[view] + /// Return whether a fungible asset type is dispatchable. + public fun is_dispatchable(store: Object): bool acquires FungibleStore { + let fa_store = borrow_store_resource(&store); + let metadata_addr = object::object_address(&fa_store.metadata); + exists(metadata_addr) + } + + public fun deposit_dispatch_function(store: Object): Option acquires FungibleStore, DispatchFunctionStore { + let fa_store = borrow_store_resource(&store); + let metadata_addr = object::object_address(&fa_store.metadata); + if(exists(metadata_addr)) { + borrow_global(metadata_addr).deposit_function + } else { + option::none() + } + } + + fun has_deposit_dispatch_function(metadata: Object): bool acquires DispatchFunctionStore { + let metadata_addr = object::object_address(&metadata); + // Short circuit on APT for better perf + if(metadata_addr != @aptos_fungible_asset && exists(metadata_addr)) { + option::is_some(&borrow_global(metadata_addr).deposit_function) + } else { + false + } + } + + public fun withdraw_dispatch_function(store: Object): Option acquires FungibleStore, DispatchFunctionStore { + let fa_store = borrow_store_resource(&store); + let metadata_addr = object::object_address(&fa_store.metadata); + if(exists(metadata_addr)) { + borrow_global(metadata_addr).withdraw_function + } else { + option::none() + } + } + + fun has_withdraw_dispatch_function(metadata: Object): bool acquires DispatchFunctionStore { + let metadata_addr = object::object_address(&metadata); + // Short circuit on APT for better perf + if (metadata_addr != @aptos_fungible_asset && exists(metadata_addr)) { + option::is_some(&borrow_global(metadata_addr).withdraw_function) + } else { + false + } + } + + public(friend) fun derived_balance_dispatch_function(store: Object): Option acquires FungibleStore, DispatchFunctionStore { + let fa_store = borrow_store_resource(&store); + let metadata_addr = object::object_address(&fa_store.metadata); + if (exists(metadata_addr)) { + borrow_global(metadata_addr).derived_balance_function + } else { + option::none() + } + } + public fun asset_metadata(fa: &FungibleAsset): Object { fa.metadata } @@ -349,7 +536,7 @@ module aptos_framework::fungible_asset { from: Object, to: Object, amount: u64, - ) acquires FungibleStore { + ) acquires FungibleStore, DispatchFunctionStore { let fa = withdraw(sender, from, amount); deposit(to, fa); } @@ -394,24 +581,59 @@ module aptos_framework::fungible_asset { owner: &signer, store: Object, amount: u64, + ): FungibleAsset acquires FungibleStore, DispatchFunctionStore { + assert!(object::owns(store, signer::address_of(owner)), error::permission_denied(ENOT_STORE_OWNER)); + assert!(store_exists(object::object_address(&store)), error::invalid_argument(ESTORE_IS_FROZEN)); + let fa_store = borrow_store_resource(&store); + assert!( + !has_withdraw_dispatch_function(fa_store.metadata), + error::invalid_argument(EINVALID_DISPATCHABLE_OPERATIONS) + ); + assert!(!fa_store.frozen, error::invalid_argument(ESTORE_IS_FROZEN)); + withdraw_internal(object::object_address(&store), amount) + } + + /// Deposit `amount` of the fungible asset to `store`. + public fun deposit(store: Object, fa: FungibleAsset) acquires FungibleStore, DispatchFunctionStore { + assert!(store_exists(object::object_address(&store)), error::permission_denied(ESTORE_IS_FROZEN)); + let fa_store = borrow_store_resource(&store); + assert!( + !has_deposit_dispatch_function(fa_store.metadata), + error::invalid_argument(EINVALID_DISPATCHABLE_OPERATIONS) + ); + assert!(!fa_store.frozen, error::permission_denied(ESTORE_IS_FROZEN)); + deposit_internal(store, fa); + } + + /// Withdraw `amount` of the fungible asset from `store` by the owner. + public(friend) fun withdraw_non_dispatch( + owner: &signer, + store: Object, + amount: u64, ): FungibleAsset acquires FungibleStore { assert!(object::owns(store, signer::address_of(owner)), error::permission_denied(ENOT_STORE_OWNER)); - assert!(!is_frozen(store), error::invalid_argument(ESTORE_IS_FROZEN)); + assert!(!is_frozen(store), error::permission_denied(ESTORE_IS_FROZEN)); withdraw_internal(object::object_address(&store), amount) } /// Deposit `amount` of the fungible asset to `store`. - public fun deposit(store: Object, fa: FungibleAsset) acquires FungibleStore { - assert!(!is_frozen(store), error::invalid_argument(ESTORE_IS_FROZEN)); + public(friend) fun deposit_non_dispatch(store: Object, fa: FungibleAsset) acquires FungibleStore { + assert!(!is_frozen(store), error::permission_denied(ESTORE_IS_FROZEN)); deposit_internal(store, fa); } /// Mint the specified `amount` of the fungible asset. public fun mint(ref: &MintRef, amount: u64): FungibleAsset acquires Supply, ConcurrentSupply { - assert!(amount > 0, error::invalid_argument(EAMOUNT_CANNOT_BE_ZERO)); let metadata = ref.metadata; - increase_supply(&metadata, amount); + mint_internal(metadata, amount) + } + /// CAN ONLY BE CALLED BY coin.move for migration. + public(friend) fun mint_internal( + metadata: Object, + amount: u64 + ): FungibleAsset acquires Supply, ConcurrentSupply { + increase_supply(&metadata, amount); FungibleAsset { metadata, amount @@ -420,7 +642,7 @@ module aptos_framework::fungible_asset { /// Mint the specified `amount` of the fungible asset to a destination store. public fun mint_to(ref: &MintRef, store: Object, amount: u64) - acquires FungibleStore, Supply, ConcurrentSupply { + acquires FungibleStore, Supply, ConcurrentSupply, DispatchFunctionStore { deposit(store, mint(ref, amount)); } @@ -434,6 +656,13 @@ module aptos_framework::fungible_asset { ref.metadata == store_metadata(store), error::invalid_argument(ETRANSFER_REF_AND_STORE_MISMATCH), ); + set_frozen_flag_internal(store, frozen) + } + + public(friend) fun set_frozen_flag_internal( + store: Object, + frozen: bool + ) acquires FungibleStore { let store_addr = object::object_address(&store); borrow_global_mut(store_addr).frozen = frozen; @@ -442,12 +671,23 @@ module aptos_framework::fungible_asset { /// Burns a fungible asset public fun burn(ref: &BurnRef, fa: FungibleAsset) acquires Supply, ConcurrentSupply { + assert!( + ref.metadata == metadata_from_asset(&fa), + error::invalid_argument(EBURN_REF_AND_FUNGIBLE_ASSET_MISMATCH) + ); + burn_internal(fa); + } + + /// CAN ONLY BE CALLED BY coin.move for migration. + public(friend) fun burn_internal( + fa: FungibleAsset + ): u64 acquires Supply, ConcurrentSupply { let FungibleAsset { metadata, - amount, + amount } = fa; - assert!(ref.metadata == metadata, error::invalid_argument(EBURN_REF_AND_FUNGIBLE_ASSET_MISMATCH)); decrease_supply(&metadata, amount); + amount } /// Burn the `amount` of the fungible asset from the given store. @@ -532,7 +772,7 @@ module aptos_framework::fungible_asset { assert!(amount == 0, error::invalid_argument(EAMOUNT_IS_NOT_ZERO)); } - fun deposit_internal(store: Object, fa: FungibleAsset) acquires FungibleStore { + public(friend) fun deposit_internal(store: Object, fa: FungibleAsset) acquires FungibleStore { let FungibleAsset { metadata, amount } = fa; if (amount == 0) return; @@ -546,24 +786,26 @@ module aptos_framework::fungible_asset { } /// Extract `amount` of the fungible asset from `store`. - fun withdraw_internal( + public(friend) fun withdraw_internal( store_addr: address, amount: u64, ): FungibleAsset acquires FungibleStore { - assert!(amount != 0, error::invalid_argument(EAMOUNT_CANNOT_BE_ZERO)); + assert!(exists(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE)); let store = borrow_global_mut(store_addr); - assert!(store.balance >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE)); - store.balance = store.balance - amount; - let metadata = store.metadata; - event::emit(Withdraw { store: store_addr, amount }); - + if (amount != 0) { + assert!(store.balance >= amount, error::invalid_argument(EINSUFFICIENT_BALANCE)); + store.balance = store.balance - amount; + event::emit(Withdraw { store: store_addr, amount }); + }; FungibleAsset { metadata, amount } } /// Increase the supply of a fungible asset by minting. fun increase_supply(metadata: &Object, amount: u64) acquires Supply, ConcurrentSupply { - assert!(amount != 0, error::invalid_argument(EAMOUNT_CANNOT_BE_ZERO)); + if (amount == 0) { + return + }; let metadata_address = object::object_address(metadata); if (exists(metadata_address)) { @@ -583,13 +825,15 @@ module aptos_framework::fungible_asset { }; supply.current = supply.current + (amount as u128); } else { - assert!(false, error::not_found(ESUPPLY_NOT_FOUND)); + abort error::not_found(ESUPPLY_NOT_FOUND) } } /// Decrease the supply of a fungible asset by burning. fun decrease_supply(metadata: &Object, amount: u64) acquires Supply, ConcurrentSupply { - assert!(amount != 0, error::invalid_argument(EAMOUNT_CANNOT_BE_ZERO)); + if (amount == 0) { + return + }; let metadata_address = object::object_address(metadata); if (exists(metadata_address)) { @@ -627,7 +871,9 @@ module aptos_framework::fungible_asset { } inline fun borrow_store_resource(store: &Object): &FungibleStore acquires FungibleStore { - borrow_global(object::object_address(store)) + let store_addr = object::object_address(store); + assert!(exists(store_addr), error::not_found(EFUNGIBLE_STORE_EXISTENCE)); + borrow_global(store_addr) } public fun upgrade_to_concurrent( @@ -635,7 +881,10 @@ module aptos_framework::fungible_asset { ) acquires Supply { let metadata_object_address = object::address_from_extend_ref(ref); let metadata_object_signer = object::generate_signer_for_extending(ref); - assert!(features::concurrent_fungible_assets_enabled(), error::invalid_argument(ECONCURRENT_SUPPLY_NOT_ENABLED)); + assert!( + features::concurrent_fungible_assets_enabled(), + error::invalid_argument(ECONCURRENT_SUPPLY_NOT_ENABLED) + ); assert!(exists(metadata_object_address), error::not_found(ESUPPLY_NOT_FOUND)); let Supply { current, @@ -747,7 +996,7 @@ module aptos_framework::fungible_asset { fun test_e2e_basic_flow( creator: &signer, aaron: &signer, - ) acquires FungibleStore, Supply, ConcurrentSupply { + ) acquires FungibleStore, Supply, ConcurrentSupply, DispatchFunctionStore { let (mint_ref, transfer_ref, burn_ref, test_token) = create_fungible_asset(creator); let metadata = mint_ref.metadata; let creator_store = create_test_store(creator, metadata); @@ -776,10 +1025,10 @@ module aptos_framework::fungible_asset { } #[test(creator = @0xcafe)] - #[expected_failure(abort_code = 0x10003, location = Self)] + #[expected_failure(abort_code = 0x50003, location = Self)] fun test_frozen( creator: &signer - ) acquires FungibleStore, Supply, ConcurrentSupply { + ) acquires FungibleStore, Supply, ConcurrentSupply, DispatchFunctionStore { let (mint_ref, transfer_ref, _burn_ref, _) = create_fungible_asset(creator); let creator_store = create_test_store(creator, mint_ref.metadata); diff --git a/aptos-move/framework/aptos-framework/sources/jwks.move b/aptos-move/framework/aptos-framework/sources/jwks.move index 1ff030ed908d7..febdccc2858d9 100644 --- a/aptos-move/framework/aptos-framework/sources/jwks.move +++ b/aptos-move/framework/aptos-framework/sources/jwks.move @@ -247,9 +247,15 @@ module aptos_framework::jwks { } /// Only used in reconfigurations to apply the pending `SupportedOIDCProviders`, if there is any. - public(friend) fun on_new_epoch() acquires SupportedOIDCProviders { + public(friend) fun on_new_epoch(framework: &signer) acquires SupportedOIDCProviders { + system_addresses::assert_aptos_framework(framework); if (config_buffer::does_exist()) { - *borrow_global_mut(@aptos_framework) = config_buffer::extract(); + let new_config = config_buffer::extract(); + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = new_config; + } else { + move_to(framework, new_config); + } } } diff --git a/aptos-move/framework/aptos-framework/sources/jwks.spec.move b/aptos-move/framework/aptos-framework/sources/jwks.spec.move new file mode 100644 index 0000000000000..764b09f125f36 --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/jwks.spec.move @@ -0,0 +1,7 @@ +spec aptos_framework::jwks { + spec on_new_epoch(framework: &signer) { + requires @aptos_framework == std::signer::address_of(framework); + include config_buffer::OnNewEpochRequirement; + aborts_if false; + } +} diff --git a/aptos-move/framework/aptos-framework/sources/keyless_account.move b/aptos-move/framework/aptos-framework/sources/keyless_account.move index 27f2787a30b65..ad217a313f38a 100644 --- a/aptos-move/framework/aptos-framework/sources/keyless_account.move +++ b/aptos-move/framework/aptos-framework/sources/keyless_account.move @@ -1,22 +1,36 @@ /// This module is responsible for configuring keyless blockchain accounts which were introduced in /// [AIP-61](https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-61.md). module aptos_framework::keyless_account { + use std::bn254_algebra; + use std::config_buffer; use std::option; use std::option::Option; use std::signer; use std::string::String; use std::vector; + use aptos_std::crypto_algebra; + use aptos_std::ed25519; + use aptos_framework::chain_status; use aptos_framework::system_addresses; + // The `aptos_framework::reconfiguration_with_dkg` module needs to be able to call `on_new_epoch`. + friend aptos_framework::reconfiguration_with_dkg; + /// The training wheels PK needs to be 32 bytes long. const E_TRAINING_WHEELS_PK_WRONG_SIZE : u64 = 1; + /// A serialized BN254 G1 point is invalid. + const E_INVALID_BN254_G1_SERIALIZATION: u64 = 2; + + /// A serialized BN254 G2 point is invalid. + const E_INVALID_BN254_G2_SERIALIZATION: u64 = 3; + #[resource_group(scope = global)] struct Group {} #[resource_group_member(group = aptos_framework::keyless_account::Group)] /// The 288-byte Groth16 verification key (VK) for the ZK relation that implements keyless accounts - struct Groth16VerificationKey has key, store { + struct Groth16VerificationKey has key, store, drop { /// 32-byte serialization of `alpha * G`, where `G` is the generator of `G1`. alpha_g1: vector, /// 64-byte serialization of `alpha * H`, where `H` is the generator of `G2`. @@ -31,7 +45,7 @@ module aptos_framework::keyless_account { } #[resource_group_member(group = aptos_framework::keyless_account::Group)] - struct Configuration has key, store { + struct Configuration has key, store, drop, copy { /// An override `aud` for the identity of a recovery service, which will help users recover their keyless accounts /// associated with dapps or wallets that have disappeared. /// IMPORTANT: This recovery service **cannot** on its own take over user accounts; a user must first sign in @@ -98,49 +112,45 @@ module aptos_framework::keyless_account { } } - // Sets the Groth16 verification key, only callable via governance proposal. - // WARNING: If a malicious key is set, this would lead to stolen funds. - public fun update_groth16_verification_key(fx: &signer, vk: Groth16VerificationKey) acquires Groth16VerificationKey { - system_addresses::assert_aptos_framework(fx); - - if (exists(signer::address_of(fx))) { - let Groth16VerificationKey { - alpha_g1: _, - beta_g2: _, - gamma_g2: _, - delta_g2: _, - gamma_abc_g1: _ - } = move_from(signer::address_of(fx)); + /// Pre-validate the VK to actively-prevent incorrect VKs from being set on-chain. + fun validate_groth16_vk(vk: &Groth16VerificationKey) { + // Could be leveraged to speed up the VM deserialization of the VK by 2x, since it can assume the points are valid. + assert!(option::is_some(&crypto_algebra::deserialize(&vk.alpha_g1)), E_INVALID_BN254_G1_SERIALIZATION); + assert!(option::is_some(&crypto_algebra::deserialize(&vk.beta_g2)), E_INVALID_BN254_G2_SERIALIZATION); + assert!(option::is_some(&crypto_algebra::deserialize(&vk.gamma_g2)), E_INVALID_BN254_G2_SERIALIZATION); + assert!(option::is_some(&crypto_algebra::deserialize(&vk.delta_g2)), E_INVALID_BN254_G2_SERIALIZATION); + for(i in 0..vector::length(&vk.gamma_abc_g1)) { + assert!(option::is_some(&crypto_algebra::deserialize(vector::borrow(&vk.gamma_abc_g1, i))), E_INVALID_BN254_G1_SERIALIZATION); }; + } + /// Sets the Groth16 verification key, only callable during genesis. To call during governance proposals, use + /// `set_groth16_verification_key_for_next_epoch`. + /// + /// WARNING: See `set_groth16_verification_key_for_next_epoch` for caveats. + public fun update_groth16_verification_key(fx: &signer, vk: Groth16VerificationKey) { + system_addresses::assert_aptos_framework(fx); + chain_status::assert_genesis(); + // There should not be a previous resource set here. move_to(fx, vk); } - // Sets the keyless configuration, only callable via governance proposal. - // WARNING: If a malicious key is set, this would lead to stolen funds. - public fun update_configuration(fx: &signer, config: Configuration) acquires Configuration { + /// Sets the keyless configuration, only callable during genesis. To call during governance proposals, use + /// `set_configuration_for_next_epoch`. + /// + /// WARNING: See `set_configuration_for_next_epoch` for caveats. + public fun update_configuration(fx: &signer, config: Configuration) { system_addresses::assert_aptos_framework(fx); - - if (exists(signer::address_of(fx))) { - let Configuration { - override_aud_vals: _, - max_signatures_per_txn: _, - max_exp_horizon_secs: _, - training_wheels_pubkey: _, - max_commited_epk_bytes: _, - max_iss_val_bytes: _, - max_extra_field_bytes: _, - max_jwt_header_b64_bytes: _, - } = move_from(signer::address_of(fx)); - }; - + chain_status::assert_genesis(); + // There should not be a previous resource set here. move_to(fx, config); } - // Convenience method to [un]set the training wheels PK, only callable via governance proposal. - // WARNING: If a malicious key is set, this would lead to stolen funds. + #[deprecated] public fun update_training_wheels(fx: &signer, pk: Option>) acquires Configuration { system_addresses::assert_aptos_framework(fx); + chain_status::assert_genesis(); + if (option::is_some(&pk)) { assert!(vector::length(option::borrow(&pk)) == 32, E_TRAINING_WHEELS_PK_WRONG_SIZE) }; @@ -149,30 +159,154 @@ module aptos_framework::keyless_account { config.training_wheels_pubkey = pk; } - // Convenience method to set the max expiration horizon, only callable via governance proposal. + #[deprecated] public fun update_max_exp_horizon(fx: &signer, max_exp_horizon_secs: u64) acquires Configuration { system_addresses::assert_aptos_framework(fx); + chain_status::assert_genesis(); let config = borrow_global_mut(signer::address_of(fx)); config.max_exp_horizon_secs = max_exp_horizon_secs; } - // Convenience method to clear the set of override `aud`'s, only callable via governance proposal. - // WARNING: When no override `aud` is set, recovery of keyless accounts associated with applications that disappeared - // is no longer possible. + #[deprecated] public fun remove_all_override_auds(fx: &signer) acquires Configuration { system_addresses::assert_aptos_framework(fx); + chain_status::assert_genesis(); let config = borrow_global_mut(signer::address_of(fx)); config.override_aud_vals = vector[]; } - // Convenience method to append to the set of override `aud`'s, only callable via governance proposal. - // WARNING: If a malicious override `aud` is set, this would lead to stolen funds. + #[deprecated] public fun add_override_aud(fx: &signer, aud: String) acquires Configuration { system_addresses::assert_aptos_framework(fx); + chain_status::assert_genesis(); let config = borrow_global_mut(signer::address_of(fx)); vector::push_back(&mut config.override_aud_vals, aud); } + /// Queues up a change to the Groth16 verification key. The change will only be effective after reconfiguration. + /// Only callable via governance proposal. + /// + /// WARNING: To mitigate against DoS attacks, a VK change should be done together with a training wheels PK change, + /// so that old ZKPs for the old VK cannot be replayed as potentially-valid ZKPs. + /// + /// WARNING: If a malicious key is set, this would lead to stolen funds. + public fun set_groth16_verification_key_for_next_epoch(fx: &signer, vk: Groth16VerificationKey) { + system_addresses::assert_aptos_framework(fx); + validate_groth16_vk(&vk); + config_buffer::upsert(vk); + } + + + /// Queues up a change to the keyless configuration. The change will only be effective after reconfiguration. Only + /// callable via governance proposal. + /// + /// WARNING: A malicious `Configuration` could lead to DoS attacks, create liveness issues, or enable a malicious + /// recovery service provider to phish users' accounts. + public fun set_configuration_for_next_epoch(fx: &signer, config: Configuration) { + system_addresses::assert_aptos_framework(fx); + config_buffer::upsert(config); + } + + /// Convenience method to queue up a change to the training wheels PK. The change will only be effective after + /// reconfiguration. Only callable via governance proposal. + /// + /// WARNING: If a malicious key is set, this *could* lead to stolen funds. + public fun update_training_wheels_for_next_epoch(fx: &signer, pk: Option>) acquires Configuration { + system_addresses::assert_aptos_framework(fx); + + // If a PK is being set, validate it first. + if (option::is_some(&pk)) { + let bytes = *option::borrow(&pk); + let vpk = ed25519::new_validated_public_key_from_bytes(bytes); + assert!(option::is_some(&vpk), E_TRAINING_WHEELS_PK_WRONG_SIZE) + }; + + let config = if (config_buffer::does_exist()) { + config_buffer::extract() + } else { + *borrow_global(signer::address_of(fx)) + }; + + config.training_wheels_pubkey = pk; + + set_configuration_for_next_epoch(fx, config); + } + + /// Convenience method to queues up a change to the max expiration horizon. The change will only be effective after + /// reconfiguration. Only callable via governance proposal. + public fun update_max_exp_horizon_for_next_epoch(fx: &signer, max_exp_horizon_secs: u64) acquires Configuration { + system_addresses::assert_aptos_framework(fx); + + let config = if (config_buffer::does_exist()) { + config_buffer::extract() + } else { + *borrow_global(signer::address_of(fx)) + }; + + config.max_exp_horizon_secs = max_exp_horizon_secs; + + set_configuration_for_next_epoch(fx, config); + } + + /// Convenience method to queue up clearing the set of override `aud`'s. The change will only be effective after + /// reconfiguration. Only callable via governance proposal. + /// + /// WARNING: When no override `aud` is set, recovery of keyless accounts associated with applications that disappeared + /// is no longer possible. + public fun remove_all_override_auds_for_next_epoch(fx: &signer) acquires Configuration { + system_addresses::assert_aptos_framework(fx); + + let config = if (config_buffer::does_exist()) { + config_buffer::extract() + } else { + *borrow_global(signer::address_of(fx)) + }; + + config.override_aud_vals = vector[]; + + set_configuration_for_next_epoch(fx, config); + } + + /// Convenience method to queue up an append to to the set of override `aud`'s. The change will only be effective + /// after reconfiguration. Only callable via governance proposal. + /// + /// WARNING: If a malicious override `aud` is set, this *could* lead to stolen funds. + public fun add_override_aud_for_next_epoch(fx: &signer, aud: String) acquires Configuration { + system_addresses::assert_aptos_framework(fx); + + let config = if (config_buffer::does_exist()) { + config_buffer::extract() + } else { + *borrow_global(signer::address_of(fx)) + }; + + vector::push_back(&mut config.override_aud_vals, aud); + + set_configuration_for_next_epoch(fx, config); + } + + /// Only used in reconfigurations to apply the queued up configuration changes, if there are any. + public(friend) fun on_new_epoch(fx: &signer) acquires Groth16VerificationKey, Configuration { + system_addresses::assert_aptos_framework(fx); + + if (config_buffer::does_exist()) { + let vk = config_buffer::extract(); + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = vk; + } else { + move_to(fx, vk); + } + }; + + if(config_buffer::does_exist()) { + let config = config_buffer::extract(); + if (exists(@aptos_framework)) { + *borrow_global_mut(@aptos_framework) = config; + } else { + move_to(fx, config); + } + }; + } } diff --git a/aptos-move/framework/aptos-framework/sources/keyless_account.spec.move b/aptos-move/framework/aptos-framework/sources/keyless_account.spec.move new file mode 100644 index 0000000000000..c04f2ad6bf004 --- /dev/null +++ b/aptos-move/framework/aptos-framework/sources/keyless_account.spec.move @@ -0,0 +1,6 @@ +spec aptos_framework::keyless_account { + spec module { + // TODO: verification is disabled until this module is specified. + pragma verify=false; + } +} diff --git a/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move b/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move index bf08205a79b4a..e6eafd0904c11 100644 --- a/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move +++ b/aptos-move/framework/aptos-framework/sources/managed_coin.spec.move @@ -55,6 +55,8 @@ spec aptos_framework::managed_coin { amount: u64, ) { use aptos_std::type_info; + // TODO(fa_migration) + pragma verify = false; let account_addr = signer::address_of(account); @@ -112,6 +114,8 @@ spec aptos_framework::managed_coin { amount: u64, ) { use aptos_std::type_info; + // TODO(fa_migration) + pragma verify = false; let account_addr = signer::address_of(account); /// [high-level-req-3.3] aborts_if !exists>(account_addr); @@ -131,6 +135,8 @@ spec aptos_framework::managed_coin { spec register(account: &signer) { use aptos_framework::account; use aptos_std::type_info; + // TODO(fa_migration) + pragma verify = false; let account_addr = signer::address_of(account); let acc = global(account_addr); diff --git a/aptos-move/framework/aptos-framework/sources/multisig_account.move b/aptos-move/framework/aptos-framework/sources/multisig_account.move index 4114a111a19a6..b8a6200400960 100644 --- a/aptos-move/framework/aptos-framework/sources/multisig_account.move +++ b/aptos-move/framework/aptos-framework/sources/multisig_account.move @@ -897,8 +897,7 @@ module aptos_framework::multisig_account { assert!(vector::length(&payload) > 0, error::invalid_argument(EPAYLOAD_CANNOT_BE_EMPTY)); assert_multisig_account_exists(multisig_account); - let multisig_account_resource = borrow_global_mut(multisig_account); - assert_is_owner_internal(owner, multisig_account_resource); + assert_is_owner(owner, multisig_account); let creator = address_of(owner); let transaction = MultisigTransaction { @@ -908,7 +907,7 @@ module aptos_framework::multisig_account { creator, creation_time_secs: now_seconds(), }; - add_transaction(creator, multisig_account, multisig_account_resource, transaction); + add_transaction(creator, multisig_account, transaction); } /// Create a multisig transaction with a transaction hash instead of the full payload. @@ -923,8 +922,7 @@ module aptos_framework::multisig_account { assert!(vector::length(&payload_hash) == 32, error::invalid_argument(EINVALID_PAYLOAD_HASH)); assert_multisig_account_exists(multisig_account); - let multisig_account_resource = borrow_global_mut(multisig_account); - assert_is_owner_internal(owner, multisig_account_resource); + assert_is_owner(owner, multisig_account); let creator = address_of(owner); let transaction = MultisigTransaction { @@ -934,7 +932,7 @@ module aptos_framework::multisig_account { creator, creation_time_secs: now_seconds(), }; - add_transaction(creator, multisig_account, multisig_account_resource, transaction); + add_transaction(creator, multisig_account, transaction); } /// Approve a multisig transaction. @@ -1016,8 +1014,9 @@ module aptos_framework::multisig_account { multisig_account: address, ) acquires MultisigAccount { assert_multisig_account_exists(multisig_account); - let sequence_number = last_resolved_sequence_number(multisig_account) + 1; + assert_is_owner(owner, multisig_account); + let sequence_number = last_resolved_sequence_number(multisig_account) + 1; let owner_addr = address_of(owner); if(features::multisig_v2_enhancement_feature_enabled()) { // Implicitly vote for rejection if the owner has not voted for rejection yet. @@ -1203,33 +1202,33 @@ module aptos_framework::multisig_account { num_approvals_and_rejections_internal(&multisig_account_resource.owners, &transaction) } - fun add_transaction( + inline fun add_transaction( creator: address, - multisig_account_address: address, - multisig_account: &mut MultisigAccount, + multisig_account: address, transaction: MultisigTransaction ) { if(features::multisig_v2_enhancement_feature_enabled()) { - let num_pending_transactions = multisig_account.next_sequence_number - (multisig_account.last_executed_sequence_number + 1); assert!( - num_pending_transactions < MAX_PENDING_TRANSACTIONS, + available_transaction_queue_capacity(multisig_account) > 0, error::invalid_state(EMAX_PENDING_TRANSACTIONS_EXCEEDED) ); }; + let multisig_account_resource = borrow_global_mut(multisig_account); + // The transaction creator also automatically votes for the transaction. simple_map::add(&mut transaction.votes, creator, true); - let sequence_number = multisig_account.next_sequence_number; - multisig_account.next_sequence_number = sequence_number + 1; - table::add(&mut multisig_account.transactions, sequence_number, transaction); + let sequence_number = multisig_account_resource.next_sequence_number; + multisig_account_resource.next_sequence_number = sequence_number + 1; + table::add(&mut multisig_account_resource.transactions, sequence_number, transaction); if (std::features::module_event_migration_enabled()) { emit( - CreateTransaction { multisig_account: multisig_account_address, creator, sequence_number, transaction } + CreateTransaction { multisig_account: multisig_account, creator, sequence_number, transaction } ); }; emit_event( - &mut multisig_account.create_transaction_events, + &mut multisig_account_resource.create_transaction_events, CreateTransactionEvent { creator, sequence_number, transaction }, ); } @@ -2318,4 +2317,126 @@ module aptos_framework::multisig_account { // execute the eviction transaction to remove the compromised owner. assert!(can_be_executed(multisig_address, 11), 0); } + + #[test(owner = @0x123, non_owner = @0x234)] + #[expected_failure(abort_code = 329683, location = Self)] + public entry fun test_create_transaction_should_fail_if_not_owner( + owner: &signer, + non_owner: &signer + ) acquires MultisigAccount { + setup(); + create_account(address_of(owner)); + let multisig_account = get_next_multisig_account_address(address_of(owner)); + create(owner, 1, vector[], vector[]); + // Transaction is created with id 1. + create_transaction(non_owner, multisig_account, PAYLOAD); + } + + #[test(owner = @0x123, non_owner = @0x234)] + #[expected_failure(abort_code = 329683, location = Self)] + public entry fun test_create_transaction_with_hash_should_fail_if_not_owner( + owner: &signer, + non_owner: &signer + ) acquires MultisigAccount { + setup(); + create_account(address_of(owner)); + let multisig_account = get_next_multisig_account_address(address_of(owner)); + create(owner, 1, vector[], vector[]); + // Transaction is created with id 1. + create_transaction_with_hash(non_owner, multisig_account, sha3_256(PAYLOAD)); + } + + #[test(owner = @0x123, non_owner = @0x234)] + #[expected_failure(abort_code = 329683, location = Self)] + public entry fun test_reject_transaction_should_fail_if_not_owner( + owner: &signer, + non_owner: &signer + ) acquires MultisigAccount { + setup(); + create_account(address_of(owner)); + let multisig_account = get_next_multisig_account_address(address_of(owner)); + create(owner, 1, vector[], vector[]); + // Transaction is created with id 1. + create_transaction(owner, multisig_account, PAYLOAD); + reject_transaction(non_owner, multisig_account, 1); + } + + + #[test(owner = @0x123, non_owner = @0x234)] + #[expected_failure(abort_code = 329683, location = Self)] + public entry fun test_approve_transaction_should_fail_if_not_owner( + owner: &signer, + non_owner: &signer + ) acquires MultisigAccount { + setup(); + create_account(address_of(owner)); + let multisig_account = get_next_multisig_account_address(address_of(owner)); + create(owner, 1, vector[], vector[]); + // Transaction is created with id 1. + create_transaction(owner, multisig_account, PAYLOAD); + approve_transaction(non_owner, multisig_account, 1); + } + + #[test(owner = @0x123, non_owner = @0x234)] + #[expected_failure(abort_code = 329683, location = Self)] + public entry fun test_vote_transaction_should_fail_if_not_owner( + owner: &signer, + non_owner: &signer + ) acquires MultisigAccount { + setup(); + create_account(address_of(owner)); + let multisig_account = get_next_multisig_account_address(address_of(owner)); + create(owner, 1, vector[], vector[]); + // Transaction is created with id 1. + create_transaction(owner, multisig_account, PAYLOAD); + vote_transaction(non_owner, multisig_account, 1, true); + } + + #[test(owner = @0x123, non_owner = @0x234)] + #[expected_failure(abort_code = 329683, location = Self)] + public entry fun test_vote_transactions_should_fail_if_not_owner( + owner: &signer, + non_owner: &signer + ) acquires MultisigAccount { + setup(); + create_account(address_of(owner)); + let multisig_account = get_next_multisig_account_address(address_of(owner)); + create(owner, 1, vector[], vector[]); + // Transaction is created with id 1. + create_transaction(owner, multisig_account, PAYLOAD); + vote_transactions(non_owner, multisig_account, 1, 1, true); + } + + #[test(owner = @0x123, non_owner = @0x234)] + #[expected_failure(abort_code = 329683, location = Self)] + public entry fun test_execute_rejected_transaction_should_fail_if_not_owner( + owner: &signer, + non_owner: &signer + ) acquires MultisigAccount { + setup(); + create_account(address_of(owner)); + let multisig_account = get_next_multisig_account_address(address_of(owner)); + create(owner, 1, vector[], vector[]); + // Transaction is created with id 1. + create_transaction(owner, multisig_account, PAYLOAD); + reject_transaction(owner, multisig_account, 1); + execute_rejected_transaction(non_owner, multisig_account); + } + + + #[test(owner = @0x123, non_owner = @0x234)] + #[expected_failure(abort_code = 329683, location = Self)] + public entry fun test_execute_rejected_transactions_should_fail_if_not_owner( + owner: &signer, + non_owner: &signer + ) acquires MultisigAccount { + setup(); + create_account(address_of(owner)); + let multisig_account = get_next_multisig_account_address(address_of(owner)); + create(owner, 1, vector[], vector[]); + // Transaction is created with id 1. + create_transaction(owner, multisig_account, PAYLOAD); + reject_transaction(owner, multisig_account, 1); + execute_rejected_transactions(non_owner, multisig_account, 1); + } } diff --git a/aptos-move/framework/aptos-framework/sources/object.move b/aptos-move/framework/aptos-framework/sources/object.move index d13e07b56130a..ae31a50b56da6 100644 --- a/aptos-move/framework/aptos-framework/sources/object.move +++ b/aptos-move/framework/aptos-framework/sources/object.move @@ -29,6 +29,7 @@ module aptos_framework::object { use aptos_framework::event; use aptos_framework::guid; + friend aptos_framework::coin; friend aptos_framework::primary_fungible_store; /// An object already exists at this address @@ -201,12 +202,18 @@ module aptos_framework::object { from_bcs::to_address(hash::sha3_256(bytes)) } + native fun create_user_derived_object_address_impl(source: address, derive_from: address): address; + /// Derives an object address from the source address and an object: sha3_256([source | object addr | 0xFC]). public fun create_user_derived_object_address(source: address, derive_from: address): address { - let bytes = bcs::to_bytes(&source); - vector::append(&mut bytes, bcs::to_bytes(&derive_from)); - vector::push_back(&mut bytes, OBJECT_DERIVED_SCHEME); - from_bcs::to_address(hash::sha3_256(bytes)) + if (std::features::object_native_derived_address_enabled()) { + create_user_derived_object_address_impl(source, derive_from) + } else { + let bytes = bcs::to_bytes(&source); + vector::append(&mut bytes, bcs::to_bytes(&derive_from)); + vector::push_back(&mut bytes, OBJECT_DERIVED_SCHEME); + from_bcs::to_address(hash::sha3_256(bytes)) + } } /// Derives an object from an Account GUID. @@ -259,6 +266,14 @@ module aptos_framework::object { create_object_internal(owner_address, unique_address, false) } + /// Create a sticky object at a specific address. Only used by aptos_framework::coin. + public(friend) fun create_sticky_object_at_address( + owner_address: address, + object_address: address, + ): ConstructorRef { + create_object_internal(owner_address, object_address, false) + } + #[deprecated] /// Use `create_object` instead. /// Create a new object from a GUID generated by an account. @@ -495,13 +510,15 @@ module aptos_framework::object { inline fun transfer_raw_inner(object: address, to: address) acquires ObjectCore { let object_core = borrow_global_mut(object); if (object_core.owner != to) { - event::emit( - Transfer { - object, - from: object_core.owner, - to, - }, - ); + if (std::features::module_event_migration_enabled()) { + event::emit( + Transfer { + object, + from: object_core.owner, + to, + }, + ); + }; event::emit_event( &mut object_core.transfer_events, TransferEvent { @@ -775,6 +792,31 @@ module aptos_framework::object { assert!(auid1 == auid2, 0); } + #[test(fx = @std)] + fun test_correct_derived_object_address(fx: signer) { + use std::features; + use aptos_framework::object; + let feature = features::get_object_native_derived_address_feature(); + + let source = @0x12345; + let derive_from = @0x7890; + + features::change_feature_flags_for_testing(&fx, vector[], vector[feature]); + let in_move = object::create_user_derived_object_address(source, derive_from); + + features::change_feature_flags_for_testing(&fx, vector[feature], vector[]); + let in_native = object::create_user_derived_object_address(source, derive_from); + + assert!(in_move == in_native, 0); + + let bytes = bcs::to_bytes(&source); + vector::append(&mut bytes, bcs::to_bytes(&derive_from)); + vector::push_back(&mut bytes, OBJECT_DERIVED_SCHEME); + let directly = from_bcs::to_address(hash::sha3_256(bytes)); + + assert!(directly == in_native, 0); + } + #[test(creator = @0x123)] fun test_burn_and_unburn(creator: &signer) acquires ObjectCore, TombStone { let (hero_constructor, hero) = create_hero(creator); diff --git a/aptos-move/framework/aptos-framework/sources/object.spec.move b/aptos-move/framework/aptos-framework/sources/object.spec.move index 49ec75b3bdbe9..128fbea0227dc 100644 --- a/aptos-move/framework/aptos-framework/sources/object.spec.move +++ b/aptos-move/framework/aptos-framework/sources/object.spec.move @@ -56,6 +56,7 @@ spec aptos_framework::object { ensures [abstract] result == spec_exists_at(object); } + spec address_to_object(object: address): Object { aborts_if !exists(object); aborts_if !spec_exists_at(object); @@ -117,6 +118,13 @@ spec aptos_framework::object { ensures [abstract] result == spec_create_object_address(source, seed); } + spec fun spec_create_user_derived_object_address_impl(source: address, derive_from: address): address; + + spec create_user_derived_object_address_impl(source: address, derive_from: address): address { + pragma opaque; + ensures [abstract] result == spec_create_user_derived_object_address_impl(source, derive_from); + } + spec create_user_derived_object_address(source: address, derive_from: address): address { pragma opaque; pragma aborts_if_is_strict = false; @@ -298,6 +306,11 @@ spec aptos_framework::object { ensures result == ConstructorRef { self: obj_addr, can_delete: true }; } + spec create_sticky_object_at_address(owner_address: address, object_address: address): ConstructorRef { + // TODO(fa_migration) + pragma verify = false; + } + spec create_object_internal( creator_address: address, object: address, diff --git a/aptos-move/framework/aptos-framework/sources/primary_fungible_store.move b/aptos-move/framework/aptos-framework/sources/primary_fungible_store.move index b028dfe2010a5..d8e7a43458824 100644 --- a/aptos-move/framework/aptos-framework/sources/primary_fungible_store.move +++ b/aptos-move/framework/aptos-framework/sources/primary_fungible_store.move @@ -12,9 +12,11 @@ /// 4. The fungible asset metadata object calls `deposit` on the recipient's primary store to deposit `amount` of /// fungible asset to it. This emits an deposit event. module aptos_framework::primary_fungible_store { + use aptos_framework::dispatchable_fungible_asset; use aptos_framework::fungible_asset::{Self, FungibleAsset, FungibleStore, Metadata, MintRef, TransferRef, BurnRef}; use aptos_framework::object::{Self, Object, ConstructorRef, DeriveRef}; + use std::features; use std::option::Option; use std::signer; use std::string::String; @@ -74,8 +76,12 @@ module aptos_framework::primary_fungible_store { let metadata_addr = object::object_address(&metadata); object::address_to_object(metadata_addr); let derive_ref = &borrow_global(metadata_addr).metadata_derive_ref; - let constructor_ref = &object::create_user_derived_object(owner_addr, derive_ref); - + let constructor_ref = if (metadata_addr == @aptos_fungible_asset && features::primary_apt_fungible_store_at_user_address_enabled( + )) { + &object::create_sticky_object_at_address(owner_addr, owner_addr) + } else { + &object::create_user_derived_object(owner_addr, derive_ref) + }; // Disable ungated transfer as deterministic stores shouldn't be transferrable. let transfer_ref = &object::generate_transfer_ref(constructor_ref); object::disable_ungated_transfer(transfer_ref); @@ -87,7 +93,11 @@ module aptos_framework::primary_fungible_store { /// Get the address of the primary store for the given account. public fun primary_store_address(owner: address, metadata: Object): address { let metadata_addr = object::object_address(&metadata); - object::create_user_derived_object_address(owner, metadata_addr) + if (metadata_addr == @aptos_fungible_asset && features::primary_apt_fungible_store_at_user_address_enabled()) { + owner + } else { + object::create_user_derived_object_address(owner, metadata_addr) + } } #[view] @@ -113,6 +123,15 @@ module aptos_framework::primary_fungible_store { } } + #[view] + public fun is_balance_at_least(account: address, metadata: Object, amount: u64): bool { + if (primary_store_exists(account, metadata)) { + fungible_asset::is_balance_at_least(primary_store(account, metadata), amount) + } else { + amount == 0 + } + } + #[view] /// Return whether the given account's primary store is frozen. public fun is_frozen(account: address, metadata: Object): bool { @@ -124,18 +143,25 @@ module aptos_framework::primary_fungible_store { } /// Withdraw `amount` of fungible asset from the given account's primary store. - public fun withdraw(owner: &signer, metadata: Object, amount: u64): FungibleAsset { - let store = primary_store(signer::address_of(owner), metadata); + public fun withdraw(owner: &signer, metadata: Object, amount: u64): FungibleAsset acquires DeriveRefPod { + let store = ensure_primary_store_exists(signer::address_of(owner), metadata); // Check if the store object has been burnt or not. If so, unburn it first. may_be_unburn(owner, store); - fungible_asset::withdraw(owner, store, amount) + dispatchable_fungible_asset::withdraw(owner, store, amount) } /// Deposit fungible asset `fa` to the given account's primary store. public fun deposit(owner: address, fa: FungibleAsset) acquires DeriveRefPod { let metadata = fungible_asset::asset_metadata(&fa); let store = ensure_primary_store_exists(owner, metadata); - fungible_asset::deposit(store, fa); + dispatchable_fungible_asset::deposit(store, fa); + } + + /// Deposit fungible asset `fa` to the given account's primary store. + public(friend) fun force_deposit(owner: address, fa: FungibleAsset) acquires DeriveRefPod { + let metadata = fungible_asset::asset_metadata(&fa); + let store = ensure_primary_store_exists(owner, metadata); + fungible_asset::deposit_internal(store, fa); } /// Transfer `amount` of fungible asset from sender's primary store to receiver's primary store. @@ -149,7 +175,29 @@ module aptos_framework::primary_fungible_store { // Check if the sender store object has been burnt or not. If so, unburn it first. may_be_unburn(sender, sender_store); let recipient_store = ensure_primary_store_exists(recipient, metadata); - fungible_asset::transfer(sender, sender_store, recipient_store, amount); + dispatchable_fungible_asset::transfer(sender, sender_store, recipient_store, amount); + } + + /// Transfer `amount` of fungible asset from sender's primary store to receiver's primary store. + /// Use the minimum deposit assertion api to make sure receipient will receive a minimum amount of fund. + public entry fun transfer_assert_minimum_deposit( + sender: &signer, + metadata: Object, + recipient: address, + amount: u64, + expected: u64, + ) acquires DeriveRefPod { + let sender_store = ensure_primary_store_exists(signer::address_of(sender), metadata); + // Check if the sender store object has been burnt or not. If so, unburn it first. + may_be_unburn(sender, sender_store); + let recipient_store = ensure_primary_store_exists(recipient, metadata); + dispatchable_fungible_asset::transfer_assert_minimum_deposit( + sender, + sender_store, + recipient_store, + amount, + expected + ); } /// Mint to the primary store of `owner`. @@ -204,7 +252,12 @@ module aptos_framework::primary_fungible_store { } #[test_only] - use aptos_framework::fungible_asset::{create_test_token, generate_mint_ref, generate_burn_ref, generate_transfer_ref}; + use aptos_framework::fungible_asset::{ + create_test_token, + generate_mint_ref, + generate_burn_ref, + generate_transfer_ref + }; #[test_only] use std::string; #[test_only] @@ -275,6 +328,25 @@ module aptos_framework::primary_fungible_store { assert!(balance(aaron_address, metadata) == 0, 7); } + #[test(creator = @0xcafe, aaron = @0xface)] + fun test_basic_flow_with_min_balance( + creator: &signer, + aaron: &signer, + ) acquires DeriveRefPod { + let (creator_ref, metadata) = create_test_token(creator); + let (mint_ref, _transfer_ref, _) = init_test_metadata_with_primary_store_enabled(&creator_ref); + let creator_address = signer::address_of(creator); + let aaron_address = signer::address_of(aaron); + assert!(balance(creator_address, metadata) == 0, 1); + assert!(balance(aaron_address, metadata) == 0, 2); + mint(&mint_ref, creator_address, 100); + transfer_assert_minimum_deposit(creator, metadata, aaron_address, 80, 80); + let fa = withdraw(aaron, metadata, 10); + deposit(creator_address, fa); + assert!(balance(creator_address, metadata) == 30, 3); + assert!(balance(aaron_address, metadata) == 70, 4); + } + #[test(user_1 = @0xcafe, user_2 = @0xface)] fun test_transfer_to_burnt_store( user_1: &signer, diff --git a/aptos-move/framework/aptos-framework/sources/primary_fungible_store.spec.move b/aptos-move/framework/aptos-framework/sources/primary_fungible_store.spec.move index b83d7d6887442..7d1448a3a54f7 100644 --- a/aptos-move/framework/aptos-framework/sources/primary_fungible_store.spec.move +++ b/aptos-move/framework/aptos-framework/sources/primary_fungible_store.spec.move @@ -128,4 +128,19 @@ spec aptos_framework::primary_fungible_store { // TODO: verification disabled until this module is specified. pragma verify = false; } + + spec fun spec_primary_store_exists(account: address, metadata: Object): bool { + fungible_asset::store_exists(spec_primary_store_address(account, metadata)) + } + + spec fun spec_primary_store_address(owner: address, metadata: Object): address { + let metadata_addr = object::object_address(metadata); + if (metadata_addr == @aptos_fungible_asset && features::spec_is_enabled( + features::PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS + )) { + owner + } else { + object::spec_create_user_derived_object_address(owner, metadata_addr) + } + } } diff --git a/aptos-move/framework/aptos-framework/sources/randomness.move b/aptos-move/framework/aptos-framework/sources/randomness.move index 48e6f7a4f5753..e479b6e30c84b 100644 --- a/aptos-move/framework/aptos-framework/sources/randomness.move +++ b/aptos-move/framework/aptos-framework/sources/randomness.move @@ -23,8 +23,8 @@ module aptos_framework::randomness { const DST: vector = b"APTOS_RANDOMNESS"; /// Randomness APIs calls must originate from a private entry function with - /// `#[randomness]` annotation. Otherwise, test-and-abort attacks are possible. - const E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT: u64 = 1; + /// `#[randomness]` annotation. Otherwise, malicious users can bias randomness result. + const E_API_USE_IS_BIASIBLE: u64 = 1; const MAX_U256: u256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935; @@ -74,7 +74,7 @@ module aptos_framework::randomness { /// Generate the next 32 random bytes. Repeated calls will yield different results (assuming the collision-resistance /// of the hash function). fun next_32_bytes(): vector acquires PerBlockRandomness { - assert!(is_unbiasable(), E_API_USE_SUSCEPTIBLE_TO_TEST_AND_ABORT); + assert!(is_unbiasable(), E_API_USE_IS_BIASIBLE); let input = DST; let randomness = borrow_global(@aptos_framework); diff --git a/aptos-move/framework/aptos-framework/sources/reconfiguration_with_dkg.move b/aptos-move/framework/aptos-framework/sources/reconfiguration_with_dkg.move index b5a842bff5337..1357c4edbad46 100644 --- a/aptos-move/framework/aptos-framework/sources/reconfiguration_with_dkg.move +++ b/aptos-move/framework/aptos-framework/sources/reconfiguration_with_dkg.move @@ -8,11 +8,14 @@ module aptos_framework::reconfiguration_with_dkg { use aptos_framework::gas_schedule; use aptos_framework::jwk_consensus_config; use aptos_framework::jwks; + use aptos_framework::keyless_account; + use aptos_framework::randomness_api_v0_config; use aptos_framework::randomness_config; use aptos_framework::randomness_config_seqnum; use aptos_framework::reconfiguration; use aptos_framework::reconfiguration_state; use aptos_framework::stake; + use aptos_framework::system_addresses; friend aptos_framework::block; friend aptos_framework::aptos_governance; @@ -40,17 +43,20 @@ module aptos_framework::reconfiguration_with_dkg { /// Apply buffered on-chain configs (except for ValidatorSet, which is done inside `reconfiguration::reconfigure()`). /// Re-enable validator set changes. /// Run the default reconfiguration to enter the new epoch. - public(friend) fun finish(account: &signer) { - dkg::try_clear_incomplete_session(account); - consensus_config::on_new_epoch(); - execution_config::on_new_epoch(); - gas_schedule::on_new_epoch(); - std::version::on_new_epoch(); - jwk_consensus_config::on_new_epoch(); - jwks::on_new_epoch(); - randomness_config_seqnum::on_new_epoch(); - randomness_config::on_new_epoch(); - features::on_new_epoch(account); + public(friend) fun finish(framework: &signer) { + system_addresses::assert_aptos_framework(framework); + dkg::try_clear_incomplete_session(framework); + consensus_config::on_new_epoch(framework); + execution_config::on_new_epoch(framework); + gas_schedule::on_new_epoch(framework); + std::version::on_new_epoch(framework); + features::on_new_epoch(framework); + jwk_consensus_config::on_new_epoch(framework); + jwks::on_new_epoch(framework); + keyless_account::on_new_epoch(framework); + randomness_config_seqnum::on_new_epoch(framework); + randomness_config::on_new_epoch(framework); + randomness_api_v0_config::on_new_epoch(framework); reconfiguration::reconfigure(); } diff --git a/aptos-move/framework/aptos-framework/sources/reconfiguration_with_dkg.spec.move b/aptos-move/framework/aptos-framework/sources/reconfiguration_with_dkg.spec.move index e86a2cd233c56..9bbbc3604601e 100644 --- a/aptos-move/framework/aptos-framework/sources/reconfiguration_with_dkg.spec.move +++ b/aptos-move/framework/aptos-framework/sources/reconfiguration_with_dkg.spec.move @@ -18,9 +18,10 @@ spec aptos_framework::reconfiguration_with_dkg { pragma verify_duration_estimate = 600; // TODO: set because of timeout (property proved). } - spec finish(account: &signer) { - pragma verify = false; // TODO: set because of timeout (property proved). + spec finish(framework: &signer) { + pragma verify_duration_estimate = 1500; include FinishRequirement; + aborts_if false; } spec schema FinishRequirement { @@ -40,8 +41,8 @@ spec aptos_framework::reconfiguration_with_dkg { use aptos_framework::jwks; use aptos_framework::randomness_config; use aptos_framework::jwk_consensus_config; - account: signer; - requires signer::address_of(account) == @aptos_framework; + framework: signer; + requires signer::address_of(framework) == @aptos_framework; requires chain_status::is_operating(); requires exists>(@aptos_framework); include staking_config::StakingRewardsConfigRequirement; @@ -54,15 +55,19 @@ spec aptos_framework::reconfiguration_with_dkg { include config_buffer::OnNewEpochRequirement; include config_buffer::OnNewEpochRequirement; include config_buffer::OnNewEpochRequirement; + include config_buffer::OnNewEpochRequirement; + include config_buffer::OnNewEpochRequirement; include config_buffer::OnNewEpochRequirement; - - aborts_if false; + include config_buffer::OnNewEpochRequirement; + include config_buffer::OnNewEpochRequirement; } spec finish_with_dkg_result(account: &signer, dkg_result: vector) { use aptos_framework::dkg; - pragma verify = false; // TODO: set because of timeout (property proved). - include FinishRequirement; + pragma verify_duration_estimate = 1500; + include FinishRequirement { + framework: account + }; requires dkg::has_incomplete_session(); aborts_if false; } diff --git a/aptos-move/framework/aptos-framework/sources/resource_account.move b/aptos-move/framework/aptos-framework/sources/resource_account.move index 7f85a8bf05417..3d8dc60e70d77 100644 --- a/aptos-move/framework/aptos-framework/sources/resource_account.move +++ b/aptos-move/framework/aptos-framework/sources/resource_account.move @@ -172,7 +172,10 @@ module aptos_framework::resource_account { let resource_addr = signer::address_of(resource); let (resource_signer_cap, empty_container) = { let container = borrow_global_mut(source_addr); - assert!(simple_map::contains_key(&container.store, &resource_addr), error::invalid_argument(EUNAUTHORIZED_NOT_OWNER)); + assert!( + simple_map::contains_key(&container.store, &resource_addr), + error::invalid_argument(EUNAUTHORIZED_NOT_OWNER) + ); let (_resource_addr, signer_cap) = simple_map::remove(&mut container.store, &resource_addr); (signer_cap, simple_map::length(&container.store) == 0) }; @@ -206,7 +209,9 @@ module aptos_framework::resource_account { #[test(user = @0x1111)] #[expected_failure(abort_code = 0x10002, location = aptos_std::simple_map)] - public entry fun test_create_account_and_retrieve_cap_resource_address_does_not_exist(user: signer) acquires Container { + public entry fun test_create_account_and_retrieve_cap_resource_address_does_not_exist( + user: signer + ) acquires Container { let user_addr = signer::address_of(&user); account::create_account(user_addr); diff --git a/aptos-move/framework/aptos-framework/sources/resource_account.spec.move b/aptos-move/framework/aptos-framework/sources/resource_account.spec.move index 36e270487130d..a6f4d6848a50a 100644 --- a/aptos-move/framework/aptos-framework/sources/resource_account.spec.move +++ b/aptos-move/framework/aptos-framework/sources/resource_account.spec.move @@ -80,6 +80,8 @@ spec aptos_framework::resource_account { fund_amount: u64, ) { use aptos_framework::aptos_account; + // TODO(fa_migration) + pragma verify = false; let source_addr = signer::address_of(origin); let resource_addr = account::spec_create_resource_address(source_addr, seed); let coin_store_resource = global>(resource_addr); @@ -89,7 +91,7 @@ spec aptos_framework::resource_account { include RotateAccountAuthenticationKeyAndStoreCapabilityAbortsIfWithoutAccountLimit; //coin property - aborts_if coin::is_account_registered(resource_addr) && coin_store_resource.frozen; + aborts_if coin::spec_is_account_registered(resource_addr) && coin_store_resource.frozen; /// [high-level-req-3] ensures exists>(resource_addr); } diff --git a/aptos-move/framework/aptos-framework/sources/stake.spec.move b/aptos-move/framework/aptos-framework/sources/stake.spec.move index 2d9db10e591d9..5d023400860bb 100644 --- a/aptos-move/framework/aptos-framework/sources/stake.spec.move +++ b/aptos-move/framework/aptos-framework/sources/stake.spec.move @@ -228,6 +228,8 @@ spec aptos_framework::stake { withdraw_amount: u64 ) { + // TODO(fa_migration) + pragma verify = false; aborts_if reconfiguration_state::spec_is_in_progress(); let addr = signer::address_of(owner); let ownership_cap = global(addr); @@ -688,6 +690,10 @@ spec aptos_framework::stake { } spec add_stake { + // TODO: These function passed locally however failed in github CI + pragma verify_duration_estimate = 120; + // TODO(fa_migration) + pragma aborts_if_is_partial; aborts_if reconfiguration_state::spec_is_in_progress(); include ResourceRequirement; include AddStakeAbortsIfAndEnsures; @@ -820,12 +826,6 @@ spec aptos_framework::stake { let owner_address = signer::address_of(owner); aborts_if !exists(owner_address); - include coin::WithdrawAbortsIf{ account: owner }; - let coin_store = global>(owner_address); - let balance = coin_store.coin.value; - let post coin_post = global>(owner_address).coin.value; - ensures coin_post == balance - amount; - let owner_cap = global(owner_address); include AddStakeWithCapAbortsIfAndEnsures { owner_cap }; } diff --git a/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move b/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move index 31ee882715c71..0f7caf7af2aa4 100644 --- a/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move +++ b/aptos-move/framework/aptos-framework/sources/staking_contract.spec.move @@ -76,6 +76,7 @@ spec aptos_framework::staking_contract { include ContractExistsAbortsIf; let staking_contracts = global(staker).staking_contracts; ensures result == simple_map::spec_get(staking_contracts, operator).pool_address; + } /// Staking_contract exists the stacker/operator pair. @@ -185,6 +186,7 @@ spec aptos_framework::staking_contract { /// Account is not frozen and sufficient to withdraw. /// Staking_contract exists the stacker/operator pair. spec add_stake(staker: &signer, operator: address, amount: u64) { + // TODO(fa_migration) use aptos_framework::reconfiguration_state; pragma verify_duration_estimate = 600; // TODO: this function times out @@ -296,6 +298,8 @@ spec aptos_framework::staking_contract { old_operator: address, new_operator: address, ) { + // TODO: These function passed locally however failed in github CI + pragma verify_duration_estimate = 120; // TODO: Call `update_distribution_pool` and could not verify `update_distribution_pool`. pragma aborts_if_is_partial; let staker_address = signer::address_of(staker); @@ -331,8 +335,11 @@ spec aptos_framework::staking_contract { /// Staking_contract exists the stacker/operator pair. spec distribute(staker: address, operator: address) { + // TODO: These function passed locally however failed in github CI + pragma verify_duration_estimate = 120; // TODO: Call `distribute_internal` and could not verify `update_distribution_pool`. pragma aborts_if_is_partial; + include ContractExistsAbortsIf; } @@ -344,6 +351,8 @@ spec aptos_framework::staking_contract { staking_contract: &mut StakingContract, distribute_events: &mut EventHandle, ) { + // TODO: These function passed locally however failed in github CI + pragma verify_duration_estimate = 120; // TODO: Call `update_distribution_pool` and could not verify `update_distribution_pool`. pragma aborts_if_is_partial; let pool_address = staking_contract.pool_address; diff --git a/aptos-move/framework/aptos-framework/sources/transaction_context.move b/aptos-move/framework/aptos-framework/sources/transaction_context.move index 5ebf64643bae1..a88e12d373416 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_context.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_context.move @@ -1,21 +1,47 @@ module aptos_framework::transaction_context { + use std::error; + use std::features; + use std::option::Option; + use std::string::String; + + /// Transaction context is only available in the user transaction prologue, execution, or epilogue phases. + const ETRANSACTION_CONTEXT_NOT_AVAILABLE: u64 = 1; + + /// The transaction context extension feature is not enabled. + const ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED: u64 = 2; + /// A wrapper denoting aptos unique identifer (AUID) /// for storing an address struct AUID has drop, store { unique_address: address } - /// Return the transaction hash of the current transaction. + /// Represents the entry function payload. + struct EntryFunctionPayload has copy, drop { + account_address: address, + module_name: String, + function_name: String, + ty_args_names: vector, + args: vector>, + } + + /// Represents the multisig payload. + struct MultisigPayload has copy, drop { + multisig_address: address, + entry_function_payload: Option, + } + + /// Returns the transaction hash of the current transaction. native fun get_txn_hash(): vector; - /// Return the transaction hash of the current transaction. + /// Returns the transaction hash of the current transaction. /// Internally calls the private function `get_txn_hash`. /// This function is created for to feature gate the `get_txn_hash` function. public fun get_transaction_hash(): vector { get_txn_hash() } - /// Return a universally unique identifier (of type address) generated + /// Returns a universally unique identifier (of type address) generated /// by hashing the transaction hash of this transaction and a sequence number /// specific to this transaction. This function can be called any /// number of times inside a single transaction. Each such call increments @@ -24,14 +50,14 @@ module aptos_framework::transaction_context { /// from other ways of generating unique addresses. native fun generate_unique_address(): address; - /// Return a aptos unique identifier. Internally calls + /// Returns a aptos unique identifier. Internally calls /// the private function `generate_unique_address`. This function is /// created for to feature gate the `generate_unique_address` function. public fun generate_auid_address(): address { generate_unique_address() } - /// Return the script hash of the current entry function. + /// Returns the script hash of the current entry function. public native fun get_script_hash(): vector; /// This method runs `generate_unique_address` native function and returns @@ -42,10 +68,120 @@ module aptos_framework::transaction_context { } } + /// Returns the unique address wrapped in the given AUID struct. public fun auid_address(auid: &AUID): address { auid.unique_address } + /// Returns the sender's address for the current transaction. + /// This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + public fun sender(): address { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + sender_internal() + } + native fun sender_internal(): address; + + /// Returns the list of the secondary signers for the current transaction. + /// If the current transaction has no secondary signers, this function returns an empty vector. + /// This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + public fun secondary_signers(): vector
{ + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + secondary_signers_internal() + } + native fun secondary_signers_internal(): vector
; + + /// Returns the gas payer address for the current transaction. + /// It is either the sender's address if no separate gas fee payer is specified for the current transaction, + /// or the address of the separate gas fee payer if one is specified. + /// This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + public fun gas_payer(): address { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + gas_payer_internal() + } + native fun gas_payer_internal(): address; + + /// Returns the max gas amount in units which is specified for the current transaction. + /// This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + public fun max_gas_amount(): u64 { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + max_gas_amount_internal() + } + native fun max_gas_amount_internal(): u64; + + /// Returns the gas unit price in Octas which is specified for the current transaction. + /// This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + public fun gas_unit_price(): u64 { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + gas_unit_price_internal() + } + native fun gas_unit_price_internal(): u64; + + /// Returns the chain ID specified for the current transaction. + /// This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + public fun chain_id(): u8 { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + chain_id_internal() + } + native fun chain_id_internal(): u8; + + /// Returns the entry function payload if the current transaction has such a payload. Otherwise, return `None`. + /// This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + public fun entry_function_payload(): Option { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + entry_function_payload_internal() + } + native fun entry_function_payload_internal(): Option; + + /// Returns the account address of the entry function payload. + public fun account_address(payload: &EntryFunctionPayload): address { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + payload.account_address + } + + /// Returns the module name of the entry function payload. + public fun module_name(payload: &EntryFunctionPayload): String { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + payload.module_name + } + + /// Returns the function name of the entry function payload. + public fun function_name(payload: &EntryFunctionPayload): String { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + payload.function_name + } + + /// Returns the type arguments names of the entry function payload. + public fun type_arg_names(payload: &EntryFunctionPayload): vector { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + payload.ty_args_names + } + + /// Returns the arguments of the entry function payload. + public fun args(payload: &EntryFunctionPayload): vector> { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + payload.args + } + + /// Returns the multisig payload if the current transaction has such a payload. Otherwise, return `None`. + /// This function aborts if called outside of the transaction prologue, execution, or epilogue phases. + public fun multisig_payload(): Option { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + multisig_payload_internal() + } + native fun multisig_payload_internal(): Option; + + /// Returns the multisig account address of the multisig payload. + public fun multisig_address(payload: &MultisigPayload): address { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + payload.multisig_address + } + + /// Returns the inner entry function payload of the multisig payload. + public fun inner_entry_function_payload(payload: &MultisigPayload): Option { + assert!(features::transaction_context_extension_enabled(), error::invalid_state(ETRANSACTION_CONTEXT_EXTENSION_NOT_ENABLED)); + payload.entry_function_payload + } + #[test(fx = @std)] fun test_auid_uniquess(fx: signer) { use std::features; @@ -71,4 +207,60 @@ module aptos_framework::transaction_context { i = i + 1; }; } + + #[test] + #[expected_failure(abort_code=196609, location = Self)] + fun test_call_sender() { + // expected to fail with the error code of `invalid_state(E_TRANSACTION_CONTEXT_NOT_AVAILABLE)` + let _sender = sender(); + } + + #[test] + #[expected_failure(abort_code=196609, location = Self)] + fun test_call_secondary_signers() { + // expected to fail with the error code of `invalid_state(E_TRANSACTION_CONTEXT_NOT_AVAILABLE)` + let _secondary_signers = secondary_signers(); + } + + #[test] + #[expected_failure(abort_code=196609, location = Self)] + fun test_call_gas_payer() { + // expected to fail with the error code of `invalid_state(E_TRANSACTION_CONTEXT_NOT_AVAILABLE)` + let _gas_payer = gas_payer(); + } + + #[test] + #[expected_failure(abort_code=196609, location = Self)] + fun test_call_max_gas_amount() { + // expected to fail with the error code of `invalid_state(E_TRANSACTION_CONTEXT_NOT_AVAILABLE)` + let _max_gas_amount = max_gas_amount(); + } + + #[test] + #[expected_failure(abort_code=196609, location = Self)] + fun test_call_gas_unit_price() { + // expected to fail with the error code of `invalid_state(E_TRANSACTION_CONTEXT_NOT_AVAILABLE)` + let _gas_unit_price = gas_unit_price(); + } + + #[test] + #[expected_failure(abort_code=196609, location = Self)] + fun test_call_chain_id() { + // expected to fail with the error code of `invalid_state(E_TRANSACTION_CONTEXT_NOT_AVAILABLE)` + let _chain_id = chain_id(); + } + + #[test] + #[expected_failure(abort_code=196609, location = Self)] + fun test_call_entry_function_payload() { + // expected to fail with the error code of `invalid_state(E_TRANSACTION_CONTEXT_NOT_AVAILABLE)` + let _entry_fun = entry_function_payload(); + } + + #[test] + #[expected_failure(abort_code=196609, location = Self)] + fun test_call_multisig_payload() { + // expected to fail with the error code of `invalid_state(E_TRANSACTION_CONTEXT_NOT_AVAILABLE)` + let _multisig = multisig_payload(); + } } diff --git a/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move b/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move index a175984c99bb5..f9837e26e6a75 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_context.spec.move @@ -72,4 +72,38 @@ spec aptos_framework::transaction_context { /// [high-level-req-2] aborts_if false; } + + spec sender_internal(): address { + //TODO: temporary mockup + pragma opaque; + } + spec secondary_signers_internal(): vector
{ + //TODO: temporary mockup + pragma opaque; + } + spec gas_payer_internal(): address { + //TODO: temporary mockup + pragma opaque; + } + spec max_gas_amount_internal(): u64 { + //TODO: temporary mockup + pragma opaque; + } + spec gas_unit_price_internal(): u64 { + //TODO: temporary mockup + pragma opaque; + } + spec chain_id_internal(): u8 { + //TODO: temporary mockup + pragma opaque; + } + spec entry_function_payload_internal(): Option { + //TODO: temporary mockup + pragma opaque; + } + + spec multisig_payload_internal(): Option { + //TODO: temporary mockup + pragma opaque; + } } diff --git a/aptos-move/framework/aptos-framework/sources/transaction_fee.move b/aptos-move/framework/aptos-framework/sources/transaction_fee.move index 2e7d34ad09e53..239a45b9babf0 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_fee.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_fee.move @@ -247,6 +247,8 @@ module aptos_framework::transaction_fee { #[test_only] use aptos_framework::aggregator_factory; + #[test_only] + use aptos_framework::object; #[test(aptos_framework = @aptos_framework)] fun test_initialize_fee_collection_and_distribution(aptos_framework: signer) acquires CollectedFeesPerBlock { @@ -324,6 +326,7 @@ module aptos_framework::transaction_fee { aptos_account::create_account(alice_addr); aptos_account::create_account(bob_addr); aptos_account::create_account(carol_addr); + assert!(object::object_address(&coin::ensure_paired_metadata()) == @aptos_fungible_asset, 0); coin::deposit(alice_addr, coin::mint(10000, &mint_cap)); coin::deposit(bob_addr, coin::mint(10000, &mint_cap)); coin::deposit(carol_addr, coin::mint(10000, &mint_cap)); diff --git a/aptos-move/framework/aptos-framework/sources/transaction_fee.spec.move b/aptos-move/framework/aptos-framework/sources/transaction_fee.spec.move index 6adc9fcbec513..dbdacb60260df 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_fee.spec.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_fee.spec.move @@ -198,7 +198,8 @@ spec aptos_framework::transaction_fee { use aptos_framework::optional_aggregator; use aptos_framework::coin; use aptos_framework::coin::{CoinInfo, CoinStore}; - + // TODO(fa_migration) + pragma verify = false; aborts_if !exists(@aptos_framework); @@ -210,7 +211,7 @@ spec aptos_framework::transaction_fee { let coin_store = global>(account_addr); let post post_coin_store = global>(account_addr); - modifies global>(account_addr); + // modifies global>(account_addr); aborts_if amount != 0 && !(exists>(aptos_addr) && exists>(account_addr)); @@ -240,16 +241,17 @@ spec aptos_framework::transaction_fee { use aptos_framework::aptos_coin::AptosCoin; use aptos_framework::coin::{CoinInfo, CoinStore}; use aptos_framework::coin; - - pragma opaque; + // TODO(fa_migration) + pragma verify = false; + // pragma opaque; let aptos_addr = type_info::type_of().account_address; - modifies global>(aptos_addr); + aborts_if (refund != 0) && !exists>(aptos_addr); include coin::CoinAddAbortsIf { amount: refund }; aborts_if !exists>(account); - modifies global>(account); + // modifies global>(account); aborts_if !exists(@aptos_framework); @@ -261,6 +263,8 @@ spec aptos_framework::transaction_fee { spec collect_fee(account: address, fee: u64) { use aptos_framework::aggregator; + // TODO(fa_migration) + pragma verify = false; let collected_fees = global(@aptos_framework).amount; let aggr = collected_fees.value; diff --git a/aptos-move/framework/aptos-framework/sources/transaction_validation.move b/aptos-move/framework/aptos-framework/sources/transaction_validation.move index b5797184ca96d..acd2fc809dd27 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_validation.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_validation.move @@ -155,8 +155,10 @@ module aptos_framework::transaction_validation { coin::is_account_registered(gas_payer), error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), ); - let balance = coin::balance(gas_payer); - assert!(balance >= max_transaction_fee, error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT)); + assert!( + coin::is_balance_at_least(gas_payer, max_transaction_fee), + error::invalid_argument(PROLOGUE_ECANT_PAY_GAS_DEPOSIT) + ); } fun script_prologue( @@ -370,7 +372,7 @@ module aptos_framework::transaction_validation { // it's important to maintain the error code consistent with vm // to do failed transaction cleanup. assert!( - coin::balance(gas_payer) >= transaction_fee_amount, + coin::is_balance_at_least(gas_payer, transaction_fee_amount), error::out_of_range(PROLOGUE_ECANT_PAY_GAS_DEPOSIT), ); diff --git a/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move b/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move index 918dbe02ed31e..f50b7b7b0dc15 100644 --- a/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move +++ b/aptos-move/framework/aptos-framework/sources/transaction_validation.spec.move @@ -107,7 +107,8 @@ spec aptos_framework::transaction_validation { txn_expiration_time: u64, chain_id: u8, ) { - + // TODO(fa_migration) + pragma verify = false; include PrologueCommonAbortsIf; } @@ -121,6 +122,8 @@ spec aptos_framework::transaction_validation { chain_id: u8, _script_hash: vector, ) { + // TODO(fa_migration) + pragma verify = false; include PrologueCommonAbortsIf { gas_payer: signer::address_of(sender), txn_authentication_key: txn_public_key @@ -175,6 +178,8 @@ spec aptos_framework::transaction_validation { ) { pragma verify_duration_estimate = 120; let gas_payer = signer::address_of(sender); + // TODO(fa_migration) + pragma verify = false; include PrologueCommonAbortsIf { gas_payer, txn_sequence_number, @@ -228,6 +233,8 @@ spec aptos_framework::transaction_validation { txn_max_gas_units: u64, gas_units_remaining: u64 ) { + // TODO(fa_migration) + pragma verify = false; include EpilogueGasPayerAbortsIf { gas_payer: signer::address_of(account) }; } @@ -242,6 +249,8 @@ spec aptos_framework::transaction_validation { txn_max_gas_units: u64, gas_units_remaining: u64 ) { + // TODO(fa_migration) + pragma verify = false; include EpilogueGasPayerAbortsIf; } @@ -271,16 +280,17 @@ spec aptos_framework::transaction_validation { // Check account invariants. let addr = signer::address_of(account); - let pre_balance = global>(gas_payer).coin.value; - let post balance = global>(gas_payer).coin.value; + // TODO(fa_migration) + // let pre_balance = global>(gas_payer).coin.value; + // let post balance = global>(gas_payer).coin.value; let pre_account = global(addr); let post account = global(addr); aborts_if !exists>(gas_payer); aborts_if !exists(addr); aborts_if !(global(addr).sequence_number < MAX_U64); - aborts_if pre_balance < transaction_fee_amount; - ensures balance == pre_balance - transaction_fee_amount + storage_fee_refunded; + // aborts_if pre_balance < transaction_fee_amount; + // ensures balance == pre_balance - transaction_fee_amount + storage_fee_refunded; ensures account.sequence_number == pre_account.sequence_number + 1; diff --git a/aptos-move/framework/aptos-framework/sources/vesting.spec.move b/aptos-move/framework/aptos-framework/sources/vesting.spec.move index 8781782badd82..bd003945ded17 100644 --- a/aptos-move/framework/aptos-framework/sources/vesting.spec.move +++ b/aptos-move/framework/aptos-framework/sources/vesting.spec.move @@ -396,6 +396,8 @@ spec aptos_framework::vesting { contract_address: address, new_voter: address, ) { + // TODO: set because of timeout (property proved) + pragma verify_duration_estimate = 300; include VerifyAdminAbortsIf; let vesting_contract = global(contract_address); @@ -433,8 +435,9 @@ spec aptos_framework::vesting { shareholder: address, new_beneficiary: address, ) { + pragma aborts_if_is_partial; aborts_if !account::exists_at(new_beneficiary); - aborts_if !coin::is_account_registered(new_beneficiary); + aborts_if !coin::spec_is_account_registered(new_beneficiary); include VerifyAdminAbortsIf; let post vesting_contract = global(contract_address); ensures simple_map::spec_contains_key(vesting_contract.beneficiaries,shareholder); diff --git a/aptos-move/framework/aptos-framework/tests/aptos_coin_tests.move b/aptos-move/framework/aptos-framework/tests/aptos_coin_tests.move new file mode 100644 index 0000000000000..7c3325c3e8b08 --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/aptos_coin_tests.move @@ -0,0 +1,49 @@ +#[test_only] +module aptos_framework::aptos_coin_tests { + use aptos_framework::aptos_coin; + use aptos_framework::coin; + use aptos_framework::fungible_asset::{Self, FungibleStore, Metadata}; + use aptos_framework::primary_fungible_store; + use aptos_framework::object::{Self, Object}; + + public fun mint_apt_fa_to_for_test(store: Object, amount: u64) { + fungible_asset::deposit(store, aptos_coin::mint_apt_fa_for_test(amount)); + } + + public fun mint_apt_fa_to_primary_fungible_store_for_test( + owner: address, + amount: u64, + ) { + primary_fungible_store::deposit(owner, aptos_coin::mint_apt_fa_for_test(amount)); + } + + #[test(aptos_framework = @aptos_framework)] + fun test_apt_setup_and_mint(aptos_framework: &signer) { + let (burn_cap, mint_cap) = aptos_coin::initialize_for_test(aptos_framework); + let coin = coin::mint(100, &mint_cap); + let fa = coin::coin_to_fungible_asset(coin); + primary_fungible_store::deposit(@aptos_framework, fa); + assert!( + primary_fungible_store::balance( + @aptos_framework, + object::address_to_object(@aptos_fungible_asset) + ) == 100, + 0 + ); + coin::destroy_mint_cap(mint_cap); + coin::destroy_burn_cap(burn_cap); + } + + #[test] + fun test_fa_helpers_for_test() { + assert!(!object::object_exists(@aptos_fungible_asset), 0); + aptos_coin::ensure_initialized_with_apt_fa_metadata_for_test(); + assert!(object::object_exists(@aptos_fungible_asset), 0); + mint_apt_fa_to_primary_fungible_store_for_test(@aptos_framework, 100); + let metadata = object::address_to_object(@aptos_fungible_asset); + assert!(primary_fungible_store::balance(@aptos_framework, metadata) == 100, 0); + let store_addr = primary_fungible_store::primary_store_address(@aptos_framework, metadata); + mint_apt_fa_to_for_test(object::address_to_object(store_addr), 100); + assert!(primary_fungible_store::balance(@aptos_framework, metadata) == 200, 0); + } +} diff --git a/aptos-move/framework/aptos-framework/tests/deflation_token.move b/aptos-move/framework/aptos-framework/tests/deflation_token.move new file mode 100644 index 0000000000000..fa98e45a27e85 --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/deflation_token.move @@ -0,0 +1,78 @@ +#[test_only] +module 0xcafe::deflation_token { + use aptos_framework::fungible_asset::{Self, BurnRef, FungibleAsset, TransferRef}; + use aptos_framework::dispatchable_fungible_asset; + use aptos_framework::object::{ConstructorRef, Object}; + use aptos_framework::function_info; + + use std::option; + use std::signer; + use std::string; + + struct BurnStore has key { + burn_ref: BurnRef, + } + + public fun initialize(account: &signer, constructor_ref: &ConstructorRef) { + let burn_ref = fungible_asset::generate_burn_ref(constructor_ref); + + assert!(signer::address_of(account) == @0xcafe, 1); + move_to(account, BurnStore { burn_ref }); + + let withdraw = function_info::new_function_info( + account, + string::utf8(b"deflation_token"), + string::utf8(b"withdraw"), + ); + + dispatchable_fungible_asset::register_dispatch_functions( + constructor_ref, + option::some(withdraw), + option::none(), + option::none(), + ); + } + + public fun withdraw( + store: Object, + amount: u64, + transfer_ref: &TransferRef, + ): FungibleAsset acquires BurnStore { + // For every withdraw, we burn 10% from the store. + let burn_amount = amount / 10; + if (burn_amount > 0) { + fungible_asset::burn_from(&borrow_global(@0xcafe).burn_ref, store, burn_amount); + }; + + fungible_asset::withdraw_with_ref(transfer_ref, store, amount) + } + + #[test_only] + use aptos_framework::object; + #[test_only] + use aptos_framework::fungible_asset::{Metadata, TestToken}; + + #[test(creator = @0xcafe)] + #[expected_failure(major_status=4037, location=aptos_framework::dispatchable_fungible_asset)] + fun test_self_reentrancy( + creator: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + + initialize(creator, &creator_ref); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + dispatchable_fungible_asset::deposit(creator_store, fa); + + // Withdraw will cause an re-entrant call into self module. + let fa = dispatchable_fungible_asset::withdraw(creator, creator_store, 10); + dispatchable_fungible_asset::deposit(creator_store, fa); + } +} diff --git a/aptos-move/framework/aptos-framework/tests/deflation_token_tests.move b/aptos-move/framework/aptos-framework/tests/deflation_token_tests.move new file mode 100644 index 0000000000000..5b823e1c8f91f --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/deflation_token_tests.move @@ -0,0 +1,238 @@ +#[test_only] +module 0xcafe::deflation_token_tests { + use aptos_framework::function_info; + use aptos_framework::fungible_asset::{Self, Metadata, TestToken}; + use aptos_framework::dispatchable_fungible_asset; + use 0xcafe::deflation_token; + use aptos_framework::object; + use std::option; + use std::string; + + #[test(creator = @0xcafe, aaron = @0xface)] + fun test_deflation_e2e_basic_flow( + creator: &signer, + aaron: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + let aaron_store = fungible_asset::create_test_store(aaron, metadata); + + deflation_token::initialize(creator, &creator_ref); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit + dispatchable_fungible_asset::deposit(creator_store, fa); + // Withdraw + let fa = dispatchable_fungible_asset::withdraw(creator, creator_store, 5); + assert!(fungible_asset::supply(metadata) == option::some(100), 3); + dispatchable_fungible_asset::deposit(aaron_store, fa); + + assert!(fungible_asset::balance(creator_store) == 95, 42); + assert!(fungible_asset::balance(aaron_store) == 5, 42); + + // Withdrawing 10 token will cause 1 token to be burned. + let fa = dispatchable_fungible_asset::withdraw(creator, creator_store, 10); + assert!(fungible_asset::supply(metadata) == option::some(99), 3); + dispatchable_fungible_asset::deposit(aaron_store, fa); + + assert!(fungible_asset::balance(creator_store) == 84, 42); + assert!(fungible_asset::balance(aaron_store) == 15, 42); + + dispatchable_fungible_asset::transfer(creator, creator_store, aaron_store, 10); + assert!(fungible_asset::balance(creator_store) == 73, 42); + assert!(fungible_asset::balance(aaron_store) == 25, 42); + + dispatchable_fungible_asset::transfer_assert_minimum_deposit(creator, creator_store, aaron_store, 10, 10); + assert!(fungible_asset::balance(creator_store) == 62, 42); + assert!(fungible_asset::balance(aaron_store) == 35, 42); + } + + #[test(creator = @0xcafe, aaron = @0xface)] + #[expected_failure(abort_code = 0x70002, location = aptos_framework::dispatchable_fungible_asset)] + fun test_deflation_assert_min_deposit( + creator: &signer, + aaron: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + let aaron_store = fungible_asset::create_test_store(aaron, metadata); + + deflation_token::initialize(creator, &creator_ref); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + dispatchable_fungible_asset::deposit(creator_store, fa); + + dispatchable_fungible_asset::transfer_assert_minimum_deposit(creator, creator_store, aaron_store, 10, 11); + } + + #[test(creator = @0xcafe)] + #[expected_failure(abort_code = 0x1001C, location = aptos_framework::fungible_asset)] + fun test_deflation_fa_deposit( + creator: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + + deflation_token::initialize(creator, &creator_ref); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + dispatchable_fungible_asset::deposit(creator_store, fa); + + // Withdraw would fail if using existing FA api. + let fa = fungible_asset::withdraw(creator, creator_store, 5); + fungible_asset::deposit(creator_store, fa); + } + + #[test(creator = @0xcafe, aaron = @0xface)] + #[expected_failure(abort_code = 0x1001C, location = aptos_framework::fungible_asset)] + fun test_deflation_fa_withdraw( + creator: &signer, + aaron: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + let aaron_store = fungible_asset::create_test_store(aaron, metadata); + + deflation_token::initialize(creator, &creator_ref); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit + dispatchable_fungible_asset::deposit(creator_store, fa); + // Withdraw would fail if using existing FA api. + let fa = fungible_asset::withdraw(creator, creator_store, 5); + assert!(fungible_asset::supply(metadata) == option::some(100), 3); + dispatchable_fungible_asset::deposit(aaron_store, fa); + } + + #[test(creator = @0xcafe, aaron = @0xface)] + #[expected_failure(abort_code = 0x8001D, location = aptos_framework::fungible_asset)] + fun test_double_init( + creator: &signer, + ) { + let (creator_ref, _) = fungible_asset::create_test_token(creator); + let (_, _, _) = fungible_asset::init_test_metadata(&creator_ref); + deflation_token::initialize(creator, &creator_ref); + + let withdraw = function_info::new_function_info( + creator, + string::utf8(b"deflation_token"), + string::utf8(b"withdraw"), + ); + + // Re-registering the overload function should yield an error + dispatchable_fungible_asset::register_dispatch_functions( + &creator_ref, + option::some(withdraw), + option::none(), + option::none(), + ); + } + + #[test(creator = @0xcafe)] + #[expected_failure(abort_code = 0x10019, location = aptos_framework::fungible_asset)] + fun test_register_bad_withdraw( + creator: &signer, + ) { + let (creator_ref, _) = fungible_asset::create_test_token(creator); + + let withdraw = function_info::new_function_info( + creator, + string::utf8(b"deflation_token"), + string::utf8(b"initialize"), + ); + + // Change the deposit and withdraw function. Should give a type mismatch error. + dispatchable_fungible_asset::register_dispatch_functions( + &creator_ref, + option::some(withdraw), + option::none(), + option::none() + ); + } + + #[test(creator = @0xcafe)] + #[expected_failure(abort_code = 0x1001A, location = aptos_framework::fungible_asset)] + fun test_register_bad_deposit( + creator: &signer, + ) { + let (creator_ref, _) = fungible_asset::create_test_token(creator); + + let withdraw = function_info::new_function_info( + creator, + string::utf8(b"deflation_token"), + string::utf8(b"withdraw"), + ); + + // Change the deposit and withdraw function. Should give a type mismatch error. + dispatchable_fungible_asset::register_dispatch_functions( + &creator_ref, + option::some(withdraw), + option::some(withdraw), + option::none() + ); + } + + #[test(creator = @0xcafe)] + #[expected_failure(abort_code = 0x1001B, location = aptos_framework::fungible_asset)] + fun test_register_bad_value( + creator: &signer, + ) { + let (creator_ref, _) = fungible_asset::create_test_token(creator); + + let withdraw = function_info::new_function_info( + creator, + string::utf8(b"deflation_token"), + string::utf8(b"withdraw"), + ); + + // Change the deposit and withdraw function. Should give a type mismatch error. + dispatchable_fungible_asset::register_dispatch_functions( + &creator_ref, + option::some(withdraw), + option::none(), + option::some(withdraw), + ); + } + + #[test(creator = @0xcafe)] + fun test_calling_overloadable_api_on_regular_fa( + creator: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit would succeed + dispatchable_fungible_asset::deposit(creator_store, fa); + } +} diff --git a/aptos-move/framework/aptos-framework/tests/function_info_tests.move b/aptos-move/framework/aptos-framework/tests/function_info_tests.move new file mode 100644 index 0000000000000..93a7776f5974b --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/function_info_tests.move @@ -0,0 +1,100 @@ +#[test_only] +module aptos_framework::function_info_tests { + use aptos_framework::function_info::{Self, FunctionInfo}; + use std::string; + + public fun lhs(_s: &FunctionInfo) {} + + public fun rhs() {} + + public fun rhs2(_u: u8) {} + + public fun lhs_generic(_s: &FunctionInfo) {} + + public fun rhs_generic() {} + + #[test] + fun test_valid_identifier() { + let s1 = string::utf8(b"abcd"); + let _ = function_info::new_function_info_from_address(@0xcafe, s1, s1); + } + + #[test] + #[expected_failure(abort_code = 0x1, location = aptos_framework::function_info)] + fun test_invalid_identifier() { + let s1 = string::utf8(b"0abcd"); + let _ = function_info::new_function_info_from_address(@0xcafe, s1, s1); + } + + #[test] + fun test_func_type_eq() { + let m = string::utf8(b"function_info_tests_helpers"); + let m2 = string::utf8(b"function_info_tests"); + let lhs = function_info::new_function_info_from_address(@aptos_framework, m2, string::utf8(b"lhs")); + let rhs = function_info::new_function_info_from_address(@0xcafe, m, string::utf8(b"rhs")); + assert!(function_info::check_dispatch_type_compatibility(&lhs, &rhs), 0x1); + } + + #[test] + fun test_func_type_eq_generic() { + let m = string::utf8(b"function_info_tests_helpers"); + let m2 = string::utf8(b"function_info_tests"); + let lhs = function_info::new_function_info_from_address(@aptos_framework, m2, string::utf8(b"lhs_generic")); + let rhs = function_info::new_function_info_from_address(@0xcafe, m, string::utf8(b"rhs_generic")); + assert!(function_info::check_dispatch_type_compatibility(&lhs, &rhs), 0x1); + } + + #[test] + #[expected_failure(abort_code = 0x2, location = aptos_framework::function_info)] + fun test_func_type_eq_reject_same_module() { + let m2 = string::utf8(b"function_info_tests"); + let lhs = function_info::new_function_info_from_address(@aptos_framework, m2, string::utf8(b"lhs")); + let rhs = function_info::new_function_info_from_address(@aptos_framework, m2, string::utf8(b"rhs")); + assert!(function_info::check_dispatch_type_compatibility(&lhs, &rhs), 0x1); + } + + #[test] + #[expected_failure(abort_code = 0x2, location = aptos_framework::function_info)] + fun test_func_type_bad_lhs() { + let m = string::utf8(b"function_info_tests_helpers"); + let m2 = string::utf8(b"function_info_tests"); + let lhs = function_info::new_function_info_from_address(@aptos_framework, m2, string::utf8(b"lhs")); + let rhs = function_info::new_function_info_from_address(@0xcafe, m, string::utf8(b"rhs")); + + // rhs has less than one arguments. + assert!(function_info::check_dispatch_type_compatibility(&rhs, &lhs), 0x42); + } + + #[test] + #[expected_failure(abort_code = 0x42, location = aptos_framework::function_info_tests)] + fun test_func_type_neq() { + let m = string::utf8(b"function_info_tests_helpers"); + let m2 = string::utf8(b"function_info_tests"); + let lhs = function_info::new_function_info_from_address(@aptos_framework, m2, string::utf8(b"lhs")); + let rhs = function_info::new_function_info_from_address(@0xcafe, m, string::utf8(b"rhs2")); + assert!(function_info::check_dispatch_type_compatibility(&lhs, &rhs), 0x42); + } + + #[test] + #[expected_failure(abort_code = 0x42, location = aptos_framework::function_info_tests)] + fun test_func_type_neq_generic() { + let m = string::utf8(b"function_info_tests_helpers"); + let m2 = string::utf8(b"function_info_tests"); + let lhs = function_info::new_function_info_from_address(@aptos_framework, m2, string::utf8(b"lhs_generic")); + let rhs = function_info::new_function_info_from_address(@0xcafe, m, string::utf8(b"rhs")); + assert!(function_info::check_dispatch_type_compatibility(&lhs, &rhs), 0x42); + } + + #[test] + #[expected_failure(abort_code = 0x2, location = aptos_framework::function_info)] + fun test_func_type_rhs_doesnt_exist() { + let m = string::utf8(b"function_info_tests_helpers"); + let m2 = string::utf8(b"function_info_tests"); + + let lhs = function_info::new_function_info_from_address(@aptos_framework, m2, string::utf8(b"lhs")); + let rhs = function_info::new_function_info_from_address(@0xcafe, m, string::utf8(b"rhs3")); + + // rhs has less than one arguments. + assert!(function_info::check_dispatch_type_compatibility(&rhs, &lhs), 0x42); + } +} diff --git a/aptos-move/framework/aptos-framework/tests/function_info_tests_helpers.move b/aptos-move/framework/aptos-framework/tests/function_info_tests_helpers.move new file mode 100644 index 0000000000000..40d6016235000 --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/function_info_tests_helpers.move @@ -0,0 +1,14 @@ +#[test_only] +module 0xcafe::function_info_tests_helpers { + use aptos_framework::function_info::FunctionInfo; + + public fun lhs(_s: &FunctionInfo) {} + + public fun rhs() {} + + public fun rhs2(_u: u8) {} + + public fun lhs_generic(_s: &FunctionInfo) {} + + public fun rhs_generic() {} +} diff --git a/aptos-move/framework/aptos-framework/tests/nil_op_token.move b/aptos-move/framework/aptos-framework/tests/nil_op_token.move new file mode 100644 index 0000000000000..6a4a852e19c78 --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/nil_op_token.move @@ -0,0 +1,36 @@ +#[test_only] +module 0xcafe::nil_op_token { + use aptos_framework::fungible_asset::{Self, FungibleAsset, TransferRef}; + use aptos_framework::dispatchable_fungible_asset; + use aptos_framework::object::{ConstructorRef, Object}; + use aptos_framework::function_info; + + use std::option; + use std::signer; + use std::string; + + public fun initialize(account: &signer, constructor_ref: &ConstructorRef) { + assert!(signer::address_of(account) == @0xcafe, 1); + let withdraw = function_info::new_function_info( + account, + string::utf8(b"nil_op_token"), + string::utf8(b"withdraw"), + ); + + dispatchable_fungible_asset::register_dispatch_functions( + constructor_ref, + option::some(withdraw), + option::none(), + option::none() + ); + } + + public fun withdraw( + store: Object, + _amount: u64, + transfer_ref: &TransferRef, + ): FungibleAsset { + // Always return a one FA. + fungible_asset::withdraw_with_ref(transfer_ref, store, 1) + } +} diff --git a/aptos-move/framework/aptos-framework/tests/nil_op_token_tests.move b/aptos-move/framework/aptos-framework/tests/nil_op_token_tests.move new file mode 100644 index 0000000000000..5749acbc18a41 --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/nil_op_token_tests.move @@ -0,0 +1,33 @@ +#[test_only] +module aptos_framework::nil_op_token_tests { + use aptos_framework::fungible_asset::{Self, Metadata, TestToken}; + use aptos_framework::dispatchable_fungible_asset; + use 0xcafe::nil_op_token; + use aptos_framework::object; + use std::option; + + #[test(creator = @0xcafe)] + #[expected_failure(abort_code=0x70002, location=aptos_framework::dispatchable_fungible_asset)] + fun test_nil_op_token( + creator: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + + nil_op_token::initialize(creator, &creator_ref); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit will cause an re-entrant call into dispatchable_fungible_asset + dispatchable_fungible_asset::deposit(creator_store, fa); + + // Withdraw will fail because it's not drawing the basic amount. + let fa = dispatchable_fungible_asset::withdraw(creator, creator_store, 10); + dispatchable_fungible_asset::deposit(creator_store, fa); + } +} diff --git a/aptos-move/framework/aptos-framework/tests/permissioned_token.move b/aptos-move/framework/aptos-framework/tests/permissioned_token.move new file mode 100644 index 0000000000000..fe0ea6d3a7dfc --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/permissioned_token.move @@ -0,0 +1,58 @@ +#[test_only] +module 0xcafe::permissioned_token { + use aptos_framework::fungible_asset::{Self, FungibleAsset, TransferRef}; + use aptos_framework::dispatchable_fungible_asset; + use aptos_framework::object::{Self, ConstructorRef, Object}; + use aptos_framework::function_info; + + use std::option; + use std::signer; + use std::string; + use std::vector; + + /// Provided withdraw function type doesn't meet the signature requirement. + const EWITHDRAW_NOT_ALLOWED: u64 = 1; + + struct AllowlistStore has key { + allowed_sender: vector
, + } + + public fun initialize(account: &signer, constructor_ref: &ConstructorRef, allowed_sender: vector
) { + assert!(signer::address_of(account) == @0xcafe, 1); + move_to(account, AllowlistStore { allowed_sender }); + + let withdraw = function_info::new_function_info( + account, + string::utf8(b"permissioned_token"), + string::utf8(b"withdraw"), + ); + + dispatchable_fungible_asset::register_dispatch_functions( + constructor_ref, + option::some(withdraw), + option::none(), + option::none() + ); + } + + public fun add_to_allow_list(account: &signer, new_address: address) acquires AllowlistStore { + assert!(signer::address_of(account) == @0xcafe, 1); + let allowed_sender = borrow_global_mut(@0xcafe); + if(!vector::contains(&allowed_sender.allowed_sender, &new_address)) { + vector::push_back(&mut allowed_sender.allowed_sender, new_address); + } + } + + public fun withdraw( + store: Object, + amount: u64, + transfer_ref: &TransferRef, + ): FungibleAsset acquires AllowlistStore { + assert!(vector::contains( + &borrow_global(@0xcafe).allowed_sender, + &object::object_address(&store) + ), EWITHDRAW_NOT_ALLOWED); + + fungible_asset::withdraw_with_ref(transfer_ref, store, amount) + } +} diff --git a/aptos-move/framework/aptos-framework/tests/permissioned_token_tests.move b/aptos-move/framework/aptos-framework/tests/permissioned_token_tests.move new file mode 100644 index 0000000000000..683b0e9c8afd1 --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/permissioned_token_tests.move @@ -0,0 +1,111 @@ +#[test_only] +module 0xcafe::permissioned_token_tests { + use aptos_framework::fungible_asset::{Self, Metadata, TestToken}; + use aptos_framework::dispatchable_fungible_asset; + use 0xcafe::permissioned_token; + use aptos_framework::object; + use std::option; + + #[test(creator = @0xcafe, aaron = @0xface)] + fun test_permissioned_e2e_basic_flow( + creator: &signer, + aaron: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + let aaron_store = fungible_asset::create_test_store(aaron, metadata); + let allowed_sender = vector[ + object::object_address(&creator_store), + object::object_address(&aaron_store), + ]; + + permissioned_token::initialize(creator, &creator_ref, allowed_sender); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit + dispatchable_fungible_asset::deposit(creator_store, fa); + // Withdraw + let fa = dispatchable_fungible_asset::withdraw(creator, creator_store, 5); + assert!(fungible_asset::supply(metadata) == option::some(100), 3); + dispatchable_fungible_asset::deposit(aaron_store, fa); + + let fa = dispatchable_fungible_asset::withdraw(creator, creator_store, 10); + assert!(fungible_asset::supply(metadata) == option::some(100), 3); + dispatchable_fungible_asset::deposit(aaron_store, fa); + } + + #[test(creator = @0xcafe, aaron = @0xface)] + #[expected_failure(abort_code = 1, location = 0xcafe::permissioned_token)] + fun test_permissioned_disallowed_sender( + creator: &signer, + aaron: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + let aaron_store = fungible_asset::create_test_store(aaron, metadata); + let allowed_sender = vector[ + object::object_address(&creator_store), + ]; + + permissioned_token::initialize(creator, &creator_ref, allowed_sender); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit + dispatchable_fungible_asset::deposit(creator_store, fa); + // Withdraw + let fa = dispatchable_fungible_asset::withdraw(creator, creator_store, 5); + assert!(fungible_asset::supply(metadata) == option::some(100), 3); + dispatchable_fungible_asset::deposit(aaron_store, fa); + + // aaron_store is not allowed to perform withdraw according to the allowlist rule + let fa = dispatchable_fungible_asset::withdraw(aaron, aaron_store, 10); + assert!(fungible_asset::supply(metadata) == option::some(100), 3); + dispatchable_fungible_asset::deposit(creator_store, fa); + } + + #[test(creator = @0xcafe, aaron = @0xface)] + fun test_permissioned_update_disallowed_sender( + creator: &signer, + aaron: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + let aaron_store = fungible_asset::create_test_store(aaron, metadata); + let allowed_sender = vector[ + object::object_address(&creator_store), + ]; + + permissioned_token::initialize(creator, &creator_ref, allowed_sender); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit + dispatchable_fungible_asset::deposit(creator_store, fa); + // Withdraw + let fa = dispatchable_fungible_asset::withdraw(creator, creator_store, 5); + assert!(fungible_asset::supply(metadata) == option::some(100), 3); + dispatchable_fungible_asset::deposit(aaron_store, fa); + + permissioned_token::add_to_allow_list(creator, object::object_address(&aaron_store)); + // aaron_store is now allowed to perform withdraw + let fa = dispatchable_fungible_asset::withdraw(aaron, aaron_store, 1); + dispatchable_fungible_asset::deposit(creator_store, fa); + } +} diff --git a/aptos-move/framework/aptos-framework/tests/reentrant_token.move b/aptos-move/framework/aptos-framework/tests/reentrant_token.move new file mode 100644 index 0000000000000..7a668423a71d3 --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/reentrant_token.move @@ -0,0 +1,36 @@ +#[test_only] +module 0xcafe::reentrant_token { + use aptos_framework::fungible_asset::{FungibleAsset, TransferRef}; + use aptos_framework::dispatchable_fungible_asset; + use aptos_framework::object::{ConstructorRef, Object}; + use aptos_framework::function_info; + + use std::option; + use std::signer; + use std::string; + + public fun initialize(account: &signer, constructor_ref: &ConstructorRef) { + assert!(signer::address_of(account) == @0xcafe, 1); + let deposit = function_info::new_function_info( + account, + string::utf8(b"reentrant_token"), + string::utf8(b"deposit"), + ); + + dispatchable_fungible_asset::register_dispatch_functions( + constructor_ref, + option::none(), + option::some(deposit), + option::none() + ); + } + + public fun deposit( + store: Object, + fa: FungibleAsset, + _transfer_ref: &TransferRef, + ) { + // Re-entering into dispatchable_fungible_asset. Will be rejected by the MoveVM runtime. + dispatchable_fungible_asset::deposit(store, fa); + } +} diff --git a/aptos-move/framework/aptos-framework/tests/reentrant_token_tests.move b/aptos-move/framework/aptos-framework/tests/reentrant_token_tests.move new file mode 100644 index 0000000000000..d68af4bbceb76 --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/reentrant_token_tests.move @@ -0,0 +1,29 @@ +#[test_only] +module 0xcafe::reentrant_token_tests { + use aptos_framework::fungible_asset::{Self, Metadata, TestToken}; + use aptos_framework::dispatchable_fungible_asset; + use 0xcafe::reentrant_token; + use aptos_framework::object; + use std::option; + + #[test(creator = @0xcafe)] + #[expected_failure(major_status=4037, location=aptos_framework::dispatchable_fungible_asset)] + fun test_reentrant_deposit( + creator: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + + reentrant_token::initialize(creator, &creator_ref); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit will cause an re-entrant call into dispatchable_fungible_asset + dispatchable_fungible_asset::deposit(creator_store, fa); + } +} diff --git a/aptos-move/framework/aptos-framework/tests/ten_x_token.move b/aptos-move/framework/aptos-framework/tests/ten_x_token.move new file mode 100644 index 0000000000000..7db59d838c9fc --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/ten_x_token.move @@ -0,0 +1,31 @@ +#[test_only] +module 0xcafe::ten_x_token { + use aptos_framework::fungible_asset; + use aptos_framework::dispatchable_fungible_asset; + use aptos_framework::object::{ConstructorRef, Object}; + use aptos_framework::function_info; + + use std::option; + use std::signer; + use std::string; + + public fun initialize(account: &signer, constructor_ref: &ConstructorRef) { + assert!(signer::address_of(account) == @0xcafe, 1); + let value = function_info::new_function_info( + account, + string::utf8(b"ten_x_token"), + string::utf8(b"derived_balance"), + ); + dispatchable_fungible_asset::register_dispatch_functions( + constructor_ref, + option::none(), + option::none(), + option::some(value) + ); + } + + public fun derived_balance(store: Object): u64 { + // Derived value is always 10x! + fungible_asset::balance(store) * 10 + } +} diff --git a/aptos-move/framework/aptos-framework/tests/ten_x_token_tests.move b/aptos-move/framework/aptos-framework/tests/ten_x_token_tests.move new file mode 100644 index 0000000000000..6ec82bac2b94a --- /dev/null +++ b/aptos-move/framework/aptos-framework/tests/ten_x_token_tests.move @@ -0,0 +1,31 @@ +#[test_only] +module aptos_framework::ten_x_token_tests { + use aptos_framework::fungible_asset::{Self, Metadata, TestToken}; + use aptos_framework::dispatchable_fungible_asset; + use 0xcafe::ten_x_token; + use aptos_framework::object; + use std::option; + + #[test(creator = @0xcafe)] + fun test_ten_x( + creator: &signer, + ) { + let (creator_ref, token_object) = fungible_asset::create_test_token(creator); + let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let metadata = object::convert(token_object); + + let creator_store = fungible_asset::create_test_store(creator, metadata); + + ten_x_token::initialize(creator, &creator_ref); + + assert!(fungible_asset::supply(metadata) == option::some(0), 1); + // Mint + let fa = fungible_asset::mint(&mint, 100); + assert!(fungible_asset::supply(metadata) == option::some(100), 2); + // Deposit will cause an re-entrant call into dispatchable_fungible_asset + dispatchable_fungible_asset::deposit(creator_store, fa); + + // The derived value is 10x + assert!(dispatchable_fungible_asset::derived_balance(creator_store) == 1000, 5); + } +} diff --git a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs index c238a8a5e0d26..96e1228c66ece 100644 --- a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs +++ b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs @@ -272,6 +272,18 @@ pub enum EntryFunctionCall { code: Vec>, }, + CoinCreateCoinConversionMap {}, + + /// Create APT pairing by passing `AptosCoin`. + CoinCreatePairing { + coin_type: TypeTag, + }, + + /// Voluntarily migrate to fungible store for `CoinType` if not yet. + CoinMigrateToFungibleStore { + coin_type: TypeTag, + }, + /// Transfers `amount` of coins `CoinType` from `from` to `to`. CoinTransfer { coin_type: TypeTag, @@ -1125,6 +1137,9 @@ impl EntryFunctionCall { metadata_serialized, code, } => code_publish_package_txn(metadata_serialized, code), + CoinCreateCoinConversionMap {} => coin_create_coin_conversion_map(), + CoinCreatePairing { coin_type } => coin_create_pairing(coin_type), + CoinMigrateToFungibleStore { coin_type } => coin_migrate_to_fungible_store(coin_type), CoinTransfer { coin_type, to, @@ -2222,6 +2237,53 @@ pub fn code_publish_package_txn( )) } +pub fn coin_create_coin_conversion_map() -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 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, + ]), + ident_str!("coin").to_owned(), + ), + ident_str!("create_coin_conversion_map").to_owned(), + vec![], + vec![], + )) +} + +/// Create APT pairing by passing `AptosCoin`. +pub fn coin_create_pairing(coin_type: TypeTag) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 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, + ]), + ident_str!("coin").to_owned(), + ), + ident_str!("create_pairing").to_owned(), + vec![coin_type], + vec![], + )) +} + +/// Voluntarily migrate to fungible store for `CoinType` if not yet. +pub fn coin_migrate_to_fungible_store(coin_type: TypeTag) -> TransactionPayload { + TransactionPayload::EntryFunction(EntryFunction::new( + ModuleId::new( + AccountAddress::new([ + 0, 0, 0, 0, 0, 0, 0, 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, + ]), + ident_str!("coin").to_owned(), + ), + ident_str!("migrate_to_fungible_store").to_owned(), + vec![coin_type], + vec![], + )) +} + /// Transfers `amount` of coins `CoinType` from `from` to `to`. pub fn coin_transfer(coin_type: TypeTag, to: AccountAddress, amount: u64) -> TransactionPayload { TransactionPayload::EntryFunction(EntryFunction::new( @@ -4798,6 +4860,38 @@ mod decoder { } } + pub fn coin_create_coin_conversion_map( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(_script) = payload { + Some(EntryFunctionCall::CoinCreateCoinConversionMap {}) + } else { + None + } + } + + pub fn coin_create_pairing(payload: &TransactionPayload) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CoinCreatePairing { + coin_type: script.ty_args().get(0)?.clone(), + }) + } else { + None + } + } + + pub fn coin_migrate_to_fungible_store( + payload: &TransactionPayload, + ) -> Option { + if let TransactionPayload::EntryFunction(script) = payload { + Some(EntryFunctionCall::CoinMigrateToFungibleStore { + coin_type: script.ty_args().get(0)?.clone(), + }) + } else { + None + } + } + pub fn coin_transfer(payload: &TransactionPayload) -> Option { if let TransactionPayload::EntryFunction(script) = payload { Some(EntryFunctionCall::CoinTransfer { @@ -6241,6 +6335,18 @@ static SCRIPT_FUNCTION_DECODER_MAP: once_cell::sync::Lazy + +Whether migration from coin to fungible asset feature is enabled. + +Lifetime: transient + + +
const COIN_TO_FUNGIBLE_ASSET_MIGRATION: u64 = 60;
+
+ + + Whether gas fees are collected and distributed to the block proposers. @@ -411,6 +433,18 @@ Lifetime: transient + + +Whether the dispatchable fungible asset standard feature is enabled. + +Lifetime: transient + + +
const DISPATCHABLE_FUNGIBLE_ASSET: u64 = 63;
+
+ + + @@ -603,6 +637,16 @@ Whether deploying to objects is enabled. + + +Whether we use more efficient native implementation of computing object derived address + + +
const OBJECT_NATIVE_DERIVED_ADDRESS: u64 = 62;
+
+ + + Whether allow changing beneficiaries for operators. @@ -636,6 +680,15 @@ Lifetime: transient + + + + +
const PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS: u64 = 61;
+
+ + + Deprecated by aptos_framework::randomness_config::RandomnessConfig. @@ -750,6 +803,19 @@ Lifetime: transient + + +Whether the transaction context extension is enabled. This feature allows the module +transaction_context to provide contextual information about the user transaction. + +Lifetime: transient + + +
const TRANSACTION_CONTEXT_EXTENSION: u64 = 59;
+
+ + + Whether during upgrade compatibility checking, friend functions should be treated similar like @@ -2542,6 +2608,237 @@ Lifetime: transient + + + + +## Function `get_transaction_context_extension_feature` + + + +
public fun get_transaction_context_extension_feature(): u64
+
+ + + +
+Implementation + + +
public fun get_transaction_context_extension_feature(): u64 { TRANSACTION_CONTEXT_EXTENSION }
+
+ + + +
+ + + +## Function `transaction_context_extension_enabled` + + + +
public fun transaction_context_extension_enabled(): bool
+
+ + + +
+Implementation + + +
public fun transaction_context_extension_enabled(): bool acquires Features {
+    is_enabled(TRANSACTION_CONTEXT_EXTENSION)
+}
+
+ + + +
+ + + +## Function `get_coin_to_fungible_asset_migration_feature` + + + +
public fun get_coin_to_fungible_asset_migration_feature(): u64
+
+ + + +
+Implementation + + +
public fun get_coin_to_fungible_asset_migration_feature(): u64 { COIN_TO_FUNGIBLE_ASSET_MIGRATION }
+
+ + + +
+ + + +## Function `coin_to_fungible_asset_migration_feature_enabled` + + + +
public fun coin_to_fungible_asset_migration_feature_enabled(): bool
+
+ + + +
+Implementation + + +
public fun coin_to_fungible_asset_migration_feature_enabled(): bool acquires Features {
+    is_enabled(COIN_TO_FUNGIBLE_ASSET_MIGRATION)
+}
+
+ + + +
+ + + +## Function `get_primary_apt_fungible_store_at_user_address_feature` + + + +
public fun get_primary_apt_fungible_store_at_user_address_feature(): u64
+
+ + + +
+Implementation + + +
public fun get_primary_apt_fungible_store_at_user_address_feature(
+): u64 { PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS }
+
+ + + +
+ + + +## Function `primary_apt_fungible_store_at_user_address_enabled` + + + +
public fun primary_apt_fungible_store_at_user_address_enabled(): bool
+
+ + + +
+Implementation + + +
public fun primary_apt_fungible_store_at_user_address_enabled(): bool acquires Features {
+    is_enabled(PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS)
+}
+
+ + + +
+ + + +## Function `get_object_native_derived_address_feature` + + + +
public fun get_object_native_derived_address_feature(): u64
+
+ + + +
+Implementation + + +
public fun get_object_native_derived_address_feature(): u64 { OBJECT_NATIVE_DERIVED_ADDRESS }
+
+ + + +
+ + + +## Function `object_native_derived_address_enabled` + + + +
public fun object_native_derived_address_enabled(): bool
+
+ + + +
+Implementation + + +
public fun object_native_derived_address_enabled(): bool acquires Features {
+    is_enabled(OBJECT_NATIVE_DERIVED_ADDRESS)
+}
+
+ + + +
+ + + +## Function `get_dispatchable_fungible_asset_feature` + + + +
public fun get_dispatchable_fungible_asset_feature(): u64
+
+ + + +
+Implementation + + +
public fun get_dispatchable_fungible_asset_feature(): u64 { DISPATCHABLE_FUNGIBLE_ASSET }
+
+ + + +
+ + + +## Function `dispatchable_fungible_asset_enabled` + + + +
public fun dispatchable_fungible_asset_enabled(): bool
+
+ + + +
+Implementation + + +
public fun dispatchable_fungible_asset_enabled(): bool acquires Features {
+    is_enabled(DISPATCHABLE_FUNGIBLE_ASSET)
+}
+
+ + +
@@ -2565,7 +2862,7 @@ Governance proposals should use change_feature_flags(_framework: &signer, _enable: vector<u64>, _disable: vector<u64>) { - abort(error::invalid_state(EAPI_DISABLED)) + abort (error::invalid_state(EAPI_DISABLED)) }
@@ -2624,7 +2921,11 @@ Enable and disable features for the next epoch. Implementation -
public fun change_feature_flags_for_next_epoch(framework: &signer, enable: vector<u64>, disable: vector<u64>) acquires PendingFeatures, Features {
+
public fun change_feature_flags_for_next_epoch(
+    framework: &signer,
+    enable: vector<u64>,
+    disable: vector<u64>
+) acquires PendingFeatures, Features {
     assert!(signer::address_of(framework) == @std, error::permission_denied(EFRAMEWORK_SIGNER_NEEDED));
 
     // Figure out the baseline feature vec that the diff will be applied to.
@@ -2660,7 +2961,7 @@ While the scope is public, it can only be usd in system transactions like 
 who have permission to set the flag that's checked in extract().
 
 
-
public fun on_new_epoch(vm_or_framework: &signer)
+
public fun on_new_epoch(framework: &signer)
 
@@ -2669,11 +2970,15 @@ who have permission to set the flag that's checked in extract(). Implementation -
public fun on_new_epoch(vm_or_framework: &signer) acquires Features, PendingFeatures {
-    ensure_vm_or_framework_signer(vm_or_framework);
+
public fun on_new_epoch(framework: &signer) acquires Features, PendingFeatures {
+    ensure_framework_signer(framework);
     if (exists<PendingFeatures>(@std)) {
         let PendingFeatures { features } = move_from<PendingFeatures>(@std);
-        borrow_global_mut<Features>(@std).features = features;
+        if (exists<Features>(@std)) {
+            borrow_global_mut<Features>(@std).features = features;
+        } else {
+            move_to(framework, Features { features })
+        }
     }
 }
 
@@ -2799,13 +3104,13 @@ Helper to check whether a feature flag is enabled. - + -## Function `ensure_vm_or_framework_signer` +## Function `ensure_framework_signer` -
fun ensure_vm_or_framework_signer(account: &signer)
+
fun ensure_framework_signer(account: &signer)
 
@@ -2814,9 +3119,9 @@ Helper to check whether a feature flag is enabled. Implementation -
fun ensure_vm_or_framework_signer(account: &signer) {
+
fun ensure_framework_signer(account: &signer) {
     let addr = signer::address_of(account);
-    assert!(addr == @std || addr == @vm, error::permission_denied(EFRAMEWORK_SIGNER_NEEDED));
+    assert!(addr == @std, error::permission_denied(EFRAMEWORK_SIGNER_NEEDED));
 }
 
@@ -2840,7 +3145,11 @@ Helper to check whether a feature flag is enabled. Implementation -
public fun change_feature_flags_for_verification(framework: &signer, enable: vector<u64>, disable: vector<u64>) acquires Features {
+
public fun change_feature_flags_for_verification(
+    framework: &signer,
+    enable: vector<u64>,
+    disable: vector<u64>
+) acquires Features {
     change_feature_flags_internal(framework, enable, disable)
 }
 
@@ -3025,18 +3334,17 @@ Helper to check whether a feature flag is enabled. ### Function `on_new_epoch` -
public fun on_new_epoch(vm_or_framework: &signer)
+
public fun on_new_epoch(framework: &signer)
 
-
let addr = signer::address_of(vm_or_framework);
-aborts_if addr != @std && addr != @vm;
-aborts_if exists<PendingFeatures>(@std) && !exists<Features>(@std);
+
requires @std == signer::address_of(framework);
 let features_pending = global<PendingFeatures>(@std).features;
 let post features_std = global<Features>(@std).features;
 ensures exists<PendingFeatures>(@std) ==> features_std == features_pending;
+aborts_if false;
 
diff --git a/aptos-move/framework/move-stdlib/sources/configs/features.move b/aptos-move/framework/move-stdlib/sources/configs/features.move index a0b802dd7256a..514721e9238de 100644 --- a/aptos-move/framework/move-stdlib/sources/configs/features.move +++ b/aptos-move/framework/move-stdlib/sources/configs/features.move @@ -369,7 +369,9 @@ module std::features { /// Deprecated by `aptos_framework::randomness_config::RandomnessConfig`. const RECONFIGURE_WITH_DKG: u64 = 45; + public fun get_reconfigure_with_dkg_feature(): u64 { RECONFIGURE_WITH_DKG } + public fun reconfigure_with_dkg_enabled(): bool acquires Features { is_enabled(RECONFIGURE_WITH_DKG) } @@ -476,6 +478,58 @@ module std::features { is_enabled(MODULE_EVENT_MIGRATION) } + /// Whether the transaction context extension is enabled. This feature allows the module + /// `transaction_context` to provide contextual information about the user transaction. + /// + /// Lifetime: transient + const TRANSACTION_CONTEXT_EXTENSION: u64 = 59; + + public fun get_transaction_context_extension_feature(): u64 { TRANSACTION_CONTEXT_EXTENSION } + + public fun transaction_context_extension_enabled(): bool acquires Features { + is_enabled(TRANSACTION_CONTEXT_EXTENSION) + } + + /// Whether migration from coin to fungible asset feature is enabled. + /// + /// Lifetime: transient + const COIN_TO_FUNGIBLE_ASSET_MIGRATION: u64 = 60; + + public fun get_coin_to_fungible_asset_migration_feature(): u64 { COIN_TO_FUNGIBLE_ASSET_MIGRATION } + + public fun coin_to_fungible_asset_migration_feature_enabled(): bool acquires Features { + is_enabled(COIN_TO_FUNGIBLE_ASSET_MIGRATION) + } + + const PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS: u64 = 61; + + public fun get_primary_apt_fungible_store_at_user_address_feature( + ): u64 { PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS } + + public fun primary_apt_fungible_store_at_user_address_enabled(): bool acquires Features { + is_enabled(PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS) + } + + /// Whether we use more efficient native implementation of computing object derived address + const OBJECT_NATIVE_DERIVED_ADDRESS: u64 = 62; + + public fun get_object_native_derived_address_feature(): u64 { OBJECT_NATIVE_DERIVED_ADDRESS } + + public fun object_native_derived_address_enabled(): bool acquires Features { + is_enabled(OBJECT_NATIVE_DERIVED_ADDRESS) + } + + /// Whether the dispatchable fungible asset standard feature is enabled. + /// + /// Lifetime: transient + const DISPATCHABLE_FUNGIBLE_ASSET: u64 = 63; + + public fun get_dispatchable_fungible_asset_feature(): u64 { DISPATCHABLE_FUNGIBLE_ASSET } + + public fun dispatchable_fungible_asset_enabled(): bool acquires Features { + is_enabled(DISPATCHABLE_FUNGIBLE_ASSET) + } + // ============================================================================================ // Feature Flag Implementation @@ -499,7 +553,7 @@ module std::features { /// /// Governance proposals should use `change_feature_flags_for_next_epoch()` to enable/disable features. public fun change_feature_flags(_framework: &signer, _enable: vector, _disable: vector) { - abort(error::invalid_state(EAPI_DISABLED)) + abort (error::invalid_state(EAPI_DISABLED)) } /// Update feature flags directly. Only used in genesis/tests. @@ -518,7 +572,11 @@ module std::features { } /// Enable and disable features for the next epoch. - public fun change_feature_flags_for_next_epoch(framework: &signer, enable: vector, disable: vector) acquires PendingFeatures, Features { + public fun change_feature_flags_for_next_epoch( + framework: &signer, + enable: vector, + disable: vector + ) acquires PendingFeatures, Features { assert!(signer::address_of(framework) == @std, error::permission_denied(EFRAMEWORK_SIGNER_NEEDED)); // Figure out the baseline feature vec that the diff will be applied to. @@ -543,11 +601,15 @@ module std::features { /// /// While the scope is public, it can only be usd in system transactions like `block_prologue` and governance proposals, /// who have permission to set the flag that's checked in `extract()`. - public fun on_new_epoch(vm_or_framework: &signer) acquires Features, PendingFeatures { - ensure_vm_or_framework_signer(vm_or_framework); + public fun on_new_epoch(framework: &signer) acquires Features, PendingFeatures { + ensure_framework_signer(framework); if (exists(@std)) { let PendingFeatures { features } = move_from(@std); - borrow_global_mut(@std).features = features; + if (exists(@std)) { + borrow_global_mut(@std).features = features; + } else { + move_to(framework, Features { features }) + } } } @@ -588,18 +650,26 @@ module std::features { }); } - fun ensure_vm_or_framework_signer(account: &signer) { + fun ensure_framework_signer(account: &signer) { let addr = signer::address_of(account); - assert!(addr == @std || addr == @vm, error::permission_denied(EFRAMEWORK_SIGNER_NEEDED)); + assert!(addr == @std, error::permission_denied(EFRAMEWORK_SIGNER_NEEDED)); } #[verify_only] - public fun change_feature_flags_for_verification(framework: &signer, enable: vector, disable: vector) acquires Features { + public fun change_feature_flags_for_verification( + framework: &signer, + enable: vector, + disable: vector + ) acquires Features { change_feature_flags_internal(framework, enable, disable) } #[test_only] - public fun change_feature_flags_for_testing(framework: &signer, enable: vector, disable: vector) acquires Features { + public fun change_feature_flags_for_testing( + framework: &signer, + enable: vector, + disable: vector + ) acquires Features { change_feature_flags_internal(framework, enable, disable) } diff --git a/aptos-move/framework/move-stdlib/sources/configs/features.spec.move b/aptos-move/framework/move-stdlib/sources/configs/features.spec.move index 1246a616d8489..8779c94835b22 100644 --- a/aptos-move/framework/move-stdlib/sources/configs/features.spec.move +++ b/aptos-move/framework/move-stdlib/sources/configs/features.spec.move @@ -96,12 +96,11 @@ spec std::features { ensures [abstract] result == spec_module_event_enabled(); } - spec on_new_epoch(vm_or_framework: &signer) { - let addr = signer::address_of(vm_or_framework); - aborts_if addr != @std && addr != @vm; - aborts_if exists(@std) && !exists(@std); + spec on_new_epoch(framework: &signer) { + requires @std == signer::address_of(framework); let features_pending = global(@std).features; let post features_std = global(@std).features; ensures exists(@std) ==> features_std == features_pending; + aborts_if false; } } diff --git a/aptos-move/framework/src/aptos.rs b/aptos-move/framework/src/aptos.rs index 79e6c1e36f348..80753542af20e 100644 --- a/aptos-move/framework/src/aptos.rs +++ b/aptos-move/framework/src/aptos.rs @@ -181,12 +181,14 @@ static NAMED_ADDRESSES: Lazy> = Lazy::new(|| let one = NumericalAddress::parse_str("0x1").unwrap(); let three = NumericalAddress::parse_str("0x3").unwrap(); let four = NumericalAddress::parse_str("0x4").unwrap(); + let ten = NumericalAddress::parse_str("0xA").unwrap(); let resources = NumericalAddress::parse_str("0xA550C18").unwrap(); result.insert("std".to_owned(), one); result.insert("aptos_std".to_owned(), one); result.insert("aptos_framework".to_owned(), one); result.insert("aptos_token".to_owned(), three); result.insert("aptos_token_objects".to_owned(), four); + result.insert("aptos_fungible_asset".to_owned(), ten); result.insert("core_resources".to_owned(), resources); result.insert("vm".to_owned(), zero); result.insert("vm_reserved".to_owned(), zero); diff --git a/aptos-move/framework/src/built_package.rs b/aptos-move/framework/src/built_package.rs index a6e6f90b97206..38fa59c2b829e 100644 --- a/aptos-move/framework/src/built_package.rs +++ b/aptos-move/framework/src/built_package.rs @@ -272,22 +272,25 @@ impl BuiltPackage { let effective_compiler_version = compiler_version.unwrap_or_default(); let effective_language_version = language_version.unwrap_or_default(); let mut error_writer = StandardStream::stderr(ColorChoice::Auto); - error_writer.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; if effective_compiler_version.unstable() { + error_writer.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; writeln!( &mut error_writer, "Warning: compiler version `{}` is experimental \ and should not be used in production", effective_compiler_version - )? + )?; + error_writer.reset()?; } if effective_language_version.unstable() { + error_writer.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)))?; writeln!( &mut error_writer, "Warning: language version `{}` is experimental \ and should not be used in production", effective_language_version - )? + )?; + error_writer.reset()?; } effective_compiler_version.check_language_support(effective_language_version)?; Ok(()) diff --git a/aptos-move/framework/src/natives/dispatchable_fungible_asset.rs b/aptos-move/framework/src/natives/dispatchable_fungible_asset.rs new file mode 100644 index 0000000000000..d7d0d76a6784d --- /dev/null +++ b/aptos-move/framework/src/natives/dispatchable_fungible_asset.rs @@ -0,0 +1,60 @@ +use super::function_info::extract_function_info; +use aptos_gas_schedule::gas_params::natives::aptos_framework::DISPATCHABLE_FUNGIBLE_ASSET_DISPATCH_BASE; +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 +use aptos_native_interface::{ + RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeError, SafeNativeResult, +}; +use move_vm_runtime::native_functions::NativeFunction; +use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use smallvec::SmallVec; +use std::collections::VecDeque; + +/*************************************************************************************************** + * native fun dispatchable_withdraw / dispatchable_deposit / dispatchable_derived_balance + * + * Directs control flow based on the last argument. We use the same native function implementation + * for all dispatching native. + * gas cost: a flat fee because we charged the loading of those modules previously. + * + **************************************************************************************************/ +pub(crate) fn native_dispatch( + context: &mut SafeNativeContext, + ty_args: Vec, + mut arguments: VecDeque, +) -> SafeNativeResult> { + let (module_name, func_name) = extract_function_info(&mut arguments)?; + // Check if the module is already properly charged in this transaction. + if !context + .traversal_context() + .visited + .contains_key(&(module_name.address(), module_name.name())) + { + return Err(SafeNativeError::Abort { abort_code: 4 }); + } + + // Use Error to instruct the VM to perform a function call dispatch. + Err(SafeNativeError::FunctionDispatch { + cost: context.eval_gas(DISPATCHABLE_FUNGIBLE_ASSET_DISPATCH_BASE), + module_name, + func_name, + ty_args, + args: arguments.into_iter().collect(), + }) +} + +/*************************************************************************************************** + * module + * + **************************************************************************************************/ +pub fn make_all( + builder: &SafeNativeBuilder, +) -> impl Iterator + '_ { + let natives = [ + ("dispatchable_withdraw", native_dispatch as RawSafeNative), + ("dispatchable_deposit", native_dispatch), + ("dispatchable_derived_balance", native_dispatch), + ]; + + builder.make_named_natives(natives) +} diff --git a/aptos-move/framework/src/natives/function_info.rs b/aptos-move/framework/src/natives/function_info.rs new file mode 100644 index 0000000000000..5ef8cd9a24706 --- /dev/null +++ b/aptos-move/framework/src/natives/function_info.rs @@ -0,0 +1,192 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 +use aptos_gas_schedule::gas_params::natives::aptos_framework::*; +use aptos_native_interface::{ + safely_pop_arg, RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeError, + SafeNativeResult, +}; +use move_binary_format::errors::PartialVMError; +use move_core_types::{ + account_address::AccountAddress, gas_algebra::NumBytes, identifier::Identifier, + language_storage::ModuleId, vm_status::StatusCode, +}; +use move_vm_runtime::native_functions::NativeFunction; +use move_vm_types::{ + loaded_data::runtime_types::Type, + values::{Reference, StructRef, Value, VectorRef}, +}; +use smallvec::{smallvec, SmallVec}; +use std::collections::VecDeque; + +// Extract Identifer from a move value of type &String +fn identifier_from_ref(v: Value) -> SafeNativeResult { + let bytes = v + .value_as::() + .and_then(|s| s.borrow_field(0)) + .and_then(|v| v.value_as::()) + .map_err(SafeNativeError::InvariantViolation)? + .as_bytes_ref() + .to_vec(); + Identifier::from_utf8(bytes).map_err(|_| SafeNativeError::Abort { abort_code: 1 }) +} + +pub(crate) fn extract_function_info( + arguments: &mut VecDeque, +) -> SafeNativeResult<(ModuleId, Identifier)> { + match arguments.pop_back() { + Some(val) => match val.value_as::() { + Ok(v) => { + let module_address = v + .borrow_field(0) + .and_then(|v| v.value_as::()) + .and_then(|v| v.read_ref()) + .and_then(|v| v.value_as::()) + .map_err(SafeNativeError::InvariantViolation)?; + + let module_name = identifier_from_ref( + v.borrow_field(1) + .map_err(SafeNativeError::InvariantViolation)?, + )?; + + let func_name = identifier_from_ref( + v.borrow_field(2) + .map_err(SafeNativeError::InvariantViolation)?, + )?; + Ok((ModuleId::new(module_address, module_name), func_name)) + }, + Err(e) => Err(SafeNativeError::InvariantViolation(e)), + }, + None => Err(SafeNativeError::InvariantViolation(PartialVMError::new( + StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, + ))), + } +} + +/*************************************************************************************************** + * native fun check_dispatch_type_compatibility_impl + * + * Returns true if the function argument types of rhs is the same as (arguments type of lhs || &FunctionInfo) + * gas cost: base_cost + unit_cost * type_size + * + **************************************************************************************************/ +fn native_check_dispatch_type_compatibility_impl( + context: &mut SafeNativeContext, + _ty_args: Vec, + mut arguments: VecDeque, +) -> SafeNativeResult> { + debug_assert!(arguments.len() == 2); + + // TODO: Figure out the correct gas charging schema here. + // + // We need to load the modules from lhs and rhs, and cloning the bytes for module id and function name. + context.charge(FUNCTION_INFO_CHECK_DISPATCH_TYPE_COMPATIBILITY_IMPL_BASE)?; + + let (rhs, rhs_id) = { + let (module, func) = extract_function_info(&mut arguments)?; + if !context + .traversal_context() + .visited + .contains_key(&(module.address(), module.name())) + { + return Err(SafeNativeError::Abort { abort_code: 2 }); + } + ( + context + .load_function(&module, &func) + .map_err(|_| SafeNativeError::Abort { abort_code: 2 })?, + module, + ) + }; + let (lhs, lhs_id) = { + let (module, func) = extract_function_info(&mut arguments)?; + ( + context + .load_function(&module, &func) + .map_err(|_| SafeNativeError::Abort { abort_code: 2 })?, + module, + ) + }; + + if lhs.parameter_types.is_empty() { + return Err(SafeNativeError::Abort { abort_code: 2 }); + } + + Ok(smallvec![Value::bool( + rhs.type_parameters == lhs.type_parameters + && rhs.return_types == lhs.return_types + && lhs.parameter_types[0..lhs.parameter_types.len() - 1] == rhs.parameter_types + && !rhs.def_is_friend_or_private + && lhs_id != rhs_id + )]) +} + +/*************************************************************************************************** + * native fun is_identifier + * + * Returns true if the string passed in is a valid Move identifier + * gas cost: base_cost + unit_cost * num_of_bytes + * + **************************************************************************************************/ +fn native_is_identifier( + context: &mut SafeNativeContext, + _ty_args: Vec, + mut arguments: VecDeque, +) -> SafeNativeResult> { + debug_assert!(arguments.len() == 1); + + let s_arg = safely_pop_arg!(arguments, VectorRef); + let s_ref = s_arg.as_bytes_ref(); + + context.charge( + FUNCTION_INFO_CHECK_IS_IDENTIFIER_BASE + + FUNCTION_INFO_CHECK_IS_IDENTIFIER_PER_BYTE + * NumBytes::new(s_ref.as_slice().len() as u64), + )?; + + let result = if let Ok(str) = std::str::from_utf8(&s_ref) { + Identifier::is_valid(str) + } else { + false + }; + + Ok(smallvec![Value::bool(result)]) +} + +/*************************************************************************************************** + * native fun load_function_impl + * + * Load up a module related to the function and charge gas. + * gas cost: base_cost + transitive deps size of the function. + * + **************************************************************************************************/ +fn native_load_function_impl( + context: &mut SafeNativeContext, + _ty_args: Vec, + mut arguments: VecDeque, +) -> SafeNativeResult> { + debug_assert!(arguments.len() == 1); + + context.charge(FUNCTION_INFO_LOAD_FUNCTION_BASE)?; + let (module_name, _) = extract_function_info(&mut arguments)?; + + Err(SafeNativeError::LoadModule { module_name }) +} + +/*************************************************************************************************** + * module + * + **************************************************************************************************/ +pub fn make_all( + builder: &SafeNativeBuilder, +) -> impl Iterator + '_ { + let natives = [ + ( + "check_dispatch_type_compatibility_impl", + native_check_dispatch_type_compatibility_impl as RawSafeNative, + ), + ("is_identifier", native_is_identifier), + ("load_function_impl", native_load_function_impl), + ]; + + builder.make_named_natives(natives) +} diff --git a/aptos-move/framework/src/natives/mod.rs b/aptos-move/framework/src/natives/mod.rs index 9f5cdf25b6cab..bec070b996540 100644 --- a/aptos-move/framework/src/natives/mod.rs +++ b/aptos-move/framework/src/natives/mod.rs @@ -9,7 +9,9 @@ pub mod consensus_config; pub mod create_signer; pub mod cryptography; pub mod debug; +pub mod dispatchable_fungible_asset; pub mod event; +pub mod function_info; pub mod hash; pub mod object; pub mod object_code_deployment; @@ -83,6 +85,11 @@ pub fn all_natives( add_natives_from_module!("debug", debug::make_all(builder)); add_natives_from_module!("string_utils", string_utils::make_all(builder)); add_natives_from_module!("consensus_config", consensus_config::make_all(builder)); + add_natives_from_module!("function_info", function_info::make_all(builder)); + add_natives_from_module!( + "dispatchable_fungible_asset", + dispatchable_fungible_asset::make_all(builder) + ); make_table_from_iter(framework_addr, natives) } diff --git a/aptos-move/framework/src/natives/object.rs b/aptos-move/framework/src/natives/object.rs index 4e251d475c827..fe4adb302bbd0 100644 --- a/aptos-move/framework/src/natives/object.rs +++ b/aptos-move/framework/src/natives/object.rs @@ -6,6 +6,8 @@ use aptos_native_interface::{ safely_assert_eq, safely_pop_arg, RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeResult, }; +use aptos_types::transaction::authenticator::AuthenticationKey; +use better_any::{Tid, TidAble}; use move_core_types::{ account_address::AccountAddress, gas_algebra::{InternalGas, InternalGasPerByte}, @@ -16,7 +18,21 @@ use move_vm_types::{ loaded_data::runtime_types::Type, natives::function::PartialVMError, values::Value, }; use smallvec::{smallvec, SmallVec}; -use std::collections::VecDeque; +use std::{ + cell::RefCell, + collections::{HashMap, VecDeque}, +}; + +/// Cached emitted module events. +#[derive(Default, Tid)] +pub struct NativeObjectContext { + // TODO - if further optimizations is important, we can consider if: + // - caching all (or just some derive_from) locations is useful + // - if it is faster to use BTreeMap or HashMap, given the lenghts of the addresses + // - if it is worth moving to native/caching other address deriving as well + derived_from_object_addresses: + RefCell>, +} /*************************************************************************************************** * native exists_at @@ -60,6 +76,37 @@ fn native_exists_at( Ok(smallvec![Value::bool(exists)]) } +/*************************************************************************************************** + * native fun create_user_derived_object_address_impl + * + * gas cost: base_cost + * + **************************************************************************************************/ +fn native_create_user_derived_object_address_impl( + context: &mut SafeNativeContext, + ty_args: Vec, + mut args: VecDeque, +) -> SafeNativeResult> { + debug_assert!(ty_args.is_empty()); + debug_assert!(args.len() == 2); + + context.charge(OBJECT_USER_DERIVED_ADDRESS_BASE)?; + + let object_context = context.extensions().get::(); + let derive_from = safely_pop_arg!(args, AccountAddress); + let source = safely_pop_arg!(args, AccountAddress); + + let derived_address = *object_context + .derived_from_object_addresses + .borrow_mut() + .entry((derive_from, source)) + .or_insert_with(|| { + AuthenticationKey::object_address_from_object(&source, &derive_from).account_address() + }); + + Ok(smallvec![Value::address(derived_address)]) +} + /*************************************************************************************************** * module * @@ -67,7 +114,13 @@ fn native_exists_at( pub fn make_all( builder: &SafeNativeBuilder, ) -> impl Iterator + '_ { - let natives = [("exists_at", native_exists_at as RawSafeNative)]; + let natives = [ + ("exists_at", native_exists_at as RawSafeNative), + ( + "create_user_derived_object_address_impl", + native_create_user_derived_object_address_impl, + ), + ]; builder.make_named_natives(natives) } diff --git a/aptos-move/framework/src/natives/transaction_context.rs b/aptos-move/framework/src/natives/transaction_context.rs index 2a79e8ee085ad..044e948a0ecb5 100644 --- a/aptos-move/framework/src/natives/transaction_context.rs +++ b/aptos-move/framework/src/natives/transaction_context.rs @@ -3,16 +3,29 @@ use aptos_gas_schedule::gas_params::natives::aptos_framework::*; use aptos_native_interface::{ - RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeResult, + RawSafeNative, SafeNativeBuilder, SafeNativeContext, SafeNativeError, SafeNativeResult, +}; +use aptos_types::{ + error, + transaction::{ + authenticator::AuthenticationKey, + user_transaction_context::{EntryFunctionPayload, UserTransactionContext}, + }, }; -use aptos_types::transaction::authenticator::AuthenticationKey; use better_any::{Tid, TidAble}; -use move_core_types::account_address::AccountAddress; +use move_core_types::gas_algebra::{NumArgs, NumBytes}; use move_vm_runtime::native_functions::NativeFunction; -use move_vm_types::{loaded_data::runtime_types::Type, values::Value}; +use move_vm_types::{ + loaded_data::runtime_types::Type, + values::{Struct, Value}, +}; use smallvec::{smallvec, SmallVec}; use std::collections::VecDeque; +pub mod abort_codes { + pub const ETRANSACTION_CONTEXT_NOT_AVAILABLE: u64 = 1; +} + /// The native transaction context extension. This needs to be attached to the /// NativeContextExtensions value which is passed into session functions, so it /// is accessible from natives of this extension. @@ -24,17 +37,26 @@ pub struct NativeTransactionContext { auid_counter: u64, script_hash: Vec, chain_id: u8, + /// A transaction context is available upon transaction prologue/execution/epilogue. It is not available + /// when a VM session is created for other purposes, such as for processing validator transactions. + user_transaction_context_opt: Option, } impl NativeTransactionContext { /// Create a new instance of a native transaction context. This must be passed in via an /// extension into VM session functions. - pub fn new(txn_hash: Vec, script_hash: Vec, chain_id: u8) -> Self { + pub fn new( + txn_hash: Vec, + script_hash: Vec, + chain_id: u8, + user_transaction_context_opt: Option, + ) -> Self { Self { txn_hash, auid_counter: 0, script_hash, chain_id, + user_transaction_context_opt, } } @@ -80,16 +102,12 @@ fn native_generate_unique_address( .get_mut::(); transaction_context.auid_counter += 1; - let hash_vec = AuthenticationKey::auid( + let auid = AuthenticationKey::auid( transaction_context.txn_hash.clone(), transaction_context.auid_counter, - ); - Ok(smallvec![Value::address(AccountAddress::new( - hash_vec - .to_vec() - .try_into() - .expect("Unable to convert hash vector into [u8]") - ))]) + ) + .account_address(); + Ok(smallvec![Value::address(auid)]) } /*************************************************************************************************** @@ -112,6 +130,253 @@ fn native_get_script_hash( )]) } +fn native_sender_internal( + context: &mut SafeNativeContext, + _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(TRANSACTION_CONTEXT_SENDER_BASE)?; + + let user_transaction_context_opt = get_user_transaction_context_opt_from_context(context); + if let Some(transaction_context) = user_transaction_context_opt { + Ok(smallvec![Value::address(transaction_context.sender())]) + } else { + Err(SafeNativeError::Abort { + abort_code: error::invalid_state(abort_codes::ETRANSACTION_CONTEXT_NOT_AVAILABLE), + }) + } +} + +fn native_secondary_signers_internal( + context: &mut SafeNativeContext, + _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(TRANSACTION_CONTEXT_SECONDARY_SIGNERS_BASE)?; + + let user_transaction_context_opt = get_user_transaction_context_opt_from_context(context); + if let Some(transaction_context) = user_transaction_context_opt { + let secondary_signers = transaction_context.secondary_signers(); + context.charge( + TRANSACTION_CONTEXT_SECONDARY_SIGNERS_PER_SIGNER + * NumArgs::new(secondary_signers.len() as u64), + )?; + Ok(smallvec![Value::vector_address(secondary_signers)]) + } else { + Err(SafeNativeError::Abort { + abort_code: error::invalid_state(abort_codes::ETRANSACTION_CONTEXT_NOT_AVAILABLE), + }) + } +} + +fn native_gas_payer_internal( + context: &mut SafeNativeContext, + _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(TRANSACTION_CONTEXT_FEE_PAYER_BASE)?; + + let user_transaction_context_opt = get_user_transaction_context_opt_from_context(context); + if let Some(transaction_context) = user_transaction_context_opt { + Ok(smallvec![Value::address(transaction_context.gas_payer())]) + } else { + Err(SafeNativeError::Abort { + abort_code: error::invalid_state(abort_codes::ETRANSACTION_CONTEXT_NOT_AVAILABLE), + }) + } +} + +fn native_max_gas_amount_internal( + context: &mut SafeNativeContext, + _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(TRANSACTION_CONTEXT_MAX_GAS_AMOUNT_BASE)?; + + let user_transaction_context_opt = get_user_transaction_context_opt_from_context(context); + if let Some(transaction_context) = user_transaction_context_opt { + Ok(smallvec![Value::u64(transaction_context.max_gas_amount())]) + } else { + Err(SafeNativeError::Abort { + abort_code: error::invalid_state(abort_codes::ETRANSACTION_CONTEXT_NOT_AVAILABLE), + }) + } +} + +fn native_gas_unit_price_internal( + context: &mut SafeNativeContext, + _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(TRANSACTION_CONTEXT_GAS_UNIT_PRICE_BASE)?; + + let user_transaction_context_opt = get_user_transaction_context_opt_from_context(context); + if let Some(transaction_context) = user_transaction_context_opt { + Ok(smallvec![Value::u64(transaction_context.gas_unit_price())]) + } else { + Err(SafeNativeError::Abort { + abort_code: error::invalid_state(abort_codes::ETRANSACTION_CONTEXT_NOT_AVAILABLE), + }) + } +} + +fn native_chain_id_internal( + context: &mut SafeNativeContext, + _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(TRANSACTION_CONTEXT_CHAIN_ID_BASE)?; + + let user_transaction_context_opt = get_user_transaction_context_opt_from_context(context); + if let Some(transaction_context) = user_transaction_context_opt { + Ok(smallvec![Value::u8(transaction_context.chain_id())]) + } else { + Err(SafeNativeError::Abort { + abort_code: error::invalid_state(abort_codes::ETRANSACTION_CONTEXT_NOT_AVAILABLE), + }) + } +} + +fn create_option_some_value(value: Value) -> Value { + Value::struct_(Struct::pack(vec![create_singleton_vector(value)])) +} + +fn create_option_none() -> Value { + Value::struct_(Struct::pack(vec![create_empty_vector()])) +} + +fn create_string_value(s: String) -> Value { + Value::struct_(Struct::pack(vec![Value::vector_u8(s.as_bytes().to_vec())])) +} + +fn create_vector_value(vv: Vec) -> Value { + // This is safe because this function is only used to create vectors of homogenous values. + Value::vector_for_testing_only(vv) +} + +fn create_singleton_vector(v: Value) -> Value { + create_vector_value(vec![v]) +} + +fn create_empty_vector() -> Value { + create_vector_value(vec![]) +} + +fn num_bytes_from_entry_function_payload(entry_function_payload: &EntryFunctionPayload) -> usize { + entry_function_payload.account_address.len() + + entry_function_payload.module_name.len() + + entry_function_payload.function_name.len() + + entry_function_payload + .ty_arg_names + .iter() + .map(|s| s.len()) + .sum::() + + entry_function_payload + .args + .iter() + .map(|v| v.len()) + .sum::() +} + +fn create_entry_function_payload(entry_function_payload: EntryFunctionPayload) -> Value { + let args = entry_function_payload + .args + .iter() + .map(|arg| Value::vector_u8(arg.clone())) + .collect::>(); + + let ty_args = entry_function_payload + .ty_arg_names + .iter() + .map(|ty_arg| create_string_value(ty_arg.clone())) + .collect::>(); + + Value::struct_(Struct::pack(vec![ + Value::address(entry_function_payload.account_address), + create_string_value(entry_function_payload.module_name), + create_string_value(entry_function_payload.function_name), + create_vector_value(ty_args), + create_vector_value(args), + ])) +} + +fn native_entry_function_payload_internal( + context: &mut SafeNativeContext, + mut _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(TRANSACTION_CONTEXT_ENTRY_FUNCTION_PAYLOAD_BASE)?; + + let user_transaction_context_opt = get_user_transaction_context_opt_from_context(context); + + if let Some(transaction_context) = user_transaction_context_opt { + if let Some(entry_function_payload) = transaction_context.entry_function_payload() { + let num_bytes = num_bytes_from_entry_function_payload(&entry_function_payload); + context.charge( + TRANSACTION_CONTEXT_ENTRY_FUNCTION_PAYLOAD_PER_BYTE_IN_STR + * NumBytes::new(num_bytes as u64), + )?; + let payload = create_entry_function_payload(entry_function_payload); + Ok(smallvec![create_option_some_value(payload)]) + } else { + Ok(smallvec![create_option_none()]) + } + } else { + Err(SafeNativeError::Abort { + abort_code: error::invalid_state(abort_codes::ETRANSACTION_CONTEXT_NOT_AVAILABLE), + }) + } +} + +fn native_multisig_payload_internal( + context: &mut SafeNativeContext, + mut _ty_args: Vec, + _args: VecDeque, +) -> SafeNativeResult> { + context.charge(TRANSACTION_CONTEXT_MULTISIG_PAYLOAD_BASE)?; + + let user_transaction_context_opt = get_user_transaction_context_opt_from_context(context); + + if let Some(transaction_context) = user_transaction_context_opt { + if let Some(multisig_payload) = transaction_context.multisig_payload() { + if let Some(entry_function_payload) = multisig_payload.entry_function_payload { + let num_bytes = num_bytes_from_entry_function_payload(&entry_function_payload); + context.charge( + TRANSACTION_CONTEXT_MULTISIG_PAYLOAD_PER_BYTE_IN_STR + * NumBytes::new(num_bytes as u64), + )?; + let inner_entry_fun_payload = create_entry_function_payload(entry_function_payload); + let multisig_payload = Value::struct_(Struct::pack(vec![ + Value::address(multisig_payload.multisig_address), + create_option_some_value(inner_entry_fun_payload), + ])); + Ok(smallvec![create_option_some_value(multisig_payload)]) + } else { + let multisig_payload = Value::struct_(Struct::pack(vec![ + Value::address(multisig_payload.multisig_address), + create_option_none(), + ])); + Ok(smallvec![create_option_some_value(multisig_payload)]) + } + } else { + Ok(smallvec![create_option_none()]) + } + } else { + Err(SafeNativeError::Abort { + abort_code: error::invalid_state(abort_codes::ETRANSACTION_CONTEXT_NOT_AVAILABLE), + }) + } +} + +fn get_user_transaction_context_opt_from_context<'a>( + context: &'a SafeNativeContext, +) -> &'a Option { + &context + .extensions() + .get::() + .user_transaction_context_opt +} + /*************************************************************************************************** * module * @@ -123,6 +388,23 @@ pub fn make_all( ("get_script_hash", native_get_script_hash as RawSafeNative), ("generate_unique_address", native_generate_unique_address), ("get_txn_hash", native_get_txn_hash), + ("sender_internal", native_sender_internal), + ( + "secondary_signers_internal", + native_secondary_signers_internal, + ), + ("gas_payer_internal", native_gas_payer_internal), + ("max_gas_amount_internal", native_max_gas_amount_internal), + ("gas_unit_price_internal", native_gas_unit_price_internal), + ("chain_id_internal", native_chain_id_internal), + ( + "entry_function_payload_internal", + native_entry_function_payload_internal, + ), + ( + "multisig_payload_internal", + native_multisig_payload_internal, + ), ]; builder.make_named_natives(natives) diff --git a/aptos-move/framework/tests/move_unit_test.rs b/aptos-move/framework/tests/move_unit_test.rs index cc7e3a0003d28..5a896737e1c38 100644 --- a/aptos-move/framework/tests/move_unit_test.rs +++ b/aptos-move/framework/tests/move_unit_test.rs @@ -9,7 +9,7 @@ use aptos_types::on_chain_config::{ }; use aptos_vm::natives; use move_cli::base::test::{run_move_unit_tests, UnitTestResult}; -use move_command_line_common::{env::read_bool_env_var, testing::MOVE_COMPILER_V2}; +use move_command_line_common::env::get_move_compiler_v2_from_env; use move_model::metadata::CompilerVersion; use move_package::CompilerConfig; use move_unit_test::UnitTestingConfig; @@ -45,7 +45,7 @@ fn run_tests_for_pkg(path_to_pkg: impl Into) { if ok != UnitTestResult::Success { panic!("move unit tests failed") } - if read_bool_env_var(MOVE_COMPILER_V2) { + if get_move_compiler_v2_from_env() { // Run test against v2 when MOVE_COMPILER_V2 is set compiler_config.compiler_version = Some(CompilerVersion::V2_0); build_config.compiler_config = compiler_config; diff --git a/aptos-move/move-examples/bcs-stream/Move.toml b/aptos-move/move-examples/bcs-stream/Move.toml new file mode 100644 index 0000000000000..37e624a8445dd --- /dev/null +++ b/aptos-move/move-examples/bcs-stream/Move.toml @@ -0,0 +1,9 @@ +[package] +name = "BCSStream" +version = "0.0.0" + +[addresses] +bcs_stream = "_" + +[dependencies] +AptosStdlib = { local = "../../framework/aptos-stdlib" } diff --git a/aptos-move/move-examples/bcs-stream/sources/stream.move b/aptos-move/move-examples/bcs-stream/sources/stream.move new file mode 100644 index 0000000000000..d54fcdbb1cbf6 --- /dev/null +++ b/aptos-move/move-examples/bcs-stream/sources/stream.move @@ -0,0 +1,291 @@ +/// This module enables the deserialization of BCS-formatted byte arrays into Move primitive types. +/// Deserialization Strategies: +/// - Per-Byte Deserialization: Employed for most types to ensure lower gas consumption, this method processes each byte +/// individually to match the length and type requirements of target Move types. +/// - Exception: For the `deserialize_address` function, the function-based approach from `aptos_std::from_bcs` is used +/// due to type constraints, even though it is generally more gas-intensive. +/// - This can be optimized further by introducing native vector slices. +/// Application: +/// - This deserializer is particularly valuable for processing BCS serialized data within Move modules, +/// especially useful for systems requiring cross-chain message interpretation or off-chain data verification. +module bcs_stream::bcs_stream { + use std::error; + use std::vector; + use std::option::{Self, Option}; + use std::string::{Self, String}; + + use aptos_std::from_bcs; + + /// The data does not fit the expected format. + const EMALFORMED_DATA: u64 = 1; + /// There are not enough bytes to deserialize for the given type. + const EOUT_OF_BYTES: u64 = 2; + + struct BCSStream has drop { + /// Byte buffer containing the serialized data. + data: vector, + /// Cursor indicating the current position in the byte buffer. + cur: u64, + } + + /// Constructs a new BCSStream instance from the provided byte array. + public fun new(data: vector): BCSStream { + BCSStream { + data, + cur: 0, + } + } + + /// Deserializes a ULEB128-encoded integer from the stream. + /// In the BCS format, lengths of vectors are represented using ULEB128 encoding. + public fun deserialize_uleb128(stream: &mut BCSStream): u64 { + let res = 0; + let shift = 0; + + while (stream.cur < vector::length(&stream.data)) { + let byte = *vector::borrow(&stream.data, stream.cur); + stream.cur = stream.cur + 1; + + let val = ((byte & 0x7f) as u64); + if (((val << shift) >> shift) != val) { + abort error::invalid_argument(EMALFORMED_DATA) + }; + res = res | (val << shift); + + if ((byte & 0x80) == 0) { + if (shift > 0 && val == 0) { + abort error::invalid_argument(EMALFORMED_DATA) + }; + return res + }; + + shift = shift + 7; + if (shift > 64) { + abort error::invalid_argument(EMALFORMED_DATA) + }; + }; + + abort error::out_of_range(EOUT_OF_BYTES) + } + + /// Deserializes a `bool` value from the stream. + public fun deserialize_bool(stream: &mut BCSStream): bool { + assert!(stream.cur < vector::length(&stream.data), error::out_of_range(EOUT_OF_BYTES)); + let byte = *vector::borrow(&stream.data, stream.cur); + stream.cur = stream.cur + 1; + if (byte == 0) { + false + } else if (byte == 1) { + true + } else { + abort error::invalid_argument(EMALFORMED_DATA) + } + } + + /// Deserializes an `address` value from the stream. + /// 32-byte `address` values are serialized using little-endian byte order. + /// This function utilizes the `to_address` function from the `aptos_std::from_bcs` module, + /// because the Move type system does not permit per-byte referencing of addresses. + public fun deserialize_address(stream: &mut BCSStream): address { + let data = &stream.data; + let cur = stream.cur; + + assert!(cur + 32 <= vector::length(data), error::out_of_range(EOUT_OF_BYTES)); + let res = from_bcs::to_address(vector::slice(data, cur, cur + 32)); + + stream.cur = cur + 32; + res + } + + /// Deserializes a `u8` value from the stream. + /// 1-byte `u8` values are serialized using little-endian byte order. + public fun deserialize_u8(stream: &mut BCSStream): u8 { + let data = &stream.data; + let cur = stream.cur; + + assert!(cur < vector::length(data), error::out_of_range(EOUT_OF_BYTES)); + + let res = *vector::borrow(data, cur); + + stream.cur = cur + 1; + res + } + + /// Deserializes a `u16` value from the stream. + /// 2-byte `u16` values are serialized using little-endian byte order. + public fun deserialize_u16(stream: &mut BCSStream): u16 { + let data = &stream.data; + let cur = stream.cur; + + assert!(cur + 2 <= vector::length(data), error::out_of_range(EOUT_OF_BYTES)); + let res = + (*vector::borrow(data, cur) as u16) | + ((*vector::borrow(data, cur + 1) as u16) << 8) + ; + + stream.cur = stream.cur + 2; + res + } + + /// Deserializes a `u32` value from the stream. + /// 4-byte `u32` values are serialized using little-endian byte order. + public fun deserialize_u32(stream: &mut BCSStream): u32 { + let data = &stream.data; + let cur = stream.cur; + + assert!(cur + 4 <= vector::length(data), error::out_of_range(EOUT_OF_BYTES)); + let res = + (*vector::borrow(data, cur) as u32) | + ((*vector::borrow(data, cur + 1) as u32) << 8) | + ((*vector::borrow(data, cur + 2) as u32) << 16) | + ((*vector::borrow(data, cur + 3) as u32) << 24) + ; + + stream.cur = stream.cur + 4; + res + } + + /// Deserializes a `u64` value from the stream. + /// 8-byte `u64` values are serialized using little-endian byte order. + public fun deserialize_u64(stream: &mut BCSStream): u64 { + let data = &stream.data; + let cur = stream.cur; + + assert!(cur + 8 <= vector::length(data), error::out_of_range(EOUT_OF_BYTES)); + let res = + (*vector::borrow(data, cur) as u64) | + ((*vector::borrow(data, cur + 1) as u64) << 8) | + ((*vector::borrow(data, cur + 2) as u64) << 16) | + ((*vector::borrow(data, cur + 3) as u64) << 24) | + ((*vector::borrow(data, cur + 4) as u64) << 32) | + ((*vector::borrow(data, cur + 5) as u64) << 40) | + ((*vector::borrow(data, cur + 6) as u64) << 48) | + ((*vector::borrow(data, cur + 7) as u64) << 56) + ; + + stream.cur = stream.cur + 8; + res + } + + /// Deserializes a `u128` value from the stream. + /// 16-byte `u128` values are serialized using little-endian byte order. + public fun deserialize_u128(stream: &mut BCSStream): u128 { + let data = &stream.data; + let cur = stream.cur; + + assert!(cur + 16 <= vector::length(data), error::out_of_range(EOUT_OF_BYTES)); + let res = + (*vector::borrow(data, cur) as u128) | + ((*vector::borrow(data, cur + 1) as u128) << 8) | + ((*vector::borrow(data, cur + 2) as u128) << 16) | + ((*vector::borrow(data, cur + 3) as u128) << 24) | + ((*vector::borrow(data, cur + 4) as u128) << 32) | + ((*vector::borrow(data, cur + 5) as u128) << 40) | + ((*vector::borrow(data, cur + 6) as u128) << 48) | + ((*vector::borrow(data, cur + 7) as u128) << 56) | + ((*vector::borrow(data, cur + 8) as u128) << 64) | + ((*vector::borrow(data, cur + 9) as u128) << 72) | + ((*vector::borrow(data, cur + 10) as u128) << 80) | + ((*vector::borrow(data, cur + 11) as u128) << 88) | + ((*vector::borrow(data, cur + 12) as u128) << 96) | + ((*vector::borrow(data, cur + 13) as u128) << 104) | + ((*vector::borrow(data, cur + 14) as u128) << 112) | + ((*vector::borrow(data, cur + 15) as u128) << 120) + ; + + stream.cur = stream.cur + 16; + res + } + + /// Deserializes a `u256` value from the stream. + /// 32-byte `u256` values are serialized using little-endian byte order. + public fun deserialize_u256(stream: &mut BCSStream): u256 { + let data = &stream.data; + let cur = stream.cur; + + assert!(cur + 32 <= vector::length(data), error::out_of_range(EOUT_OF_BYTES)); + let res = + (*vector::borrow(data, cur) as u256) | + ((*vector::borrow(data, cur + 1) as u256) << 8) | + ((*vector::borrow(data, cur + 2) as u256) << 16) | + ((*vector::borrow(data, cur + 3) as u256) << 24) | + ((*vector::borrow(data, cur + 4) as u256) << 32) | + ((*vector::borrow(data, cur + 5) as u256) << 40) | + ((*vector::borrow(data, cur + 6) as u256) << 48) | + ((*vector::borrow(data, cur + 7) as u256) << 56) | + ((*vector::borrow(data, cur + 8) as u256) << 64) | + ((*vector::borrow(data, cur + 9) as u256) << 72) | + ((*vector::borrow(data, cur + 10) as u256) << 80) | + ((*vector::borrow(data, cur + 11) as u256) << 88) | + ((*vector::borrow(data, cur + 12) as u256) << 96) | + ((*vector::borrow(data, cur + 13) as u256) << 104) | + ((*vector::borrow(data, cur + 14) as u256) << 112) | + ((*vector::borrow(data, cur + 15) as u256) << 120) | + ((*vector::borrow(data, cur + 16) as u256) << 128) | + ((*vector::borrow(data, cur + 17) as u256) << 136) | + ((*vector::borrow(data, cur + 18) as u256) << 144) | + ((*vector::borrow(data, cur + 19) as u256) << 152) | + ((*vector::borrow(data, cur + 20) as u256) << 160) | + ((*vector::borrow(data, cur + 21) as u256) << 168) | + ((*vector::borrow(data, cur + 22) as u256) << 176) | + ((*vector::borrow(data, cur + 23) as u256) << 184) | + ((*vector::borrow(data, cur + 24) as u256) << 192) | + ((*vector::borrow(data, cur + 25) as u256) << 200) | + ((*vector::borrow(data, cur + 26) as u256) << 208) | + ((*vector::borrow(data, cur + 27) as u256) << 216) | + ((*vector::borrow(data, cur + 28) as u256) << 224) | + ((*vector::borrow(data, cur + 29) as u256) << 232) | + ((*vector::borrow(data, cur + 30) as u256) << 240) | + ((*vector::borrow(data, cur + 31) as u256) << 248) + ; + + stream.cur = stream.cur + 32; + res + } + + /// Deserializes an array of BCS deserializable elements from the stream. + /// First, reads the length of the vector, which is in uleb128 format. + /// After determining the length, it then reads the contents of the vector. + /// The `elem_deserializer` lambda expression is used sequentially to deserialize each element of the vector. + public inline fun deserialize_vector(stream: &mut BCSStream, elem_deserializer: |&mut BCSStream| E): vector { + let len = deserialize_uleb128(stream); + let v = vector::empty(); + + let i = 0; + while (i < len) { + vector::push_back(&mut v, elem_deserializer(stream)); + i = i + 1; + }; + + v + } + + /// Deserializes utf-8 `String` from the stream. + /// First, reads the length of the String, which is in uleb128 format. + /// After determining the length, it then reads the contents of the String. + public fun deserialize_string(stream: &mut BCSStream): String { + let len = deserialize_uleb128(stream); + let data = &stream.data; + let cur = stream.cur; + + assert!(cur + len <= vector::length(data), error::out_of_range(EOUT_OF_BYTES)); + + let res = string::utf8(vector::slice(data, cur, cur + len)); + stream.cur = cur + len; + + res + } + + /// Deserializes `Option` from the stream. + /// First, reads a single byte representing the presence (0x01) or absence (0x00) of data. + /// After determining the presence of data, it then reads the actual data if present. + /// The `elem_deserializer` lambda expression is used to deserialize the element contained within the `Option`. + public inline fun deserialize_option(stream: &mut BCSStream, elem_deserializer: |&mut BCSStream| E): Option { + let is_data = deserialize_bool(stream); + if (is_data) { + option::some(elem_deserializer(stream)) + } else { + option::none() + } + } +} diff --git a/aptos-move/move-examples/bcs-stream/sources/tests/tests.move b/aptos-move/move-examples/bcs-stream/sources/tests/tests.move new file mode 100644 index 0000000000000..56370f6e5479d --- /dev/null +++ b/aptos-move/move-examples/bcs-stream/sources/tests/tests.move @@ -0,0 +1,566 @@ +#[test_only] +module bcs_stream::tests { + use bcs_stream::bcs_stream; + use std::vector; + use std::option::{Self, Option}; + use std::string::{Self, String}; + + struct Bar has drop { + x: u16, + y: bool, + } + + struct Foo has drop { + a: u8, + b: u16, + c: u32, + d: u64, + e: u128, + f: u256, + g: bool, + h: vector, + i: address, + j: String, + k: Option>, + } + + fun deserialize_Bar(stream: &mut bcs_stream::BCSStream): Bar { + Bar { + x: bcs_stream::deserialize_u16(stream), + y: bcs_stream::deserialize_bool(stream), + } + } + + fun deserialize_Foo(stream: &mut bcs_stream::BCSStream): Foo { + Foo { + a: bcs_stream::deserialize_u8(stream), + b: bcs_stream::deserialize_u16(stream), + c: bcs_stream::deserialize_u32(stream), + d: bcs_stream::deserialize_u64(stream), + e: bcs_stream::deserialize_u128(stream), + f: bcs_stream::deserialize_u256(stream), + g: bcs_stream::deserialize_bool(stream), + h: bcs_stream::deserialize_vector(stream, |stream| { + deserialize_Bar(stream) + }), + i: bcs_stream::deserialize_address(stream), + j: bcs_stream::deserialize_string(stream), + k: bcs_stream::deserialize_option>( + stream, + |stream| { bcs_stream::deserialize_vector(stream, |stream_| { deserialize_Bar(stream_) }) } + ), + } + } + + #[test] + fun test_struct_all_types() { + let data = vector::empty(); + vector::append(&mut data, x"01"); // u8 + vector::append(&mut data, x"0200"); // u16 + vector::append(&mut data, x"03000000"); // u32 + vector::append(&mut data, x"0400000000000000"); // u64 + vector::append(&mut data, x"05000000000000000000000000000000"); // u128 + vector::append(&mut data, x"0600000000000000000000000000000000000000000000000000000000000000"); // u256 + vector::append(&mut data, x"01"); // bool + vector::append(&mut data, x"02010000020001"); // vector + vector::append(&mut data, x"000000000000000000000000000000000000000000000000000000000000ABCD"); // address + vector::append(&mut data, x"0B736F6D6520737472696E67"); // String + vector::append(&mut data, x"0102010000020001"); // Option + + let stream = bcs_stream::new(data); + let foo = deserialize_Foo(&mut stream); + + let expected = Foo { + a: 1, + b: 2, + c: 3, + d: 4, + e: 5, + f: 6, + g: true, + h: vector[Bar { x: 01, y: false }, Bar { x: 02, y: true }], + i: @0xABCD, + j: string::utf8(b"some string"), + k: option::some(vector[Bar { x: 01, y: false }, Bar { x: 02, y: true }]), + }; + + assert!(foo == expected, 0); + } + + #[test] + fun test_bool_true() { + let data = x"01"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_bool(&mut stream) == true, 0); + } + + #[test] + fun test_bool_false() { + let data = x"00"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_bool(&mut stream) == false, 0); + } + + #[test] + #[expected_failure(abort_code = 0x010001, location = bcs_stream::bcs_stream)] + fun test_bool_invalid() { + let data = x"02"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_bool(&mut stream); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_bool_out_of_bytes() { + let data = vector::empty(); + let stream = bcs_stream::new(data); + bcs_stream::deserialize_bool(&mut stream); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_length_no_bytes() { + let data = vector::empty(); + let stream = bcs_stream::new(data); + bcs_stream::deserialize_uleb128(&mut stream); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_length_no_ending_group() { + let data = x"808080808080808080"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_uleb128(&mut stream); + } + + #[test] + fun test_length_0() { + let data = x"00"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_uleb128(&mut stream) == 0, 0); + } + + #[test] + fun test_length_1() { + let data = x"01"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_uleb128(&mut stream) == 1, 0); + } + + #[test] + fun test_length_127() { + let data = x"7f"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_uleb128(&mut stream) == 127, 0); + } + + #[test] + fun test_length_128() { + let data = x"8001"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_uleb128(&mut stream) == 128, 0); + } + + #[test] + fun test_length_130() { + let data = x"8201"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_uleb128(&mut stream) == 130, 0); + } + + #[test] + fun test_length_16383() { + let data = x"ff7f"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_uleb128(&mut stream) == 16383, 0); + } + + #[test] + fun test_length_large() { + let data = x"E1D8F9FC06"; + let stream = bcs_stream::new(data); + let len = bcs_stream::deserialize_uleb128(&mut stream); + assert!(len == 1872653409, 0); + + let data = x"BEC020"; + let stream = bcs_stream::new(data); + let len = bcs_stream::deserialize_uleb128(&mut stream); + assert!(len == 532542, 0); + + let data = x"B39AEDD084E15D"; + let stream = bcs_stream::new(data); + let len = bcs_stream::deserialize_uleb128(&mut stream); + assert!(len == 412352463457587, 0); + } + + #[test] + fun test_length_2_pow_63_minus_1() { + let data = x"FFFFFFFFFFFFFFFF7F"; + let stream = bcs_stream::new(data); + let len = bcs_stream::deserialize_uleb128(&mut stream); + assert!(len == 9223372036854775807, 0); + } + + #[test] + fun test_length_2_pow_63() { + let data = x"80808080808080808001"; + let stream = bcs_stream::new(data); + let len = bcs_stream::deserialize_uleb128(&mut stream); + assert!(len == 9223372036854775808, 0); + } + + #[test] + fun test_length_2_pow_64_minus_1() { + let data = x"FFFFFFFFFFFFFFFFFF01"; + let stream = bcs_stream::new(data); + let len = bcs_stream::deserialize_uleb128(&mut stream); + assert!(len == 18446744073709551615, 0); + } + + #[test] + #[expected_failure(abort_code = 0x010001, location = bcs_stream::bcs_stream)] + fun test_length_2_pow_64() { + let data = x"80808080808080808002"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_uleb128(&mut stream); + } + + #[test] + fun test_vector_simple() { + let data = x"03010203"; + let stream = bcs_stream::new(data); + let v = bcs_stream::deserialize_vector(&mut stream, |stream| { + bcs_stream::deserialize_u8(stream) + }); + assert!(v == vector[1, 2, 3], 0); + } + + #[test] + fun test_vector_empty() { + let data = x"00"; + let stream = bcs_stream::new(data); + let v = bcs_stream::deserialize_vector(&mut stream, |stream| { + bcs_stream::deserialize_u8(stream) + }); + assert!(v == vector[], 0); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_vector_not_enough_items() { + let data = x"FFFFFFFFFFFFFFFFFF01"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_vector(&mut stream, |stream| { + bcs_stream::deserialize_u8(stream) + }); + } + + #[test] + fun test_u8() { + let data = vector::empty(); + + let i = 0; + while (i < 256) { + vector::push_back(&mut data, (i as u8)); + i = i + 1; + }; + + let stream = bcs_stream::new(data); + let i = 0; + while (i < 256) { + assert!(bcs_stream::deserialize_u8(&mut stream) == (i as u8), 0); + i = i + 1; + } + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_u8_out_of_bytes() { + let data = vector::empty(); + let stream = bcs_stream::new(data); + bcs_stream::deserialize_u8(&mut stream); + } + + #[test] + fun test_u16() { + let data = vector::empty(); + + let i = 0; + while (i < 65536) { + vector::push_back(&mut data, ((i % 256) as u8)); + vector::push_back(&mut data, ((i / 256) as u8)); + i = i + 1; + }; + + let stream = bcs_stream::new(data); + let i = 0; + while (i < 65536) { + assert!(bcs_stream::deserialize_u16(&mut stream) == (i as u16), 0); + i = i + 1; + } + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_u16_out_of_bytes() { + let data = x"00"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_u16(&mut stream); + } + + #[test] + fun test_u32() { + let data = x"01020304"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_u32(&mut stream) == 0x04030201, 0); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_u32_out_of_bytes() { + let data = x"000000"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_u32(&mut stream); + } + + #[test] + fun test_u64() { + let data = x"0102030405060708"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_u64(&mut stream) == 0x0807060504030201, 0); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_u64_out_of_bytes() { + let data = x"00000000000000"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_u64(&mut stream); + } + + #[test] + fun test_u128() { + let data = x"01020304050607081112131415161718"; + let stream = bcs_stream::new(data); + assert!(bcs_stream::deserialize_u128(&mut stream) == 0x18171615141312110807060504030201, 0); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_u128_out_of_bytes() { + let data = x"000000000000000000000000000000"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_u128(&mut stream); + } + + #[test] + fun test_u256() { + let data = x"0102030405060708111213141516171821222324252627283132333435363738"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_u256( + &mut stream + ) == 0x3837363534333231282726252423222118171615141312110807060504030201, + 0 + ); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_u256_out_of_bytes() { + let data = x"00000000000000000000000000000000000000000000000000000000000000"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_u256(&mut stream); + } + + #[test] + fun test_address() { + let data = x"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_address( + &mut stream + ) == @0x0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF, + 0 + ); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_address_too_short() { + let data = x"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCD"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_address(&mut stream); + } + + #[test] + fun test_string_simple() { + let data = x"0B736F6D6520737472696E67"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_string(&mut stream) == string::utf8(b"some string"), + 0 + ); + } + + #[test] + fun test_string_empty() { + let data = x"00"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_string(&mut stream) == string::utf8(b""), + 0 + ); + } + + #[test] + fun test_string_non_ascii() { + let data = x"18C3A7C3A5E2889EE289A0C2A2C3B5C39FE28882C692E288AB"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_string(&mut stream) == string::utf8( + x"C3A7C3A5E2889EE289A0C2A2C3B5C39FE28882C692E288AB" + ), + 0 + ); + } + + #[test] + fun test_string_large() { + let data = x"FF7F616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161"; + let stream = bcs_stream::new(data); + let res = bcs_stream::deserialize_string(&mut stream); + let expected = string::utf8( + b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ); + assert!(res == expected, 0); + } + + #[test] + #[expected_failure(abort_code = 0x020002, location = bcs_stream::bcs_stream)] + fun test_string_not_enough_bytes() { + let data = x"030101"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_string(&mut stream); + } + + #[test] + #[expected_failure(abort_code = 1, location = std::string)] + fun test_string_not_utf8() { + let data = x"01FF"; + let stream = bcs_stream::new(data); + bcs_stream::deserialize_string(&mut stream); + } + + + #[test] + fun test_option_some_bool() { + let data = x"0101"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_option( + &mut stream, + |stream| { bcs_stream::deserialize_bool(stream) } + ) == option::some(true), + 0 + ); + } + + #[test] + fun test_option_some_string() { + let data = x"010B736F6D6520737472696E67"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_option( + &mut stream, + |stream| { bcs_stream::deserialize_string(stream) } + ) == option::some(string::utf8(b"some string")), + 0 + ); + } + + #[test] + fun test_option_some_foo() { + let data = vector::empty(); + vector::append(&mut data, x"01"); // presence of data + vector::append(&mut data, x"01"); // u8 + vector::append(&mut data, x"0200"); // u16 + vector::append(&mut data, x"03000000"); // u32 + vector::append(&mut data, x"0400000000000000"); // u64 + vector::append(&mut data, x"05000000000000000000000000000000"); // u128 + vector::append(&mut data, x"0600000000000000000000000000000000000000000000000000000000000000"); // u256 + vector::append(&mut data, x"01"); // bool + vector::append(&mut data, x"02010000020001"); // vector + vector::append(&mut data, x"000000000000000000000000000000000000000000000000000000000000ABCD"); // address + vector::append(&mut data, x"0B736F6D6520737472696E67"); // String + vector::append(&mut data, x"0102010000020001"); // Option + + let stream = bcs_stream::new(data); + let some_foo = bcs_stream::deserialize_option(&mut stream, |stream| { deserialize_Foo(stream) }); + + let expected = option::some(Foo { + a: 1, + b: 2, + c: 3, + d: 4, + e: 5, + f: 6, + g: true, + h: vector[Bar { x: 01, y: false }, Bar { x: 02, y: true }], + i: @0xABCD, + j: string::utf8(b"some string"), + k: option::some(vector[Bar { x: 01, y: false }, Bar { x: 02, y: true }]), + }); + + assert!(some_foo == expected, 0); + } + + #[test] + fun test_option_no_data() { + let data = x"00"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_option( + &mut stream, + |stream| { bcs_stream::deserialize_bool(stream) } + ) == option::none(), + 0 + ); + } + + #[test] + fun test_option_nested() { + let data = x"010101"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_option( + &mut stream, + |stream| { + bcs_stream::deserialize_option( + stream, + |stream_| { bcs_stream::deserialize_bool(stream_) } + ) + } + ) == option::some(option::some(true)), + 0 + ); + } + + #[test] + fun test_option_nested_no_data() { + let data = x"0100"; + let stream = bcs_stream::new(data); + assert!( + bcs_stream::deserialize_option( + &mut stream, + |stream| { + bcs_stream::deserialize_option( + stream, + |stream_| { bcs_stream::deserialize_bool(stream_) } + ) + } + ) == option::some(option::none()), + 0 + ); + } +} diff --git a/aptos-move/vm-genesis/Cargo.toml b/aptos-move/vm-genesis/Cargo.toml index c140cf5154d51..b8d7e7efb3a11 100644 --- a/aptos-move/vm-genesis/Cargo.toml +++ b/aptos-move/vm-genesis/Cargo.toml @@ -23,6 +23,7 @@ aptos-vm-types = { workspace = true } bcs = { workspace = true } bytes = { workspace = true } move-core-types = { workspace = true } +move-vm-runtime = { workspace = true } move-vm-types = { workspace = true } once_cell = { workspace = true } rand = { workspace = true } diff --git a/aptos-move/vm-genesis/src/genesis_context.rs b/aptos-move/vm-genesis/src/genesis_context.rs index a30de58a05f1b..91c50d0b9ec34 100644 --- a/aptos-move/vm-genesis/src/genesis_context.rs +++ b/aptos-move/vm-genesis/src/genesis_context.rs @@ -4,12 +4,9 @@ #![forbid(unsafe_code)] -use aptos_types::{ - access_path::AccessPath, - state_store::{ - errors::StateviewError, state_key::StateKey, state_storage_usage::StateStorageUsage, - state_value::StateValue, TStateView, - }, +use aptos_types::state_store::{ + errors::StateviewError, state_key::StateKey, state_storage_usage::StateStorageUsage, + state_value::StateValue, TStateView, }; use bytes::Bytes; use move_core_types::language_storage::ModuleId; @@ -30,10 +27,8 @@ impl GenesisStateView { } pub(crate) fn add_module(&mut self, module_id: &ModuleId, blob: &[u8]) { - self.state_data.insert( - StateKey::access_path(AccessPath::from(module_id)), - blob.to_vec(), - ); + self.state_data + .insert(StateKey::module_id(module_id), blob.to_vec()); } } diff --git a/aptos-move/vm-genesis/src/lib.rs b/aptos-move/vm-genesis/src/lib.rs index aeac50f7b5528..7c75e466373d7 100644 --- a/aptos-move/vm-genesis/src/lib.rs +++ b/aptos-move/vm-genesis/src/lib.rs @@ -31,9 +31,10 @@ use aptos_types::{ }, move_utils::as_move_value::AsMoveValue, on_chain_config::{ - FeatureFlag, Features, GasScheduleV2, OnChainConsensusConfig, OnChainExecutionConfig, - OnChainJWKConsensusConfig, OnChainRandomnessConfig, RandomnessConfigMoveStruct, - TimedFeaturesBuilder, APTOS_MAX_KNOWN_VERSION, + randomness_api_v0_config::RequiredGasDeposit, FeatureFlag, Features, GasScheduleV2, + OnChainConsensusConfig, OnChainExecutionConfig, OnChainJWKConsensusConfig, + OnChainRandomnessConfig, RandomnessConfigMoveStruct, TimedFeaturesBuilder, + APTOS_MAX_KNOWN_VERSION, }, transaction::{authenticator::AuthenticationKey, ChangeSet, Transaction, WriteSetPayload}, write_set::TransactionWrite, @@ -49,6 +50,7 @@ use move_core_types::{ language_storage::{ModuleId, TypeTag}, value::{serialize_values, MoveTypeLayout, MoveValue}, }; +use move_vm_runtime::module_traversal::{TraversalContext, TraversalStorage}; use move_vm_types::gas::UnmeteredGasMeter; use once_cell::sync::Lazy; use rand::prelude::*; @@ -65,6 +67,7 @@ const JWK_CONSENSUS_CONFIG_MODULE_NAME: &str = "jwk_consensus_config"; const JWKS_MODULE_NAME: &str = "jwks"; const CONFIG_BUFFER_MODULE_NAME: &str = "config_buffer"; const DKG_MODULE_NAME: &str = "dkg"; +const RANDOMNESS_API_V0_CONFIG_MODULE_NAME: &str = "randomness_api_v0_config"; const RANDOMNESS_CONFIG_SEQNUM_MODULE_NAME: &str = "randomness_config_seqnum"; const RANDOMNESS_CONFIG_MODULE_NAME: &str = "randomness_config"; const RANDOMNESS_MODULE_NAME: &str = "randomness"; @@ -138,7 +141,7 @@ pub fn encode_aptos_mainnet_genesis_transaction( ) .unwrap(); let id1 = HashValue::zero(); - let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1)); + let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1), None); // On-chain genesis process. let consensus_config = OnChainConsensusConfig::default_for_genesis(); @@ -179,7 +182,7 @@ pub fn encode_aptos_mainnet_genesis_transaction( let mut id2_arr = [0u8; 32]; id2_arr[31] = 1; let id2 = HashValue::new(id2_arr); - let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id2)); + let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id2), None); publish_framework(&mut session, framework); let additional_change_set = session.finish(&configs).unwrap(); change_set @@ -256,7 +259,7 @@ pub fn encode_genesis_change_set( ) .unwrap(); let id1 = HashValue::zero(); - let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1)); + let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1), None); // On-chain genesis process. initialize( @@ -286,6 +289,7 @@ pub fn encode_genesis_change_set( .randomness_config_override .clone() .unwrap_or_else(OnChainRandomnessConfig::default_for_genesis); + initialize_randomness_api_v0_config(&mut session); initialize_randomness_config_seqnum(&mut session); initialize_randomness_config(&mut session, randomness_config); initialize_randomness_resources(&mut session); @@ -316,7 +320,7 @@ pub fn encode_genesis_change_set( let mut id2_arr = [0u8; 32]; id2_arr[31] = 1; let id2 = HashValue::new(id2_arr); - let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id2)); + let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id2), None); publish_framework(&mut session, framework); let additional_change_set = session.finish(&configs).unwrap(); change_set @@ -383,6 +387,7 @@ fn exec_function( ty_args: Vec, args: Vec>, ) { + let storage = TraversalStorage::new(); session .execute_function_bypass_visibility( &ModuleId::new( @@ -393,6 +398,7 @@ fn exec_function( ty_args, args, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&storage), ) .unwrap_or_else(|e| { panic!( @@ -517,6 +523,19 @@ fn initialize_randomness_config_seqnum(session: &mut SessionExt) { ); } +fn initialize_randomness_api_v0_config(session: &mut SessionExt) { + exec_function( + session, + RANDOMNESS_API_V0_CONFIG_MODULE_NAME, + "initialize", + vec![], + serialize_values(&vec![ + MoveValue::Signer(CORE_CODE_ADDRESS), + RequiredGasDeposit::default_for_genesis().as_move_value(), + ]), + ); +} + fn initialize_randomness_config( session: &mut SessionExt, randomness_config: OnChainRandomnessConfig, @@ -635,7 +654,7 @@ fn initialize_keyless_accounts(session: &mut SessionExt, chain_id: ChainId) { ]), ); if !chain_id.is_mainnet() { - let vk = Groth16VerificationKey::from(DEVNET_VERIFICATION_KEY.clone()); + let vk = Groth16VerificationKey::from(&*DEVNET_VERIFICATION_KEY); exec_function( session, KEYLESS_ACCOUNT_MODULE_NAME, @@ -1077,7 +1096,7 @@ pub fn test_genesis_module_publishing() { ) .unwrap(); let id1 = HashValue::zero(); - let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1)); + let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1), None); publish_framework(&mut session, aptos_cached_packages::head_release_bundle()); } @@ -1290,7 +1309,7 @@ pub fn test_mainnet_end_to_end() { let WriteSet::V0(writeset) = changeset.write_set(); - let state_key = StateKey::on_chain_config::(); + let state_key = StateKey::on_chain_config::().unwrap(); let bytes = writeset .get(&state_key) .unwrap() diff --git a/aptos-move/writeset-transaction-generator/Cargo.toml b/aptos-move/writeset-transaction-generator/Cargo.toml index 95ce154321df1..26933dca31782 100644 --- a/aptos-move/writeset-transaction-generator/Cargo.toml +++ b/aptos-move/writeset-transaction-generator/Cargo.toml @@ -24,6 +24,7 @@ aptos-vm-types = { workspace = true } handlebars = { workspace = true } move-compiler = { workspace = true } move-core-types = { workspace = true } +move-vm-runtime = { workspace = true } move-vm-types = { workspace = true } serde = { workspace = true } tempfile = { workspace = true } diff --git a/aptos-move/writeset-transaction-generator/src/writeset_builder.rs b/aptos-move/writeset-transaction-generator/src/writeset_builder.rs index e3910d44cffa5..1945bd945795b 100644 --- a/aptos-move/writeset-transaction-generator/src/writeset_builder.rs +++ b/aptos-move/writeset-transaction-generator/src/writeset_builder.rs @@ -23,6 +23,7 @@ use move_core_types::{ transaction_argument::convert_txn_args, value::{serialize_values, MoveValue}, }; +use move_vm_runtime::module_traversal::{TraversalContext, TraversalStorage}; use move_vm_types::gas::UnmeteredGasMeter; pub struct GenesisSession<'r, 'l>(SessionExt<'r, 'l>); @@ -35,6 +36,7 @@ impl<'r, 'l> GenesisSession<'r, 'l> { ty_args: Vec, args: Vec>, ) { + let traversal_storage = TraversalStorage::new(); self.0 .execute_function_bypass_visibility( &ModuleId::new( @@ -45,6 +47,7 @@ impl<'r, 'l> GenesisSession<'r, 'l> { ty_args, args, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_or_else(|e| { panic!( @@ -59,12 +62,14 @@ impl<'r, 'l> GenesisSession<'r, 'l> { pub fn exec_script(&mut self, sender: AccountAddress, script: &Script) { let mut temp = vec![sender.to_vec()]; temp.extend(convert_txn_args(script.args())); + let traversal_storage = TraversalStorage::new(); self.0 .execute_script( script.code().to_vec(), script.ty_args().to_vec(), temp, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap() } @@ -120,7 +125,7 @@ where // TODO: specify an id by human and pass that in. let genesis_id = HashValue::zero(); let mut session = - GenesisSession(move_vm.new_session(&resolver, SessionId::genesis(genesis_id))); + GenesisSession(move_vm.new_session(&resolver, SessionId::genesis(genesis_id), None)); session.disable_reconfiguration(); procedure(&mut session); session.enable_reconfiguration(); diff --git a/config/src/config/node_config_loader.rs b/config/src/config/node_config_loader.rs index 41e87855fd550..b5235620ddf58 100644 --- a/config/src/config/node_config_loader.rs +++ b/config/src/config/node_config_loader.rs @@ -166,7 +166,7 @@ fn get_chain_id(node_config: &NodeConfig) -> Result { // Extract the chain ID from the genesis transaction match genesis_txn { Transaction::GenesisTransaction(WriteSetPayload::Direct(change_set)) => { - let chain_id_state_key = StateKey::on_chain_config::(); + let chain_id_state_key = StateKey::on_chain_config::()?; // Get the write op from the write set let write_set_mut = change_set.clone().write_set().clone().into_mut(); diff --git a/consensus/src/dag/adapter.rs b/consensus/src/dag/adapter.rs index b01dfbbb6c0cc..885c4de4d4123 100644 --- a/consensus/src/dag/adapter.rs +++ b/consensus/src/dag/adapter.rs @@ -328,7 +328,7 @@ impl StorageAdapter { Ok(bcs::from_bytes( self.aptos_db .get_state_value_by_version( - &StateKey::on_chain_config::(), + &StateKey::on_chain_config::()?, latest_version, )? .ok_or_else(|| format_err!("Resource doesn't exist"))? @@ -388,7 +388,7 @@ impl DAGStorage for StorageAdapter { let new_block_event = bcs::from_bytes::( self.aptos_db .get_state_value_by_version( - &StateKey::table_item(*handle, bcs::to_bytes(&idx).unwrap()), + &StateKey::table_item(handle, &bcs::to_bytes(&idx).unwrap()), version, )? .ok_or_else(|| format_err!("Table item doesn't exist"))? diff --git a/crates/aptos-crypto/Cargo.toml b/crates/aptos-crypto/Cargo.toml index 6c23189e1b09b..011daed6366fe 100644 --- a/crates/aptos-crypto/Cargo.toml +++ b/crates/aptos-crypto/Cargo.toml @@ -19,6 +19,7 @@ aptos-crypto-derive = { workspace = true } ark-bn254 = { workspace = true } ark-ec = { workspace = true } ark-ff = { workspace = true } +ark-groth16 = { workspace = true } ark-std = { workspace = true } base64 = { workspace = true } bcs = { workspace = true } diff --git a/crates/aptos-crypto/benches/ark_bn254.rs b/crates/aptos-crypto/benches/ark_bn254.rs index d5caa5d701b79..ad6ce0d33d9a2 100644 --- a/crates/aptos-crypto/benches/ark_bn254.rs +++ b/crates/aptos-crypto/benches/ark_bn254.rs @@ -11,12 +11,13 @@ use crate::bench_utils::{ bench_function_pow_u256, bench_function_serialize_uncomp, bench_function_square, bench_function_sub, }; -use ark_bn254::{Fq, Fq12, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; +use ark_bn254::{Bn254, Fq, Fq12, Fr, G1Affine, G1Projective, G2Affine, G2Projective}; use ark_ec::{pairing::Pairing, short_weierstrass::Projective, AffineRepr, CurveGroup, Group}; use ark_ff::{UniformRand, Zero}; +use ark_groth16::Groth16; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::test_rng; -use criterion::{BenchmarkId, Criterion}; +use criterion::{Bencher, BenchmarkId, Criterion}; use std::ops::{Mul, Neg}; mod bench_utils; @@ -48,6 +49,8 @@ macro_rules! serialize { fn bench_group(c: &mut Criterion) { let mut group = c.benchmark_group("ark_bn254"); + group.bench_function("groth16/verify", bench_groth16_verify); + group.bench_function("fr_add", bench_function_add::); group.bench_function("fr_clone", bench_function_clone::); group.bench_function("fr_deser", bench_function_deser_uncomp::); @@ -515,6 +518,33 @@ fn bench_group(c: &mut Criterion) { group.finish(); } +fn bench_groth16_verify(b: &mut Bencher) { + let pvk = ark_groth16::PreparedVerifyingKey { + vk: ark_groth16::VerifyingKey { + alpha_g1: rand!(G1Affine), + beta_g2: rand!(G2Affine), + gamma_g2: rand!(G2Affine), + delta_g2: rand!(G2Affine), + gamma_abc_g1: vec![rand!(G1Affine), rand!(G1Affine)], + }, + alpha_g1_beta_g2: rand!(ark_bn254::Fq12), + gamma_g2_neg_pc: rand!(G2Affine).into(), + delta_g2_neg_pc: rand!(G2Affine).into(), + }; + + b.iter_with_setup( + || ark_groth16::Proof { + a: rand!(G1Affine), + b: rand!(G2Affine), + c: rand!(G1Affine), + }, + |proof| { + let result = Groth16::::verify_proof(&pvk, &proof, &[rand!(Fr)]); + assert!(matches!(result, Ok(false))) + }, + ) +} + criterion_group!( name = ark_bn254_benches; config = Criterion::default(); //.measurement_time(Duration::from_secs(100)); diff --git a/crates/aptos-infallible/src/rwlock.rs b/crates/aptos-infallible/src/rwlock.rs index f705209802881..63840e8fb995c 100644 --- a/crates/aptos-infallible/src/rwlock.rs +++ b/crates/aptos-infallible/src/rwlock.rs @@ -36,6 +36,10 @@ impl RwLock { .into_inner() .expect("Cannot currently handle a poisoned lock") } + + pub fn inner(&self) -> &StdRwLock { + &self.0 + } } #[cfg(test)] diff --git a/crates/aptos-metrics-core/src/lib.rs b/crates/aptos-metrics-core/src/lib.rs index 793bb72d71766..3b7c7b63b2d61 100644 --- a/crates/aptos-metrics-core/src/lib.rs +++ b/crates/aptos-metrics-core/src/lib.rs @@ -35,3 +35,13 @@ impl IntGaugeHelper for IntGaugeVec { self.with_label_values(labels).set(val) } } + +pub trait IntCounterHelper { + fn inc_with(&self, labels: &[&str]); +} + +impl IntCounterHelper for IntCounterVec { + fn inc_with(&self, labels: &[&str]) { + self.with_label_values(labels).inc() + } +} diff --git a/crates/aptos-rosetta/src/types/objects.rs b/crates/aptos-rosetta/src/types/objects.rs index 5fb9b0e075831..62c8ae130b292 100644 --- a/crates/aptos-rosetta/src/types/objects.rs +++ b/crates/aptos-rosetta/src/types/objects.rs @@ -33,7 +33,7 @@ use aptos_types::{ event::EventKey, fee_statement::FeeStatement, stake_pool::{SetOperatorEvent, StakePool}, - state_store::state_key::{StateKey, StateKeyInner}, + state_store::state_key::{inner::StateKeyInner, StateKey}, transaction::{EntryFunction, TransactionPayload}, write_set::{WriteOp, WriteSet}, }; diff --git a/execution/block-partitioner/src/v2/conflicting_txn_tracker.rs b/execution/block-partitioner/src/v2/conflicting_txn_tracker.rs index eeb955d117516..396437b7114ff 100644 --- a/execution/block-partitioner/src/v2/conflicting_txn_tracker.rs +++ b/execution/block-partitioner/src/v2/conflicting_txn_tracker.rs @@ -86,8 +86,7 @@ impl ConflictingTxnTracker { #[test] fn test_conflicting_txn_tracker() { - let mut tracker = - ConflictingTxnTracker::new(StorageLocation::Specific(StateKey::raw(vec![])), 0); + let mut tracker = ConflictingTxnTracker::new(StorageLocation::Specific(StateKey::raw(&[])), 0); tracker.add_write_candidate(4); tracker.add_write_candidate(10); tracker.add_write_candidate(7); diff --git a/execution/executor-benchmark/src/db_access.rs b/execution/executor-benchmark/src/db_access.rs index e1db7197b37f7..44d8f1e89694c 100644 --- a/execution/executor-benchmark/src/db_access.rs +++ b/execution/executor-benchmark/src/db_access.rs @@ -4,7 +4,6 @@ use anyhow::Result; use aptos_storage_interface::state_view::DbStateView; use aptos_types::{ - access_path::AccessPath, account_address::AccountAddress, state_store::{state_key::StateKey, StateView}, write_set::TOTAL_SUPPLY_STATE_KEY, @@ -78,16 +77,11 @@ impl DbAccessUtil { name: &str, type_params: Vec, ) -> StateKey { - StateKey::access_path(AccessPath::new( - address, - AccessPath::resource_path_vec(Self::new_struct_tag( - resource_address, - module, - name, - type_params, - )) - .expect("access path in test"), - )) + StateKey::resource( + &address, + &Self::new_struct_tag(resource_address, module, name, type_params), + ) + .unwrap() } pub fn new_state_key_account(address: AccountAddress) -> StateKey { diff --git a/execution/executor-benchmark/src/lib.rs b/execution/executor-benchmark/src/lib.rs index b686e3210a066..17e7b073863a1 100644 --- a/execution/executor-benchmark/src/lib.rs +++ b/execution/executor-benchmark/src/lib.rs @@ -516,7 +516,9 @@ struct ExecutionTimeMeasurement { impl ExecutionTimeMeasurement { pub fn now() -> Self { - let output_size = APTOS_PROCESSED_TXNS_OUTPUT_SIZE.get_sample_sum(); + let output_size = APTOS_PROCESSED_TXNS_OUTPUT_SIZE + .with_label_values(&["execution"]) + .get_sample_sum(); let partitioning_total = BLOCK_PARTITIONING_SECONDS.get_sample_sum(); let execution_total = APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS.get_sample_sum(); diff --git a/execution/executor-service/src/test_utils.rs b/execution/executor-service/src/test_utils.rs index 5c1854d518aa8..5a65075b74b4a 100644 --- a/execution/executor-service/src/test_utils.rs +++ b/execution/executor-service/src/test_utils.rs @@ -11,7 +11,7 @@ use aptos_types::{ block_executor::{ config::BlockExecutorConfigFromOnchain, partitioner::PartitionedTransactions, }, - state_store::state_key::StateKeyInner, + state_store::state_key::inner::StateKeyInner, transaction::{ analyzed_transaction::AnalyzedTransaction, signature_verified_transaction::SignatureVerifiedTransaction, Transaction, diff --git a/execution/executor/src/components/chunk_output.rs b/execution/executor/src/components/chunk_output.rs index 737bd40b6fdb6..22eb65cc01688 100644 --- a/execution/executor/src/components/chunk_output.rs +++ b/execution/executor/src/components/chunk_output.rs @@ -27,6 +27,7 @@ use aptos_types::{ contract_event::ContractEvent, epoch_state::EpochState, transaction::{ + authenticator::AccountAuthenticator, signature_verified_transaction::{SignatureVerifiedTransaction, TransactionProvider}, BlockOutput, ExecutionStatus, Transaction, TransactionOutput, TransactionOutputProvider, TransactionStatus, @@ -259,7 +260,9 @@ pub fn update_counters_for_processed_chunk( for (txn, output) in transactions.iter().zip(transaction_outputs.iter()) { if detailed_counters { if let Ok(size) = bcs::serialized_size(output.get_transaction_output()) { - metrics::APTOS_PROCESSED_TXNS_OUTPUT_SIZE.observe(size as f64); + metrics::APTOS_PROCESSED_TXNS_OUTPUT_SIZE + .with_label_values(&[process_type]) + .observe(size as f64); } } @@ -345,6 +348,52 @@ pub fn update_counters_for_processed_chunk( } if let Some(Transaction::UserTransaction(user_txn)) = txn.get_transaction() { + if detailed_counters { + let mut signature_count = 0; + let account_authenticators = user_txn.authenticator_ref().all_signers(); + for account_authenticator in account_authenticators { + match account_authenticator { + AccountAuthenticator::Ed25519 { .. } => { + signature_count += 1; + metrics::APTOS_PROCESSED_TXNS_AUTHENTICATOR + .with_label_values(&[process_type, "Ed25519"]) + .inc(); + }, + AccountAuthenticator::MultiEd25519 { signature, .. } => { + let count = signature.signatures().len(); + signature_count += count; + metrics::APTOS_PROCESSED_TXNS_AUTHENTICATOR + .with_label_values(&[process_type, "Ed25519_in_MultiEd25519"]) + .inc_by(count as u64); + }, + AccountAuthenticator::SingleKey { authenticator } => { + signature_count += 1; + metrics::APTOS_PROCESSED_TXNS_AUTHENTICATOR + .with_label_values(&[ + process_type, + &format!("{}_in_SingleKey", authenticator.signature().name()), + ]) + .inc(); + }, + AccountAuthenticator::MultiKey { authenticator } => { + for (_, signature) in authenticator.signatures() { + signature_count += 1; + metrics::APTOS_PROCESSED_TXNS_AUTHENTICATOR + .with_label_values(&[ + process_type, + &format!("{}_in_MultiKey", signature.name()), + ]) + .inc(); + } + }, + }; + } + + metrics::APTOS_PROCESSED_TXNS_NUM_AUTHENTICATORS + .with_label_values(&[process_type]) + .observe(signature_count as f64); + } + match user_txn.payload() { aptos_types::transaction::TransactionPayload::Script(_script) => { metrics::APTOS_PROCESSED_USER_TRANSACTIONS_PAYLOAD_TYPE diff --git a/execution/executor/src/db_bootstrapper.rs b/execution/executor/src/db_bootstrapper.rs index af444331c102c..1be7ea06bf965 100644 --- a/execution/executor/src/db_bootstrapper.rs +++ b/execution/executor/src/db_bootstrapper.rs @@ -14,7 +14,6 @@ use aptos_storage_interface::{ DbWriter, ExecutedTrees, }; use aptos_types::{ - access_path::AccessPath, account_config::CORE_CODE_ADDRESS, aggregate_signature::AggregateSignature, block_executor::config::BlockExecutorConfigFromOnchain, @@ -27,7 +26,6 @@ use aptos_types::{ waypoint::Waypoint, }; use aptos_vm::VMExecutor; -use move_core_types::move_resource::MoveResource; use std::sync::Arc; pub fn generate_waypoint( @@ -214,10 +212,9 @@ pub fn calculate_genesis( fn get_state_timestamp(state_view: &CachedStateView) -> Result { let rsrc_bytes = &state_view - .get_state_value_bytes(&StateKey::access_path(AccessPath::new( - CORE_CODE_ADDRESS, - TimestampResource::resource_path(), - )))? + .get_state_value_bytes(&StateKey::resource_typed::( + &CORE_CODE_ADDRESS, + )?)? .ok_or_else(|| format_err!("TimestampResource missing."))?; let rsrc = bcs::from_bytes::(rsrc_bytes)?; Ok(rsrc.timestamp.microseconds) @@ -225,10 +222,7 @@ fn get_state_timestamp(state_view: &CachedStateView) -> Result { fn get_state_epoch(state_view: &CachedStateView) -> Result { let rsrc_bytes = &state_view - .get_state_value_bytes(&StateKey::access_path(AccessPath::new( - CORE_CODE_ADDRESS, - ConfigurationResource::resource_path(), - )))? + .get_state_value_bytes(&StateKey::on_chain_config::()?)? .ok_or_else(|| format_err!("ConfigurationResource missing."))?; let rsrc = bcs::from_bytes::(rsrc_bytes)?; Ok(rsrc.epoch()) diff --git a/execution/executor/src/metrics.rs b/execution/executor/src/metrics.rs index 34e656b80ed55..bedb969397b92 100644 --- a/execution/executor/src/metrics.rs +++ b/execution/executor/src/metrics.rs @@ -211,11 +211,31 @@ pub static APTOS_PROCESSED_USER_TRANSACTIONS_CORE_EVENTS: Lazy = .unwrap() }); -pub static APTOS_PROCESSED_TXNS_OUTPUT_SIZE: Lazy = Lazy::new(|| { - register_histogram!( +pub static APTOS_PROCESSED_TXNS_OUTPUT_SIZE: Lazy = Lazy::new(|| { + register_histogram_vec!( "aptos_processed_txns_output_size", - "Histogram of transaction outputs", + "Histogram of transaction output sizes", + &["process"], exponential_buckets(/*start=*/ 1.0, /*factor=*/ 2.0, /*count=*/ 25).unwrap() ) .unwrap() }); + +pub static APTOS_PROCESSED_TXNS_NUM_AUTHENTICATORS: Lazy = Lazy::new(|| { + register_histogram_vec!( + "aptos_processed_txns_num_authenticators", + "Histogram of number of authenticators in a transaction", + &["process"], + exponential_buckets(/*start=*/ 1.0, /*factor=*/ 2.0, /*count=*/ 6).unwrap() + ) + .unwrap() +}); + +pub static APTOS_PROCESSED_TXNS_AUTHENTICATOR: Lazy = Lazy::new(|| { + register_int_counter_vec!( + "aptos_processed_txns_authenticator", + "Counter of authenticators by type, for processed transactions", + &["process", "auth_type"] + ) + .unwrap() +}); diff --git a/execution/executor/src/mock_vm/mock_vm_test.rs b/execution/executor/src/mock_vm/mock_vm_test.rs index 07b2d08d9ac1d..3e54400c4c866 100644 --- a/execution/executor/src/mock_vm/mock_vm_test.rs +++ b/execution/executor/src/mock_vm/mock_vm_test.rs @@ -58,11 +58,11 @@ fn test_mock_vm_different_senders() { .collect::>(), [ ( - StateKey::access_path(balance_ap(sender)), + StateKey::raw(&balance_ap(sender)), WriteOp::legacy_modification(amount.le_bytes()), ), ( - StateKey::access_path(seqnum_ap(sender)), + StateKey::raw(&seqnum_ap(sender)), WriteOp::legacy_modification(1u64.le_bytes()), ), ] @@ -94,11 +94,11 @@ fn test_mock_vm_same_sender() { .collect::>(), [ ( - StateKey::access_path(balance_ap(sender)), + StateKey::raw(&balance_ap(sender)), WriteOp::legacy_modification((amount * (i as u64 + 1)).le_bytes()), ), ( - StateKey::access_path(seqnum_ap(sender)), + StateKey::raw(&seqnum_ap(sender)), WriteOp::legacy_modification((i as u64 + 1).le_bytes()), ), ] @@ -133,15 +133,15 @@ fn test_mock_vm_payment() { .collect::>(), [ ( - StateKey::access_path(balance_ap(gen_address(0))), + StateKey::raw(&balance_ap(gen_address(0))), WriteOp::legacy_modification(50u64.le_bytes()) ), ( - StateKey::access_path(seqnum_ap(gen_address(0))), + StateKey::raw(&seqnum_ap(gen_address(0))), WriteOp::legacy_modification(2u64.le_bytes()) ), ( - StateKey::access_path(balance_ap(gen_address(1))), + StateKey::raw(&balance_ap(gen_address(1))), WriteOp::legacy_modification(150u64.le_bytes()) ), ] diff --git a/execution/executor/src/mock_vm/mod.rs b/execution/executor/src/mock_vm/mod.rs index e94fbaf3c033d..9c0401887f6e6 100644 --- a/execution/executor/src/mock_vm/mod.rs +++ b/execution/executor/src/mock_vm/mod.rs @@ -10,9 +10,7 @@ use anyhow::Result; use aptos_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; use aptos_storage_interface::cached_state_view::CachedStateView; use aptos_types::{ - access_path::AccessPath, account_address::AccountAddress, - account_config::CORE_CODE_ADDRESS, block_executor::{ config::BlockExecutorConfigFromOnchain, partitioner::{ExecutableTransactions, PartitionedTransactions}, @@ -21,10 +19,7 @@ use aptos_types::{ chain_id::ChainId, contract_event::ContractEvent, event::EventKey, - on_chain_config::{ - access_path_for_config, new_epoch_event_key, ConfigurationResource, OnChainConfig, - ValidatorSet, - }, + on_chain_config::{new_epoch_event_key, ConfigurationResource, ValidatorSet}, state_store::{state_key::StateKey, StateView}, transaction::{ signature_verified_transaction::SignatureVerifiedTransaction, BlockOutput, ChangeSet, @@ -39,7 +34,7 @@ use aptos_vm::{ sharded_block_executor::{executor_client::ExecutorClient, ShardedBlockExecutor}, VMExecutor, }; -use move_core_types::{language_storage::TypeTag, move_resource::MoveResource}; +use move_core_types::language_storage::TypeTag; use once_cell::sync::Lazy; use std::{collections::HashMap, sync::Arc}; @@ -102,12 +97,11 @@ impl VMExecutor for MockVM { if matches!(txn, Transaction::GenesisTransaction(_)) { read_state_value_from_storage( state_view, - &access_path_for_config(ValidatorSet::CONFIG_ID) - .map_err(|_| VMStatus::error(StatusCode::TOO_MANY_TYPE_NODES, None))?, + &StateKey::on_chain_config::().unwrap(), ); read_state_value_from_storage( state_view, - &AccessPath::new(CORE_CODE_ADDRESS, ConfigurationResource::resource_path()), + &StateKey::on_chain_config::().unwrap(), ); outputs.push(TransactionOutput::new( // WriteSet cannot be empty so use genesis writeset only for testing. @@ -206,7 +200,7 @@ impl VMExecutor for MockVM { } fn read_balance( - output_cache: &HashMap, + output_cache: &HashMap, u64>, state_view: &impl StateView, account: AccountAddress, ) -> u64 { @@ -218,7 +212,7 @@ fn read_balance( } fn read_seqnum( - output_cache: &HashMap, + output_cache: &HashMap, u64>, state_view: &impl StateView, account: AccountAddress, ) -> u64 { @@ -229,27 +223,27 @@ fn read_seqnum( } } -fn read_balance_from_storage(state_view: &impl StateView, balance_access_path: &AccessPath) -> u64 { +fn read_balance_from_storage(state_view: &impl StateView, balance_access_path: &[u8]) -> u64 { read_u64_from_storage(state_view, balance_access_path) } -fn read_seqnum_from_storage(state_view: &impl StateView, seqnum_access_path: &AccessPath) -> u64 { +fn read_seqnum_from_storage(state_view: &impl StateView, seqnum_access_path: &[u8]) -> u64 { read_u64_from_storage(state_view, seqnum_access_path) } -fn read_u64_from_storage(state_view: &impl StateView, access_path: &AccessPath) -> u64 { +fn read_u64_from_storage(state_view: &impl StateView, access_path: &[u8]) -> u64 { state_view - .get_state_value_bytes(&StateKey::access_path(access_path.clone())) + .get_state_value_bytes(&StateKey::raw(access_path)) .expect("Failed to query storage.") .map_or(0, |bytes| decode_bytes(&bytes)) } fn read_state_value_from_storage( state_view: &impl StateView, - access_path: &AccessPath, + state_key: &StateKey, ) -> Option> { state_view - .get_state_value_bytes(&StateKey::access_path(access_path.clone())) + .get_state_value_bytes(state_key) .expect("Failed to query storage.") .map(|bytes| bytes.to_vec()) } @@ -260,27 +254,26 @@ fn decode_bytes(bytes: &[u8]) -> u64 { u64::from_le_bytes(buf) } -fn balance_ap(account: AccountAddress) -> AccessPath { - AccessPath::new(account, b"balance".to_vec()) +fn balance_ap(account: AccountAddress) -> Vec { + let mut path = account.to_vec(); + path.extend(b"balance"); + path } -fn seqnum_ap(account: AccountAddress) -> AccessPath { - AccessPath::new(account, b"seqnum".to_vec()) +fn seqnum_ap(account: AccountAddress) -> Vec { + let mut path = account.to_vec(); + path.extend(b"seqnum"); + path } fn gen_genesis_writeset() -> WriteSet { let mut write_set = WriteSetMut::default(); - let validator_set_ap = - access_path_for_config(ValidatorSet::CONFIG_ID).expect("access path in test"); write_set.insert(( - StateKey::access_path(validator_set_ap), + StateKey::on_chain_config::().unwrap(), WriteOp::legacy_modification(bcs::to_bytes(&ValidatorSet::new(vec![])).unwrap().into()), )); write_set.insert(( - StateKey::access_path(AccessPath::new( - CORE_CODE_ADDRESS, - ConfigurationResource::resource_path(), - )), + StateKey::on_chain_config::().unwrap(), WriteOp::legacy_modification( bcs::to_bytes(&ConfigurationResource::default()) .unwrap() @@ -295,11 +288,11 @@ fn gen_genesis_writeset() -> WriteSet { fn gen_mint_writeset(sender: AccountAddress, balance: u64, seqnum: u64) -> WriteSet { let mut write_set = WriteSetMut::default(); write_set.insert(( - StateKey::access_path(balance_ap(sender)), + StateKey::raw(&balance_ap(sender)), WriteOp::legacy_modification(balance.le_bytes()), )); write_set.insert(( - StateKey::access_path(seqnum_ap(sender)), + StateKey::raw(&seqnum_ap(sender)), WriteOp::legacy_modification(seqnum.le_bytes()), )); write_set.freeze().expect("mint writeset should be valid") @@ -314,15 +307,15 @@ fn gen_payment_writeset( ) -> WriteSet { let mut write_set = WriteSetMut::default(); write_set.insert(( - StateKey::access_path(balance_ap(sender)), + StateKey::raw(&balance_ap(sender)), WriteOp::legacy_modification(sender_balance.le_bytes()), )); write_set.insert(( - StateKey::access_path(seqnum_ap(sender)), + StateKey::raw(&seqnum_ap(sender)), WriteOp::legacy_modification(sender_seqnum.le_bytes()), )); write_set.insert(( - StateKey::access_path(balance_ap(recipient)), + StateKey::raw(&balance_ap(recipient)), WriteOp::legacy_modification(recipient_balance.le_bytes()), )); write_set diff --git a/execution/executor/src/tests/mod.rs b/execution/executor/src/tests/mod.rs index 608b2e6f50ff0..9a9b0bf0d4fc9 100644 --- a/execution/executor/src/tests/mod.rs +++ b/execution/executor/src/tests/mod.rs @@ -513,9 +513,9 @@ fn apply_transaction_by_writeset( fn test_deleted_key_from_state_store() { let executor = TestExecutor::new(); let db = &executor.db; - let dummy_state_key1 = StateKey::raw(String::from("test_key1").into_bytes()); + let dummy_state_key1 = StateKey::raw(b"test_key1"); let dummy_value1 = 10u64.le_bytes(); - let dummy_state_key2 = StateKey::raw(String::from("test_key2").into_bytes()); + let dummy_state_key2 = StateKey::raw(b"test_key2"); let dummy_value2 = 20u64.le_bytes(); // Create test transaction, event and transaction output let transaction1 = create_test_transaction(0); diff --git a/execution/executor/tests/db_bootstrapper_test.rs b/execution/executor/tests/db_bootstrapper_test.rs index 2c40b93c67025..8fa93a668e9bf 100644 --- a/execution/executor/tests/db_bootstrapper_test.rs +++ b/execution/executor/tests/db_bootstrapper_test.rs @@ -18,15 +18,13 @@ use aptos_executor_types::BlockExecutorTrait; use aptos_storage_interface::{state_view::LatestDbStateCheckpointView, DbReaderWriter}; use aptos_temppath::TempPath; use aptos_types::{ - access_path::AccessPath, account_address::AccountAddress, account_config::{ aptos_test_root_address, new_block_event_key, CoinStoreResource, NewBlockEvent, - CORE_CODE_ADDRESS, }, contract_event::ContractEvent, event::EventHandle, - on_chain_config::{access_path_for_config, ConfigurationResource, OnChainConfig, ValidatorSet}, + on_chain_config::{ConfigurationResource, OnChainConfig, ValidatorSet}, state_store::{state_key::StateKey, MoveResourceExt}, test_helpers::transaction_test_helpers::{block, TEST_BLOCK_EXECUTOR_ONCHAIN_CONFIG}, transaction::{authenticator::AuthenticationKey, ChangeSet, Transaction, WriteSetPayload}, @@ -36,10 +34,7 @@ use aptos_types::{ write_set::{WriteOp, WriteSetMut}, }; use aptos_vm::AptosVM; -use move_core_types::{ - language_storage::TypeTag, - move_resource::{MoveResource, MoveStructType}, -}; +use move_core_types::{language_storage::TypeTag, move_resource::MoveStructType}; use rand::SeedableRng; #[test] @@ -217,18 +212,13 @@ fn test_new_genesis() { let genesis_txn = Transaction::GenesisTransaction(WriteSetPayload::Direct(ChangeSet::new( WriteSetMut::new(vec![ ( - StateKey::access_path( - access_path_for_config(ValidatorSet::CONFIG_ID).expect("access path in test"), - ), + StateKey::on_chain_config::().unwrap(), WriteOp::legacy_modification( bcs::to_bytes(&ValidatorSet::new(vec![])).unwrap().into(), ), ), ( - StateKey::access_path(AccessPath::new( - CORE_CODE_ADDRESS, - ConfigurationResource::resource_path(), - )), + StateKey::on_chain_config::().unwrap(), WriteOp::legacy_modification( bcs::to_bytes(&configuration.bump_epoch_for_test()) .unwrap() @@ -236,10 +226,7 @@ fn test_new_genesis() { ), ), ( - StateKey::access_path(AccessPath::new( - account1, - CoinStoreResource::resource_path(), - )), + StateKey::resource_typed::(&account1).unwrap(), WriteOp::legacy_modification( bcs::to_bytes(&CoinStoreResource::new( 100_000_000, diff --git a/execution/executor/tests/storage_integration_test.rs b/execution/executor/tests/storage_integration_test.rs index a21d8022c3388..5e63e7da8b3df 100644 --- a/execution/executor/tests/storage_integration_test.rs +++ b/execution/executor/tests/storage_integration_test.rs @@ -13,7 +13,6 @@ use aptos_executor_test_helpers::{ use aptos_executor_types::BlockExecutorTrait; use aptos_storage_interface::state_view::DbStateViewAtVersion; use aptos_types::{ - access_path::AccessPath, account_config::{aptos_test_root_address, AccountResource, CORE_CODE_ADDRESS}, block_metadata::BlockMetadata, on_chain_config::{AptosVersion, OnChainConfig, ValidatorSet}, @@ -26,7 +25,6 @@ use aptos_types::{ validator_config::ValidatorConfig, validator_signer::ValidatorSigner, }; -use move_core_types::move_resource::MoveStructType; #[test] fn test_genesis() { @@ -42,10 +40,8 @@ fn test_genesis() { let li = state_proof.latest_ledger_info(); assert_eq!(li.version(), 0); - let account_resource_path = StateKey::access_path(AccessPath::new( - CORE_CODE_ADDRESS, - AccountResource::struct_tag().access_vector(), - )); + let account_resource_path = + StateKey::resource_typed::(&CORE_CODE_ADDRESS).unwrap(); let (aptos_framework_account_resource, state_proof) = db .reader .get_state_value_with_proof_by_version(&account_resource_path, 0) diff --git a/experimental/execution/ptx-executor/src/finalizer.rs b/experimental/execution/ptx-executor/src/finalizer.rs index 6190dd5d05f56..b4588229deae8 100644 --- a/experimental/execution/ptx-executor/src/finalizer.rs +++ b/experimental/execution/ptx-executor/src/finalizer.rs @@ -25,10 +25,10 @@ use std::{ pub static TOTAL_SUPPLY_STATE_KEY: Lazy = Lazy::new(|| { StateKey::table_item( - "1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca" + &"1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca" .parse() .unwrap(), - vec![ + &[ 6, 25, 220, 41, 160, 170, 200, 250, 20, 103, 20, 5, 142, 141, 214, 210, 208, 243, 189, 245, 246, 51, 25, 7, 191, 145, 243, 172, 216, 30, 105, 53, ], diff --git a/mempool/src/counters.rs b/mempool/src/counters.rs index 10a0b06fe9459..fc46587579e73 100644 --- a/mempool/src/counters.rs +++ b/mempool/src/counters.rs @@ -99,11 +99,14 @@ pub const SUBMITTED_BY_CLIENT_LABEL: &str = "client"; pub const SUBMITTED_BY_DOWNSTREAM_LABEL: &str = "downstream"; pub const SUBMITTED_BY_PEER_VALIDATOR_LABEL: &str = "peer_validator"; -// Histogram buckets that expand DEFAULT_BUCKETS with larger timescales and some constant sized -// buckets between: 50-250ms (every 25ms), 250ms-5s (250ms), 5-10s (1s), and 10-25s (2.5s). +// Histogram buckets with a large range of 0-500s and some constant sized buckets between: +// 0-1.5s (every 25ms), 1.5-2s (every 100ms), 2-5s (250ms), 5-10s (1s), and 10-25s (2.5s). const MEMPOOL_LATENCY_BUCKETS: &[f64] = &[ - 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.125, 0.15, 0.175, 0.2, 0.225, 0.25, 0.5, 0.75, 1.0, - 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.25, 4.5, 4.75, 5.0, 6.0, + 0.025, 0.05, 0.075, 0.1, 0.125, 0.15, 0.175, 0.2, 0.225, 0.250, 0.275, 0.3, 0.325, 0.35, 0.375, + 0.4, 0.425, 0.45, 0.475, 0.5, 0.525, 0.55, 0.575, 0.6, 0.625, 0.65, 0.675, 0.7, 0.725, 0.75, + 0.775, 0.8, 0.825, 0.85, 0.875, 0.9, 0.925, 0.95, 0.975, 1.0, 1.025, 1.05, 1.075, 1.1, 1.125, + 1.15, 1.175, 1.2, 1.225, 1.25, 1.275, 1.3, 1.325, 1.35, 1.375, 1.4, 1.425, 1.45, 1.475, 1.5, + 1.6, 1.7, 1.8, 1.9, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.25, 4.5, 4.75, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 12.5, 15.0, 17.5, 20.0, 22.5, 25.0, 50.0, 100.0, 250.0, 500.0, ]; diff --git a/network/framework/Cargo.toml b/network/framework/Cargo.toml index 5fff89a87058f..fc9ede7291c34 100644 --- a/network/framework/Cargo.toml +++ b/network/framework/Cargo.toml @@ -43,11 +43,12 @@ maplit = { workspace = true } once_cell = { workspace = true } ordered-float = { workspace = true } pin-project = { workspace = true } -proptest ={ workspace = true, optional = true } +proptest = { workspace = true, optional = true } proptest-derive = { workspace = true, optional = true } rand = { workspace = true, features = ["small_rng"] } # Note: we cannot rely on the workspace version of rand. So we use this workaround. See: # https://github.com/aptos-labs/aptos-core/blob/main/state-sync/aptos-data-client/Cargo.toml#L41. +# See also https://github.com/aptos-labs/aptos-core/issues/13031 rand_latest = { package = "rand", version = "0.8.5" } serde = { workspace = true } serde_bytes = { workspace = true } diff --git a/package.json b/package.json index 35dce55127a9b..7fa0fac219c6b 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "description": "This is a pure dependency package.json which installs dependencies for js utility scripts used in the repo", + "description": "This package.json installs dependencies for JavaScript utility scripts used in the repo", "packageManager": "pnpm@8.3.1", "private": true, "type": "module", @@ -18,4 +18,4 @@ "@actions/core": "^1.10.1", "toml": "^3.0.0" } -} \ No newline at end of file +} diff --git a/sdk/src/types.rs b/sdk/src/types.rs index 4896cef3069b8..353bc21baa732 100644 --- a/sdk/src/types.rs +++ b/sdk/src/types.rs @@ -92,6 +92,13 @@ pub struct LocalAccount { sequence_number: AtomicU64, } +pub fn get_apt_primary_store_address(address: AccountAddress) -> AccountAddress { + let mut bytes = address.to_vec(); + bytes.append(&mut AccountAddress::ONE.to_vec()); + bytes.push(0xFC); + AccountAddress::from_bytes(aptos_crypto::hash::HashValue::sha3_256_of(&bytes).to_vec()).unwrap() +} + impl LocalAccount { /// Create a new representation of an account locally. Note: This function /// does not actually create an account on the Aptos blockchain, just a diff --git a/state-sync/aptos-data-client/Cargo.toml b/state-sync/aptos-data-client/Cargo.toml index d50edc3306f87..2cfdbce376a1c 100644 --- a/state-sync/aptos-data-client/Cargo.toml +++ b/state-sync/aptos-data-client/Cargo.toml @@ -38,6 +38,7 @@ ordered-float = { workspace = true } # it's not trivial to update rand on the workspace because of several dependency # issues (e.g., other outdated crate versions). This is why we fix the version here. # Eventually we'll need to update the workspace to use the latest version of rand. +# See also https://github.com/aptos-labs/aptos-core/issues/13031 rand = "0.8.5" serde = { workspace = true } thiserror = { workspace = true } diff --git a/state-sync/data-streaming-service/src/tests/data_stream.rs b/state-sync/data-streaming-service/src/tests/data_stream.rs index c3ebcab82cdc7..c62e854110dcf 100644 --- a/state-sync/data-streaming-service/src/tests/data_stream.rs +++ b/state-sync/data-streaming-service/src/tests/data_stream.rs @@ -3700,7 +3700,7 @@ fn set_state_value_response_in_queue( last_index: last_state_value_index, first_key: Default::default(), last_key: Default::default(), - raw_values: vec![(StateKey::raw(vec![]), StateValue::new_legacy(vec![].into()))], + raw_values: vec![(StateKey::raw(&[]), StateValue::new_legacy(vec![].into()))], proof: SparseMerkleRangeProof::new(vec![]), root_hash: Default::default(), }), diff --git a/state-sync/data-streaming-service/src/tests/missing_data.rs b/state-sync/data-streaming-service/src/tests/missing_data.rs index 811a9fbbcf0be..df70d4af21f5d 100644 --- a/state-sync/data-streaming-service/src/tests/missing_data.rs +++ b/state-sync/data-streaming-service/src/tests/missing_data.rs @@ -171,7 +171,7 @@ fn create_missing_data_request_state_values() { // Create the partial response payload let last_response_index = end_index - 1; let raw_values = (start_index..last_response_index + 1) - .map(|_| (StateKey::raw(vec![]), StateValue::new_legacy(vec![].into()))) + .map(|_| (StateKey::raw(&[]), StateValue::new_legacy(vec![].into()))) .collect::>(); let response_payload = ResponsePayload::StateValuesWithProof(StateValueChunkWithProof { first_index: start_index, @@ -197,7 +197,7 @@ fn create_missing_data_request_state_values() { // Create a complete response payload let last_response_index = end_index; let raw_values = (start_index..last_response_index + 1) - .map(|_| (StateKey::raw(vec![]), StateValue::new_legacy(vec![].into()))) + .map(|_| (StateKey::raw(&[]), StateValue::new_legacy(vec![].into()))) .collect::>(); let response_payload = ResponsePayload::StateValuesWithProof(StateValueChunkWithProof { first_index: start_index, @@ -869,7 +869,7 @@ fn create_state_value_chunk( ) -> StateValueChunkWithProof { // Create the raw values let raw_values = (0..num_values) - .map(|_| (StateKey::raw(vec![]), StateValue::new_legacy(vec![].into()))) + .map(|_| (StateKey::raw(&[]), StateValue::new_legacy(vec![].into()))) .collect::>(); // Create the chunk of state values diff --git a/state-sync/data-streaming-service/src/tests/utils.rs b/state-sync/data-streaming-service/src/tests/utils.rs index fbf0810efd9c9..23e8f7d1285e5 100644 --- a/state-sync/data-streaming-service/src/tests/utils.rs +++ b/state-sync/data-streaming-service/src/tests/utils.rs @@ -307,7 +307,7 @@ impl AptosDataClientInterface for MockAptosDataClient { let mut state_keys_and_values = vec![]; for _ in start_index..=end_index { state_keys_and_values.push(( - StateKey::raw(HashValue::random().to_vec()), + StateKey::raw(HashValue::random().as_ref()), StateValue::from(vec![]), )); } diff --git a/state-sync/inter-component/event-notifications/src/lib.rs b/state-sync/inter-component/event-notifications/src/lib.rs index 013226ae606cb..6bf500a05afba 100644 --- a/state-sync/inter-component/event-notifications/src/lib.rs +++ b/state-sync/inter-component/event-notifications/src/lib.rs @@ -394,10 +394,10 @@ impl DbBackedOnChainConfig { } impl OnChainConfigProvider for DbBackedOnChainConfig { - fn get(&self) -> anyhow::Result { + fn get(&self) -> Result { let bytes = self .reader - .get_state_value_by_version(&StateKey::on_chain_config::(), self.version)? + .get_state_value_by_version(&StateKey::on_chain_config::()?, self.version)? .ok_or_else(|| { anyhow!( "no config {} found in aptos root account state", diff --git a/state-sync/storage-service/server/src/tests/state_values.rs b/state-sync/storage-service/server/src/tests/state_values.rs index ef17f1ef2b4a9..b270de8bbe832 100644 --- a/state-sync/storage-service/server/src/tests/state_values.rs +++ b/state-sync/storage-service/server/src/tests/state_values.rs @@ -192,7 +192,7 @@ fn create_state_keys_and_values( (0..num_keys_and_values) .map(|_| { let state_value = StateValue::new_legacy(random_bytes.clone()); - (StateKey::raw(vec![]), state_value) + (StateKey::raw(&[]), state_value) }) .collect() } diff --git a/storage/aptosdb/src/db/aptosdb_test.rs b/storage/aptosdb/src/db/aptosdb_test.rs index 338d1a1686bb7..4bf735c2fd8c0 100644 --- a/storage/aptosdb/src/db/aptosdb_test.rs +++ b/storage/aptosdb/src/db/aptosdb_test.rs @@ -182,8 +182,8 @@ fn test_get_latest_executed_trees() { assert!(empty.is_same_view(&ExecutedTrees::new_empty())); // bootstrapped db (any transaction info is in) - let key = StateKey::raw(String::from("test_key").into_bytes()); - let value = StateValue::from(String::from("test_val").into_bytes()); + let key = StateKey::raw(b"test_key"); + let value = StateValue::from(b"test_val".to_vec()); let hash = SparseMerkleLeafNode::new(key.hash(), value.hash()).hash(); put_as_state_root(&db, 0, key, value); let txn_info = TransactionInfo::new( diff --git a/storage/aptosdb/src/db/fake_aptosdb.rs b/storage/aptosdb/src/db/fake_aptosdb.rs index e6ba33483d5ad..918c615d13105 100644 --- a/storage/aptosdb/src/db/fake_aptosdb.rs +++ b/storage/aptosdb/src/db/fake_aptosdb.rs @@ -37,8 +37,7 @@ use aptos_types::{ state_proof::StateProof, state_store::{ combine_sharded_state_updates, - state_key::StateKey, - state_key_prefix::StateKeyPrefix, + state_key::{prefix::StateKeyPrefix, StateKey}, state_storage_usage::StateStorageUsage, state_value::{StateValue, StateValueChunkWithProof}, table, ShardedStateUpdates, diff --git a/storage/aptosdb/src/db/mod.rs b/storage/aptosdb/src/db/mod.rs index bda191d434177..50bf9e72e4d5e 100644 --- a/storage/aptosdb/src/db/mod.rs +++ b/storage/aptosdb/src/db/mod.rs @@ -57,8 +57,7 @@ use aptos_types::{ }, state_proof::StateProof, state_store::{ - state_key::StateKey, - state_key_prefix::StateKeyPrefix, + state_key::{prefix::StateKeyPrefix, StateKey}, state_storage_usage::StateStorageUsage, state_value::{StateValue, StateValueChunkWithProof}, table::{TableHandle, TableInfo}, diff --git a/storage/aptosdb/src/pruner/state_merkle_pruner/test.rs b/storage/aptosdb/src/pruner/state_merkle_pruner/test.rs index c943d2200ac98..99a19f9acfe9a 100644 --- a/storage/aptosdb/src/pruner/state_merkle_pruner/test.rs +++ b/storage/aptosdb/src/pruner/state_merkle_pruner/test.rs @@ -111,7 +111,7 @@ fn create_state_merkle_pruner_manager( #[test] fn test_state_store_pruner() { - let key = StateKey::raw(String::from("test_key1").into_bytes()); + let key = StateKey::raw(b"test_key1"); let prune_batch_size = 10; let num_versions = 25; @@ -188,9 +188,9 @@ fn test_state_store_pruner_partial_version() { // ``` // On version 1, there are two entries, one changes address2 and the other changes the root node. // On version 2, there are two entries, one changes address3 and the other changes the root node. - let key1 = StateKey::raw(String::from("test_key1").into_bytes()); - let key2 = StateKey::raw(String::from("test_key2").into_bytes()); - let key3 = StateKey::raw(String::from("test_key3").into_bytes()); + let key1 = StateKey::raw(b"test_key1"); + let key2 = StateKey::raw(b"test_key2"); + let key3 = StateKey::raw(b"test_key3"); let value1 = StateValue::from(String::from("test_val1").into_bytes()); let value2 = StateValue::from(String::from("test_val2").into_bytes()); @@ -298,7 +298,7 @@ fn test_state_store_pruner_partial_version() { #[test] fn test_state_store_pruner_disabled() { - let key = StateKey::raw(String::from("test_key1").into_bytes()); + let key = StateKey::raw(b"test_key1"); let prune_batch_size = 10; let num_versions = 25; diff --git a/storage/aptosdb/src/schema/state_value/mod.rs b/storage/aptosdb/src/schema/state_value/mod.rs index dcbd76df623e1..d45e1f5f4f521 100644 --- a/storage/aptosdb/src/schema/state_value/mod.rs +++ b/storage/aptosdb/src/schema/state_value/mod.rs @@ -21,7 +21,10 @@ use aptos_schemadb::{ schema::{KeyCodec, SeekKeyCodec, ValueCodec}, }; use aptos_types::{ - state_store::{state_key::StateKey, state_key_prefix::StateKeyPrefix, state_value::StateValue}, + state_store::{ + state_key::{prefix::StateKeyPrefix, StateKey}, + state_value::StateValue, + }, transaction::Version, }; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; diff --git a/storage/aptosdb/src/schema/state_value_index/mod.rs b/storage/aptosdb/src/schema/state_value_index/mod.rs index c1ce0d65d8b88..d44a45a5c9bca 100644 --- a/storage/aptosdb/src/schema/state_value_index/mod.rs +++ b/storage/aptosdb/src/schema/state_value_index/mod.rs @@ -17,7 +17,7 @@ use aptos_schemadb::{ schema::{KeyCodec, SeekKeyCodec, ValueCodec}, }; use aptos_types::{ - state_store::{state_key::StateKey, state_key_prefix::StateKeyPrefix}, + state_store::state_key::{prefix::StateKeyPrefix, StateKey}, transaction::Version, }; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; diff --git a/storage/aptosdb/src/state_kv_db.rs b/storage/aptosdb/src/state_kv_db.rs index 00272a40d35b6..05ec243374f76 100644 --- a/storage/aptosdb/src/state_kv_db.rs +++ b/storage/aptosdb/src/state_kv_db.rs @@ -89,7 +89,7 @@ impl StateKvDb { }; if let Some(overall_kv_commit_progress) = get_state_kv_commit_progress(&state_kv_db)? { - truncate_state_kv_db_shards(&state_kv_db, overall_kv_commit_progress, None)?; + truncate_state_kv_db_shards(&state_kv_db, overall_kv_commit_progress)?; } Ok(state_kv_db) diff --git a/storage/aptosdb/src/state_store/mod.rs b/storage/aptosdb/src/state_store/mod.rs index 5c3cd2a547c52..49819bb8f41e6 100644 --- a/storage/aptosdb/src/state_store/mod.rs +++ b/storage/aptosdb/src/state_store/mod.rs @@ -54,8 +54,7 @@ use aptos_types::{ proof::{definition::LeafCount, SparseMerkleProofExt, SparseMerkleRangeProof}, state_store::{ create_empty_sharded_state_updates, - state_key::StateKey, - state_key_prefix::StateKeyPrefix, + state_key::{prefix::StateKeyPrefix, StateKey}, state_storage_usage::StateStorageUsage, state_value::{StaleStateValueIndex, StateValue, StateValueChunkWithProof}, ShardedStateUpdates, StateViewId, @@ -370,23 +369,23 @@ impl StateStore { truncate_ledger_db(ledger_db, overall_commit_progress) .expect("Failed to truncate ledger db."); - if state_kv_commit_progress != overall_commit_progress { - info!( - state_kv_commit_progress = state_kv_commit_progress, - "Start state KV truncation..." - ); - let difference = state_kv_commit_progress - overall_commit_progress; - if crash_if_difference_is_too_large { - assert_le!(difference, MAX_COMMIT_PROGRESS_DIFFERENCE); - } - truncate_state_kv_db( - &state_kv_db, - state_kv_commit_progress, - overall_commit_progress, - difference as usize, - ) - .expect("Failed to truncate state K/V db."); + // State K/V commit progress isn't (can't be) written atomically with the data, + // because there are shards, so we have to attempt truncation anyway. + info!( + state_kv_commit_progress = state_kv_commit_progress, + "Start state KV truncation..." + ); + let difference = state_kv_commit_progress - overall_commit_progress; + if crash_if_difference_is_too_large { + assert_le!(difference, MAX_COMMIT_PROGRESS_DIFFERENCE); } + truncate_state_kv_db( + &state_kv_db, + state_kv_commit_progress, + overall_commit_progress, + difference as usize, + ) + .expect("Failed to truncate state K/V db."); } else { info!("No overall commit progress was found!"); } diff --git a/storage/aptosdb/src/state_store/state_store_test.rs b/storage/aptosdb/src/state_store/state_store_test.rs index 2b28bebe18b95..9a1fc0e856bbf 100644 --- a/storage/aptosdb/src/state_store/state_store_test.rs +++ b/storage/aptosdb/src/state_store/state_store_test.rs @@ -19,8 +19,10 @@ use aptos_storage_interface::{ }; use aptos_temppath::TempPath; use aptos_types::{ - access_path::AccessPath, account_address::AccountAddress, nibble::nibble_path::NibblePath, - state_store::state_key::StateKeyTag, + account_address::AccountAddress, + account_config::{AccountResource, ChainIdResource, CoinInfoResource, CoinStoreResource}, + nibble::nibble_path::NibblePath, + state_store::state_key::inner::StateKeyTag, }; use arr_macro::arr; use proptest::{collection::hash_map, prelude::*}; @@ -114,7 +116,7 @@ fn test_empty_store() { let tmp_dir = TempPath::new(); let db = AptosDB::new_for_test(&tmp_dir); let store = &db.state_store; - let key = StateKey::raw(String::from("test_key").into_bytes()); + let key = StateKey::raw(b"test_key"); assert!(store .get_state_value_with_proof_by_version(&key, 0) .is_err()); @@ -125,9 +127,9 @@ fn test_state_store_reader_writer() { let tmp_dir = TempPath::new(); let db = AptosDB::new_for_test(&tmp_dir); let store = &db.state_store; - let key1 = StateKey::raw(String::from("test_key1").into_bytes()); - let key2 = StateKey::raw(String::from("test_key2").into_bytes()); - let key3 = StateKey::raw(String::from("test_key3").into_bytes()); + let key1 = StateKey::raw(b"test_key1"); + let key2 = StateKey::raw(b"test_key2"); + let key3 = StateKey::raw(b"test_key3"); let value1 = StateValue::from(String::from("test_val1").into_bytes()); let value1_update = StateValue::from(String::from("test_val1_update").into_bytes()); @@ -193,13 +195,13 @@ fn test_get_values_by_key_prefix() { let store = &db.state_store; let address = AccountAddress::new([12u8; AccountAddress::LENGTH]); - let key1 = StateKey::access_path(AccessPath::new(address, b"state_key1".to_vec())); - let key2 = StateKey::access_path(AccessPath::new(address, b"state_key2".to_vec())); + let key1 = StateKey::resource_typed::(&address).unwrap(); + let key2 = StateKey::resource_typed::(&address).unwrap(); let value1_v0 = StateValue::from(String::from("value1_v0").into_bytes()); let value2_v0 = StateValue::from(String::from("value2_v0").into_bytes()); - let account_key_prefx = StateKeyPrefix::new(StateKeyTag::AccessPath, address.to_vec()); + let account_key_prefix = StateKeyPrefix::new(StateKeyTag::AccessPath, address.to_vec()); put_value_set( store, @@ -211,12 +213,12 @@ fn test_get_values_by_key_prefix() { None, ); - let key_value_map = traverse_values(store, &account_key_prefx, 0); + let key_value_map = traverse_values(store, &account_key_prefix, 0); assert_eq!(key_value_map.len(), 2); assert_eq!(*key_value_map.get(&key1).unwrap(), value1_v0); assert_eq!(*key_value_map.get(&key2).unwrap(), value2_v0); - let key4 = StateKey::access_path(AccessPath::new(address, b"state_key4".to_vec())); + let key4 = StateKey::resource_typed::(&address).unwrap(); let value2_v1 = StateValue::from(String::from("value2_v1").into_bytes()); let value4_v1 = StateValue::from(String::from("value4_v1").into_bytes()); @@ -232,13 +234,13 @@ fn test_get_values_by_key_prefix() { ); // Ensure that we still get only values for key1 and key2 for version 0 after the update - let key_value_map = traverse_values(store, &account_key_prefx, 0); + let key_value_map = traverse_values(store, &account_key_prefix, 0); assert_eq!(key_value_map.len(), 2); assert_eq!(*key_value_map.get(&key1).unwrap(), value1_v0); assert_eq!(*key_value_map.get(&key2).unwrap(), value2_v0); // Ensure that key value map for version 1 returns value for key1 at version 0. - let key_value_map = traverse_values(store, &account_key_prefx, 1); + let key_value_map = traverse_values(store, &account_key_prefix, 1); assert_eq!(key_value_map.len(), 3); assert_eq!(*key_value_map.get(&key1).unwrap(), value1_v0); assert_eq!(*key_value_map.get(&key2).unwrap(), value2_v1); @@ -246,21 +248,21 @@ fn test_get_values_by_key_prefix() { // Add values for one more account and verify the state let address1 = AccountAddress::new([22u8; AccountAddress::LENGTH]); - let key5 = StateKey::access_path(AccessPath::new(address1, b"state_key5".to_vec())); + let key5 = StateKey::resource_typed::(&address1).unwrap(); let value5_v2 = StateValue::from(String::from("value5_v2").into_bytes()); - let account1_key_prefx = StateKeyPrefix::new(StateKeyTag::AccessPath, address1.to_vec()); + let account1_key_prefix = StateKeyPrefix::new(StateKeyTag::AccessPath, address1.to_vec()); put_value_set(store, vec![(key5.clone(), value5_v2.clone())], 2, Some(1)); // address1 did not exist in version 0 and 1. - let key_value_map = traverse_values(store, &account1_key_prefx, 0); + let key_value_map = traverse_values(store, &account1_key_prefix, 0); assert_eq!(key_value_map.len(), 0); - let key_value_map = traverse_values(store, &account1_key_prefx, 1); + let key_value_map = traverse_values(store, &account1_key_prefix, 1); assert_eq!(key_value_map.len(), 0); - let key_value_map = traverse_values(store, &account1_key_prefx, 2); + let key_value_map = traverse_values(store, &account1_key_prefix, 2); assert_eq!(key_value_map.len(), 1); assert_eq!(*key_value_map.get(&key5).unwrap(), value5_v2); } @@ -275,10 +277,7 @@ pub fn test_get_state_snapshot_before() { assert_eq!(store.get_state_snapshot_before(0).unwrap(), None,); // put in genesis - let kv = vec![( - StateKey::raw(b"key".to_vec()), - StateValue::from(b"value".to_vec()), - )]; + let kv = vec![(StateKey::raw(b"key"), StateValue::from(b"value".to_vec()))]; let hash = put_value_set(store, kv.clone(), 0, None); assert_eq!(store.get_state_snapshot_before(0).unwrap(), None); assert_eq!(store.get_state_snapshot_before(1).unwrap(), Some((0, hash))); @@ -489,7 +488,7 @@ proptest! { let mut restore = StateSnapshotRestore::new(&store2.state_merkle_db, store2, version, expected_root_hash, true, /* async_commit */ StateSnapshotRestoreMode::Default).unwrap(); - let dummy_state_key = StateKey::raw(vec![]); + let dummy_state_key = StateKey::raw(&[]); let (top_levels_batch, sharded_batches, _) = store2.state_merkle_db.merklize_value_set(vec![(max_hash, Some(&(HashValue::random(), dummy_state_key)))], 0, None, None).unwrap(); store2.state_merkle_db.commit(version, top_levels_batch, sharded_batches).unwrap(); assert!(store2.state_merkle_db.get_rightmost_leaf(version).unwrap().is_none()); diff --git a/storage/aptosdb/src/utils/iterators.rs b/storage/aptosdb/src/utils/iterators.rs index 9e2b112106d52..f10fad9c1d3ab 100644 --- a/storage/aptosdb/src/utils/iterators.rs +++ b/storage/aptosdb/src/utils/iterators.rs @@ -15,7 +15,10 @@ use aptos_types::{ account_address::AccountAddress, contract_event::ContractEvent, ledger_info::LedgerInfoWithSignatures, - state_store::{state_key::StateKey, state_key_prefix::StateKeyPrefix, state_value::StateValue}, + state_store::{ + state_key::{prefix::StateKeyPrefix, StateKey}, + state_value::StateValue, + }, transaction::Version, }; use std::{iter::Peekable, marker::PhantomData}; diff --git a/storage/aptosdb/src/utils/truncation_helper.rs b/storage/aptosdb/src/utils/truncation_helper.rs index 57eaadcdd39ef..cacdd0ab4b07c 100644 --- a/storage/aptosdb/src/utils/truncation_helper.rs +++ b/storage/aptosdb/src/utils/truncation_helper.rs @@ -35,7 +35,7 @@ use aptos_schemadb::{ }; use aptos_storage_interface::Result; use aptos_types::{proof::position::Position, transaction::Version}; -use claims::{assert_ge, assert_lt}; +use claims::assert_ge; use rayon::prelude::*; use status_line::StatusLine; use std::{ @@ -82,12 +82,14 @@ pub(crate) fn truncate_state_kv_db( while current_version > target_version { let target_version_for_this_batch = std::cmp::max(current_version - batch_size as u64, target_version); + // By writing the progress first, we still maintain that it is less than or equal to the + // actual progress per shard, even if it dies in the middle of truncation. state_kv_db.write_progress(target_version_for_this_batch)?; - truncate_state_kv_db_shards( - state_kv_db, - target_version_for_this_batch, - Some(current_version), - )?; + // the first batch can actually delete more versions than the target batch size because + // we calculate the start version of this batch assuming the latest data is at + // `current_version`. Otherwise, we need to seek all shards to determine the + // actual latest version of data. + truncate_state_kv_db_shards(state_kv_db, target_version_for_this_batch)?; current_version = target_version_for_this_batch; status.set_current_version(current_version); } @@ -98,17 +100,11 @@ pub(crate) fn truncate_state_kv_db( pub(crate) fn truncate_state_kv_db_shards( state_kv_db: &StateKvDb, target_version: Version, - expected_current_version: Option, ) -> Result<()> { (0..NUM_STATE_SHARDS) .into_par_iter() .try_for_each(|shard_id| { - truncate_state_kv_db_single_shard( - state_kv_db, - shard_id as u8, - target_version, - expected_current_version, - ) + truncate_state_kv_db_single_shard(state_kv_db, shard_id as u8, target_version) }) } @@ -116,15 +112,9 @@ pub(crate) fn truncate_state_kv_db_single_shard( state_kv_db: &StateKvDb, shard_id: u8, target_version: Version, - expected_current_version: Option, ) -> Result<()> { let batch = SchemaBatch::new(); - delete_state_value_and_index( - state_kv_db.db_shard(shard_id), - target_version + 1, - expected_current_version, - &batch, - )?; + delete_state_value_and_index(state_kv_db.db_shard(shard_id), target_version + 1, &batch)?; state_kv_db.commit_single_shard(target_version, shard_id, batch) } @@ -413,7 +403,6 @@ fn delete_event_data( fn delete_state_value_and_index( state_kv_db_shard: &DB, start_version: Version, - expected_current_version: Option, batch: &SchemaBatch, ) -> Result<()> { let mut iter = state_kv_db_shard.iter::(ReadOptions::default())?; @@ -421,9 +410,6 @@ fn delete_state_value_and_index( for item in iter { let (index, _) = item?; - if let Some(expected_current_version) = expected_current_version { - assert_lt!(index.stale_since_version, expected_current_version); - } batch.delete::(&index)?; batch.delete::(&(index.state_key, index.stale_since_version))?; } diff --git a/storage/backup/backup-cli/src/backup_types/state_snapshot/restore.rs b/storage/backup/backup-cli/src/backup_types/state_snapshot/restore.rs index 6c5284d1c7cff..20516aa68b604 100644 --- a/storage/backup/backup-cli/src/backup_types/state_snapshot/restore.rs +++ b/storage/backup/backup-cli/src/backup_types/state_snapshot/restore.rs @@ -33,7 +33,7 @@ use aptos_types::{ on_chain_config::{Features, TimedFeatureOverride, TimedFeaturesBuilder}, proof::TransactionInfoWithProof, state_store::{ - state_key::{StateKey, StateKeyInner}, + state_key::{inner::StateKeyInner, StateKey}, state_value::StateValue, }, transaction::Version, diff --git a/storage/db-tool/src/tests.rs b/storage/db-tool/src/tests.rs index 6bb1a41d03d62..eb31df420ee0e 100644 --- a/storage/db-tool/src/tests.rs +++ b/storage/db-tool/src/tests.rs @@ -88,7 +88,7 @@ mod dbtool_tests { use aptos_storage_interface::DbReader; use aptos_temppath::TempPath; use aptos_types::{ - state_store::{state_key::StateKeyTag::AccessPath, state_key_prefix::StateKeyPrefix}, + state_store::state_key::{inner::StateKeyTag::AccessPath, prefix::StateKeyPrefix}, transaction::Version, }; use clap::Parser; diff --git a/storage/indexer/src/db_v2.rs b/storage/indexer/src/db_v2.rs index 53d9dfb83d3a0..fa2eb86411843 100644 --- a/storage/indexer/src/db_v2.rs +++ b/storage/indexer/src/db_v2.rs @@ -18,7 +18,7 @@ use aptos_types::{ access_path::Path, account_address::AccountAddress, state_store::{ - state_key::{StateKey, StateKeyInner}, + state_key::{inner::StateKeyInner, StateKey}, table::{TableHandle, TableInfo}, }, transaction::Version, diff --git a/storage/indexer/src/lib.rs b/storage/indexer/src/lib.rs index ffae7624d3186..4d90f4f24f973 100644 --- a/storage/indexer/src/lib.rs +++ b/storage/indexer/src/lib.rs @@ -27,7 +27,7 @@ use aptos_types::{ access_path::Path, account_address::AccountAddress, state_store::{ - state_key::{StateKey, StateKeyInner}, + state_key::{inner::StateKeyInner, StateKey}, table::{TableHandle, TableInfo}, }, transaction::{AtomicVersion, Version}, diff --git a/storage/storage-interface/src/async_proof_fetcher.rs b/storage/storage-interface/src/async_proof_fetcher.rs index a65c23c33b0aa..fbc344eb8f9f5 100644 --- a/storage/storage-interface/src/async_proof_fetcher.rs +++ b/storage/storage-interface/src/async_proof_fetcher.rs @@ -160,7 +160,7 @@ impl AsyncProofFetcher { mod tests { use super::*; use crate::mock::MockDbReaderWriter; - use aptos_types::state_store::state_key::StateKeyInner; + use aptos_types::state_store::state_key::inner::StateKeyInner; use assert_unordered::assert_eq_unordered; #[test] @@ -168,13 +168,13 @@ mod tests { let fetcher = AsyncProofFetcher::new(Arc::new(MockDbReaderWriter)); let mut expected_key_hashes = vec![]; for i in 0..10 { - let state_key: StateKey = StateKey::raw(format!("test_key_{}", i).into_bytes()); + let state_key: StateKey = StateKey::raw(format!("test_key_{}", i).as_bytes()); expected_key_hashes.push(state_key.hash()); let result = fetcher .fetch_state_value_with_version_and_schedule_proof_read(&state_key, 0, None) .expect("Should not fail."); - let expected_value = StateValue::from(match state_key.into_inner() { - StateKeyInner::Raw(key) => key, + let expected_value = StateValue::from(match state_key.inner() { + StateKeyInner::Raw(key) => key.to_owned(), _ => unreachable!(), }); assert_eq!(result, Some((0, expected_value))); diff --git a/storage/storage-interface/src/lib.rs b/storage/storage-interface/src/lib.rs index b604441bd5317..ae8e43256106d 100644 --- a/storage/storage-interface/src/lib.rs +++ b/storage/storage-interface/src/lib.rs @@ -19,7 +19,6 @@ use aptos_types::{ state_proof::StateProof, state_store::{ state_key::StateKey, - state_key_prefix::StateKeyPrefix, state_storage_usage::StateStorageUsage, state_value::{StateValue, StateValueChunkWithProof}, table::{TableHandle, TableInfo}, @@ -50,6 +49,7 @@ pub mod state_view; use crate::state_delta::StateDelta; use aptos_scratchpad::SparseMerkleTree; pub use aptos_types::block_info::BlockHeight; +use aptos_types::state_store::state_key::prefix::StateKeyPrefix; pub use errors::AptosDbError; pub use executed_trees::ExecutedTrees; diff --git a/storage/storage-interface/src/mock.rs b/storage/storage-interface/src/mock.rs index 814537a6a8969..664e589150100 100644 --- a/storage/storage-interface/src/mock.rs +++ b/storage/storage-interface/src/mock.rs @@ -8,7 +8,7 @@ use crate::{errors::AptosDbError, DbReader, DbWriter, Result}; use aptos_types::{ proof::SparseMerkleProofExt, state_store::{ - state_key::{StateKey, StateKeyInner}, + state_key::{inner::StateKeyInner, StateKey}, state_value::StateValue, }, transaction::Version, diff --git a/testsuite/forge/src/backend/k8s/helm-values/aptos-node-default-values.yaml b/testsuite/forge/src/backend/k8s/helm-values/aptos-node-default-values.yaml index e4c95b22fceea..2cebfd18189d3 100644 --- a/testsuite/forge/src/backend/k8s/helm-values/aptos-node-default-values.yaml +++ b/testsuite/forge/src/backend/k8s/helm-values/aptos-node-default-values.yaml @@ -2,7 +2,7 @@ validator: enableNetworkPolicy: false # Add debug here to enable debug logs # rust_log: debug,hyper=off - rust_log: hyper=off + rust_log: info,hyper=off # force enable the telemetry service to try to send telemetry force_enable_telemetry: true @@ -13,7 +13,7 @@ fullnode: replicas: 1 # Add debug herer to enable debug logs # rust_log: debug,hyper=off - rust_log: hyper=off + rust_log: info,hyper=off # force enable the telemetry service to try to send telemetry force_enable_telemetry: true diff --git a/testsuite/forge/src/interface/aptos.rs b/testsuite/forge/src/interface/aptos.rs index 26a37aec9c668..b31cbb2655449 100644 --- a/testsuite/forge/src/interface/aptos.rs +++ b/testsuite/forge/src/interface/aptos.rs @@ -3,6 +3,7 @@ use super::Test; use crate::{CoreContext, Result, TestReport}; +use anyhow::anyhow; use aptos_cached_packages::aptos_stdlib; use aptos_logger::info; use aptos_rest_client::{Client as RestClient, PendingTransaction, State, Transaction}; @@ -267,6 +268,27 @@ impl<'t> AptosPublicInfo<'t> { }) } + pub async fn account_exists(&self, address: AccountAddress) -> Result<()> { + self.rest_client + .get_account_resources(address) + .await + .is_ok() + .then_some(()) + .ok_or_else(|| anyhow!("Account does not exist")) + } + + pub async fn get_account_sequence_number(&mut self, address: AccountAddress) -> Result { + self.account_exists(address).await?; + + Ok(self + .client() + .get_account_bcs(address) + .await + .unwrap() + .into_inner() + .sequence_number()) + } + pub fn random_account(&mut self) -> LocalAccount { LocalAccount::generate(&mut self.rng) } diff --git a/testsuite/single_node_performance.py b/testsuite/single_node_performance.py index 933576b031e69..8854dc47dd6e9 100755 --- a/testsuite/single_node_performance.py +++ b/testsuite/single_node_performance.py @@ -96,12 +96,12 @@ class RunGroupConfig: RunGroupConfig(expected_tps=4170, key=RunGroupKey("modify-global-resource"), included_in=LAND_BLOCKING_AND_C | Flow.REPRESENTATIVE), RunGroupConfig(expected_tps=15400, key=RunGroupKey("modify-global-resource", module_working_set_size=10), included_in=Flow.CONTINUOUS), RunGroupConfig(expected_tps=155, key=RunGroupKey("publish-package"), included_in=LAND_BLOCKING_AND_C | Flow.REPRESENTATIVE), - RunGroupConfig(expected_tps=2450, key=RunGroupKey( + RunGroupConfig(expected_tps=1960, key=RunGroupKey( "mix_publish_transfer", transaction_type_override="publish-package coin-transfer", transaction_weights_override="1 500", ), included_in=LAND_BLOCKING_AND_C), - RunGroupConfig(expected_tps=353, key=RunGroupKey("batch100-transfer"), included_in=LAND_BLOCKING_AND_C), + RunGroupConfig(expected_tps=277, key=RunGroupKey("batch100-transfer"), included_in=LAND_BLOCKING_AND_C), RunGroupConfig(expected_tps=995, key=RunGroupKey("batch100-transfer", executor_type="native"), included_in=Flow.CONTINUOUS), RunGroupConfig(expected_tps=165, key=RunGroupKey("vector-picture40"), included_in=Flow(0), waived=True), @@ -138,7 +138,7 @@ class RunGroupConfig: RunGroupConfig(expected_tps=14500, key=RunGroupKey("coin-init-and-mint", module_working_set_size=1), included_in=LAND_BLOCKING_AND_C), RunGroupConfig(expected_tps=12000, key=RunGroupKey("coin-init-and-mint", module_working_set_size=20), included_in=Flow.CONTINUOUS), - RunGroupConfig(expected_tps=1590, key=RunGroupKey("fungible-asset-mint", module_working_set_size=1), included_in=LAND_BLOCKING_AND_C), + RunGroupConfig(expected_tps=1870, key=RunGroupKey("fungible-asset-mint", module_working_set_size=1), included_in=LAND_BLOCKING_AND_C), RunGroupConfig(expected_tps=7900, key=RunGroupKey("fungible-asset-mint", module_working_set_size=20), included_in=Flow.CONTINUOUS), # RunGroupConfig(expected_tps=1000, key=RunGroupKey("token-v1ft-mint-and-store"), included_in=Flow(0)), @@ -150,7 +150,7 @@ class RunGroupConfig: RunGroupConfig(expected_tps=7006, key=RunGroupKey("token-v2-ambassador-mint"), included_in=LAND_BLOCKING_AND_C | Flow.REPRESENTATIVE), RunGroupConfig(expected_tps=6946, key=RunGroupKey("token-v2-ambassador-mint", module_working_set_size=20), included_in=Flow.CONTINUOUS), - RunGroupConfig(expected_tps=1030, key=RunGroupKey("liquidity-pool-swap"), included_in=LAND_BLOCKING_AND_C | Flow.REPRESENTATIVE), + RunGroupConfig(expected_tps=1150, key=RunGroupKey("liquidity-pool-swap"), included_in=LAND_BLOCKING_AND_C | Flow.REPRESENTATIVE), RunGroupConfig(expected_tps=4520, key=RunGroupKey("liquidity-pool-swap", module_working_set_size=20), included_in=Flow.CONTINUOUS), RunGroupConfig(expected_tps=970, key=RunGroupKey("liquidity-pool-swap-stable"), included_in=Flow.CONTINUOUS), diff --git a/testsuite/smoke-test/src/keyless.rs b/testsuite/smoke-test/src/keyless.rs index 45d33efb57434..7034eef54e8e1 100644 --- a/testsuite/smoke-test/src/keyless.rs +++ b/testsuite/smoke-test/src/keyless.rs @@ -21,24 +21,26 @@ use aptos_types::{ keyless::{ get_public_inputs_hash, test_utils::{ - self, get_sample_esk, get_sample_groth16_sig_and_pk, - get_sample_groth16_sig_and_pk_no_extra_field, get_sample_iss, get_sample_jwk, - get_sample_openid_sig_and_pk, + self, get_groth16_sig_and_pk_for_upgraded_vk, get_sample_esk, + get_sample_groth16_sig_and_pk, get_sample_groth16_sig_and_pk_no_extra_field, + get_sample_iss, get_sample_jwk, get_sample_openid_sig_and_pk, get_upgraded_vk, }, Configuration, EphemeralCertificate, Groth16ProofAndStatement, Groth16VerificationKey, - KeylessPublicKey, KeylessSignature, TransactionAndProof, KEYLESS_ACCOUNT_MODULE_NAME, + KeylessPublicKey, KeylessSignature, TransactionAndProof, DEVNET_VERIFICATION_KEY, + KEYLESS_ACCOUNT_MODULE_NAME, }, transaction::{ authenticator::{ - AccountAuthenticator, AnyPublicKey, AnySignature, EphemeralSignature, - TransactionAuthenticator, + AccountAuthenticator, AnyPublicKey, AnySignature, AuthenticationKey, + EphemeralSignature, TransactionAuthenticator, }, SignedTransaction, }, }; use move_core_types::account_address::AccountAddress; use rand::thread_rng; -use std::time::Duration; +use serde::de::DeserializeOwned; +use std::{fmt::Debug, time::Duration}; // TODO(keyless): Test the override aud_val path #[tokio::test] @@ -57,6 +59,84 @@ async fn test_keyless_oidc_txn_verifies() { } } +#[tokio::test] +async fn test_keyless_rotate_vk() { + let (tw_sk, config, jwk, mut swarm, mut cli, root_idx) = setup_local_net().await; + let mut info = swarm.aptos_public_info(); + + let (old_sig, old_pk) = get_sample_groth16_sig_and_pk(); + let signed_txn = sign_transaction( + &mut info, + old_sig.clone(), + old_pk.clone(), + &jwk, + &config, + Some(&tw_sk), + 1, + ) + .await; + + info!("Submitting keyless Groth16 transaction w.r.t. to initial VK; should succeed"); + let result = info + .client() + .submit_without_serializing_response(&signed_txn) + .await; + + if let Err(e) = result { + panic!("Keyless Groth16 TXN with old proof for old VK should have succeeded verification: {:?}", e) + } + + let (new_sig, new_pk) = get_groth16_sig_and_pk_for_upgraded_vk(); + let signed_txn = sign_transaction( + &mut info, + new_sig.clone(), + new_pk.clone(), + &jwk, + &config, + Some(&tw_sk), + 2, + ) + .await; + info!("Submitting keyless Groth16 transaction w.r.t. to upgraded VK; should fail"); + let result = info + .client() + .submit_without_serializing_response(&signed_txn) + .await; + + if result.is_ok() { + panic!("Keyless Groth16 TXN with new proof for old VK should have failed verification") + } + + info!("Rotating VK"); + let vk = get_upgraded_vk().into(); + rotate_vk_by_governance(&mut cli, &mut info, &vk, root_idx).await; + + let signed_txn = + sign_transaction(&mut info, old_sig, old_pk, &jwk, &config, Some(&tw_sk), 2).await; + + info!("Submitting keyless Groth16 transaction w.r.t. to old VK; should fail"); + let result = info + .client() + .submit_without_serializing_response(&signed_txn) + .await; + + if result.is_ok() { + panic!("Keyless Groth16 TXN with old proof for old VK should have failed verification") + } + + let signed_txn = + sign_transaction(&mut info, new_sig, new_pk, &jwk, &config, Some(&tw_sk), 2).await; + info!("Submitting keyless Groth16 transaction w.r.t. to upgraded VK; should succeed"); + let result = info + .client() + .submit_without_serializing_response(&signed_txn) + .await; + + if let Err(e) = result { + panic!("Keyless Groth16 TXN with new proof for new VK should have succeeded verification: {:?}", e) + } +} + #[tokio::test] async fn test_keyless_secure_test_jwk_initialized_at_genesis() { let (swarm, _cli, _faucet) = SwarmBuilder::new_local(1) @@ -84,7 +164,7 @@ async fn test_keyless_secure_test_jwk_initialized_at_genesis() { #[tokio::test] async fn test_keyless_oidc_txn_with_bad_jwt_sig() { - let (tw_sk, config, jwk, mut swarm, _) = setup_local_net().await; + let (tw_sk, config, jwk, mut swarm, _, _) = setup_local_net().await; let (mut sig, pk) = get_sample_openid_sig_and_pk(); match &mut sig.cert { @@ -95,7 +175,7 @@ async fn test_keyless_oidc_txn_with_bad_jwt_sig() { } let mut info = swarm.aptos_public_info(); - let signed_txn = sign_transaction(&mut info, sig, pk, &jwk, &config, Some(&tw_sk)).await; + let signed_txn = sign_transaction(&mut info, sig, pk, &jwk, &config, Some(&tw_sk), 1).await; info!("Submit OpenID transaction with bad JWT signature"); let result = info @@ -110,13 +190,13 @@ async fn test_keyless_oidc_txn_with_bad_jwt_sig() { #[tokio::test] async fn test_keyless_oidc_txn_with_expired_epk() { - let (tw_sk, config, jwk, mut swarm, _) = setup_local_net().await; + let (tw_sk, config, jwk, mut swarm, _, _) = setup_local_net().await; let (mut sig, pk) = get_sample_openid_sig_and_pk(); sig.exp_date_secs = 1; // This should fail the verification since the expiration date is way in the past let mut info = swarm.aptos_public_info(); - let signed_txn = sign_transaction(&mut info, sig, pk, &jwk, &config, Some(&tw_sk)).await; + let signed_txn = sign_transaction(&mut info, sig, pk, &jwk, &config, Some(&tw_sk), 1).await; info!("Submit OpenID transaction with expired EPK"); let result = info @@ -146,7 +226,7 @@ async fn test_keyless_groth16_verifies() { } #[tokio::test] -async fn test_keyless_groth16_verifies_no_extra_field() { +async fn test_keyless_no_extra_field_groth16_verifies() { let (_, _, mut swarm, signed_txn) = get_transaction(get_sample_groth16_sig_and_pk_no_extra_field).await; @@ -163,19 +243,19 @@ async fn test_keyless_groth16_verifies_no_extra_field() { } #[tokio::test] -async fn test_keyless_groth16_verifies_no_training_wheels() { - let (_tw_sk, config, jwk, mut swarm, mut cli) = setup_local_net().await; +async fn test_keyless_no_training_wheels_groth16_verifies() { + let (_tw_sk, config, jwk, mut swarm, mut cli, root_idx) = setup_local_net().await; let (sig, pk) = get_sample_groth16_sig_and_pk(); let mut info = swarm.aptos_public_info(); - let signed_txn = - sign_transaction(&mut info, sig.clone(), pk.clone(), &jwk, &config, None).await; - remove_training_wheels(&mut swarm, &mut cli).await; + remove_training_wheels(&mut cli, &mut info, root_idx).await; + + let signed_txn = + sign_transaction(&mut info, sig.clone(), pk.clone(), &jwk, &config, None, 1).await; info!("Submit keyless Groth16 transaction"); - let result = swarm - .aptos_public_info() + let result = info .client() .submit_without_serializing_response(&signed_txn) .await; @@ -187,11 +267,11 @@ async fn test_keyless_groth16_verifies_no_training_wheels() { #[tokio::test] async fn test_keyless_groth16_with_mauled_proof() { - let (tw_sk, config, jwk, mut swarm, _) = setup_local_net().await; + let (tw_sk, config, jwk, mut swarm, _, _) = setup_local_net().await; let (sig, pk) = get_sample_groth16_sig_and_pk(); let mut info = swarm.aptos_public_info(); - let signed_txn = sign_transaction(&mut info, sig, pk, &jwk, &config, Some(&tw_sk)).await; + let signed_txn = sign_transaction(&mut info, sig, pk, &jwk, &config, Some(&tw_sk), 1).await; let signed_txn = maul_groth16_zkp_signature(signed_txn); info!("Submit keyless Groth16 transaction"); @@ -207,14 +287,22 @@ async fn test_keyless_groth16_with_mauled_proof() { #[tokio::test] async fn test_keyless_groth16_with_bad_tw_signature() { - let (_tw_sk, config, jwk, mut swarm, _cli) = setup_local_net().await; + let (_tw_sk, config, jwk, mut swarm, _, _) = setup_local_net().await; let (sig, pk) = get_sample_groth16_sig_and_pk(); let mut info = swarm.aptos_public_info(); // using the sample ESK rather than the TW SK to get a bad training wheels signature - let signed_txn = - sign_transaction(&mut info, sig, pk, &jwk, &config, Some(&get_sample_esk())).await; + let signed_txn = sign_transaction( + &mut info, + sig, + pk, + &jwk, + &config, + Some(&get_sample_esk()), + 1, + ) + .await; info!("Submit keyless Groth16 transaction"); let result = info @@ -236,12 +324,35 @@ async fn sign_transaction<'a>( jwk: &RSA_JWK, config: &Configuration, tw_sk: Option<&Ed25519PrivateKey>, + seqno: usize, ) -> SignedTransaction { - let addr = info - .create_user_account_with_any_key(&AnyPublicKey::keyless(pk.clone())) - .await - .unwrap(); - info.mint(addr, 10_000_000_000).await.unwrap(); + let any_pk = AnyPublicKey::keyless(pk.clone()); + let addr = AuthenticationKey::any_key(any_pk.clone()).account_address(); + + // If the account does not exist, create it. + if info.account_exists(addr).await.is_err() { + info!( + "{} account does not exist. Creating...", + addr.to_hex_literal() + ); + info.create_user_account_with_any_key(&any_pk) + .await + .unwrap(); + info.mint(addr, 10_000_000_000).await.unwrap(); + } + + // TODO: No idea why, but these calls do not actually reflect the updated balance after a successful TXN. + info!( + "{} balance before TXN: {}", + addr.to_hex_literal(), + info.get_balance(addr).await.unwrap() + ); + // TODO: No idea why, but these calls do not actually reflect the updated sequence number after a successful TXN. + info!( + "{} sequence number before TXN: {}", + addr.to_hex_literal(), + info.get_account_sequence_number(addr).await.unwrap() + ); let recipient = info .create_and_fund_user_account(20_000_000_000) @@ -250,9 +361,12 @@ async fn sign_transaction<'a>( let raw_txn = info .transaction_factory() - .payload(aptos_stdlib::aptos_coin_transfer(recipient.address(), 100)) + .payload(aptos_stdlib::aptos_coin_transfer( + recipient.address(), + 1_000_000, + )) .sender(addr) - .sequence_number(1) + .sequence_number(seqno as u64) .build(); let esk = get_sample_esk(); @@ -324,7 +438,7 @@ async fn get_transaction( LocalSwarm, SignedTransaction, ) { - let (tw_sk, config, jwk, mut swarm, _) = setup_local_net().await; + let (tw_sk, config, jwk, mut swarm, _, _) = setup_local_net().await; let (sig, pk) = get_pk_and_sig_func(); @@ -336,6 +450,7 @@ async fn get_transaction( &jwk, &config, Some(&tw_sk), + 1, ) .await; @@ -348,23 +463,24 @@ async fn setup_local_net() -> ( RSA_JWK, LocalSwarm, CliTestFramework, + usize, ) { let (mut swarm, mut cli, _faucet) = SwarmBuilder::new_local(1) .with_aptos() .build_with_cli(0) .await; - let (tw_sk, config, jwk) = spawn_network_and_execute_gov_proposals(&mut swarm, &mut cli).await; - (tw_sk, config, jwk, swarm, cli) + let (tw_sk, config, jwk, root_idx) = + spawn_network_and_execute_gov_proposals(&mut swarm, &mut cli).await; + (tw_sk, config, jwk, swarm, cli, root_idx) } -async fn remove_training_wheels(swarm: &mut LocalSwarm, cli: &mut CliTestFramework) { - let client = swarm.validators().next().unwrap().rest_client(); - let root_idx = cli.add_account_with_address_to_cli( - swarm.root_key(), - swarm.chain_info().root_account().address(), - ); - let jwk_patch_script = format!( +async fn remove_training_wheels<'a>( + cli: &mut CliTestFramework, + info: &mut AptosPublicInfo<'a>, + root_idx: usize, +) { + let script = format!( r#" script {{ use aptos_framework::{}; @@ -372,35 +488,33 @@ use aptos_framework::aptos_governance; use std::option; fun main(core_resources: &signer) {{ let framework_signer = aptos_governance::get_signer_testnet_only(core_resources, @0x1); - {}::update_training_wheels(&framework_signer, option::none()); + {}::update_training_wheels_for_next_epoch(&framework_signer, option::none()); + aptos_governance::force_end_epoch(&framework_signer); }} }} "#, KEYLESS_ACCOUNT_MODULE_NAME, KEYLESS_ACCOUNT_MODULE_NAME ); - let txn_summary = cli.run_script(root_idx, &jwk_patch_script).await.unwrap(); + let txn_summary = cli.run_script(root_idx, &script).await.unwrap(); debug!("txn_summary={:?}", txn_summary); - let mut info = swarm.aptos_public_info(); - // Increment sequence number as we ran a governance proposal info.root_account().increment_sequence_number(); - let configuration_type_tag = format!("0x1::{}::Configuration", KEYLESS_ACCOUNT_MODULE_NAME); - let maybe_response = client - .get_account_resource_bcs::( - AccountAddress::ONE, - configuration_type_tag.as_str(), - ) - .await; - let config = maybe_response.unwrap().into_inner(); - println!("Keyless configuration after: {:?}", config); + print_account_resource::( + info.client(), + AccountAddress::ONE, + KEYLESS_ACCOUNT_MODULE_NAME, + "Configuration", + "Keyless configuration after", + ) + .await; } async fn spawn_network_and_execute_gov_proposals( swarm: &mut LocalSwarm, cli: &mut CliTestFramework, -) -> (Ed25519PrivateKey, Configuration, RSA_JWK) { +) -> (Ed25519PrivateKey, Configuration, RSA_JWK, usize) { let client = swarm.validators().next().unwrap().rest_client(); let root_idx = cli.add_account_with_address_to_cli( swarm.root_key(), @@ -411,28 +525,28 @@ async fn spawn_network_and_execute_gov_proposals( .await .expect("Epoch 2 taking too long to come!"); - let vk_type_tag = format!( - "0x1::{}::Groth16VerificationKey", - KEYLESS_ACCOUNT_MODULE_NAME + let vk = print_account_resource::( + &client, + AccountAddress::ONE, + KEYLESS_ACCOUNT_MODULE_NAME, + "Groth16VerificationKey", + "Groth16 VK", + ) + .await; + + assert_eq!( + vk, + Groth16VerificationKey::from(DEVNET_VERIFICATION_KEY.clone()) ); - let maybe_response = client - .get_account_resource_bcs::( - AccountAddress::ONE, - vk_type_tag.as_str(), - ) - .await; - let vk = maybe_response.unwrap().into_inner(); - println!("Groth16 VK: {:?}", vk); - let configuration_type_tag = format!("0x1::{}::Configuration", KEYLESS_ACCOUNT_MODULE_NAME); - let maybe_response = client - .get_account_resource_bcs::( - AccountAddress::ONE, - configuration_type_tag.as_str(), - ) - .await; - let config = maybe_response.unwrap().into_inner(); - println!("Keyless configuration before: {:?}", config); + let old_config = print_account_resource::( + &client, + AccountAddress::ONE, + KEYLESS_ACCOUNT_MODULE_NAME, + "Configuration", + "Keyless configuration before", + ) + .await; let iss = get_sample_iss(); let jwk = get_sample_jwk(); @@ -440,8 +554,9 @@ async fn spawn_network_and_execute_gov_proposals( let training_wheels_sk = Ed25519PrivateKey::generate(&mut thread_rng()); let training_wheels_pk = Ed25519PublicKey::from(&training_wheels_sk); - info!("Insert a JWK."); - let jwk_patch_script = format!( + info!("Insert JWK and update keyless configuration."); + let max_exp_horizon_secs = Configuration::new_for_testing().max_exp_horizon_secs; + let script = format!( r#" script {{ use aptos_framework::jwks; @@ -463,8 +578,9 @@ fun main(core_resources: &signer) {{ ]; jwks::set_patches(&framework_signer, patches); - {}::update_max_exp_horizon(&framework_signer, {}); - {}::update_training_wheels(&framework_signer, option::some(x"{}")); + {}::update_max_exp_horizon_for_next_epoch(&framework_signer, {}); + {}::update_training_wheels_for_next_epoch(&framework_signer, option::some(x"{}")); + aptos_governance::force_end_epoch(&framework_signer); }} }} "#, @@ -475,12 +591,12 @@ fun main(core_resources: &signer) {{ jwk.n, iss, KEYLESS_ACCOUNT_MODULE_NAME, - Configuration::new_for_testing().max_exp_horizon_secs, + max_exp_horizon_secs, KEYLESS_ACCOUNT_MODULE_NAME, hex::encode(training_wheels_pk.to_bytes()) ); - let txn_summary = cli.run_script(root_idx, &jwk_patch_script).await.unwrap(); + let txn_summary = cli.run_script(root_idx, &script).await.unwrap(); debug!("txn_summary={:?}", txn_summary); info!("Use resource API to check the patch result."); @@ -496,21 +612,24 @@ fun main(core_resources: &signer) {{ }; assert_eq!(expected_providers_jwks, patched_jwks.jwks); - let maybe_response = client - .get_account_resource_bcs::( - AccountAddress::ONE, - configuration_type_tag.as_str(), - ) - .await; - let config = maybe_response.unwrap().into_inner(); - println!("Keyless configuration after: {:?}", config); + let new_config = print_account_resource::( + &client, + AccountAddress::ONE, + KEYLESS_ACCOUNT_MODULE_NAME, + "Configuration", + "Keyless configuration after", + ) + .await; + + assert_ne!(old_config, new_config); + assert_eq!(new_config.max_exp_horizon_secs, max_exp_horizon_secs); let mut info = swarm.aptos_public_info(); // Increment sequence number since we patched a JWK info.root_account().increment_sequence_number(); - (training_wheels_sk, config, jwk) + (training_wheels_sk, new_config, jwk, root_idx) } async fn get_latest_jwkset(rest_client: &Client) -> PatchedJWKs { @@ -520,3 +639,82 @@ async fn get_latest_jwkset(rest_client: &Client) -> PatchedJWKs { let response = maybe_response.unwrap(); response.into_inner() } + +async fn rotate_vk_by_governance<'a>( + cli: &mut CliTestFramework, + info: &mut AptosPublicInfo<'a>, + vk: &Groth16VerificationKey, + root_idx: usize, +) { + let script = format!( + r#" +script {{ + use aptos_framework::{}; + use aptos_framework::aptos_governance; + fun main(core_resources: &signer) {{ + let framework_signer = aptos_governance::get_signer_testnet_only(core_resources, @0x1); + let vk = {}::new_groth16_verification_key(x"{}", x"{}", x"{}", x"{}", vector[x"{}", x"{}"]); + {}::set_groth16_verification_key_for_next_epoch(&framework_signer, vk); + aptos_governance::force_end_epoch(&framework_signer); + }} +}} +"#, + KEYLESS_ACCOUNT_MODULE_NAME, + KEYLESS_ACCOUNT_MODULE_NAME, + hex::encode(&vk.alpha_g1), + hex::encode(&vk.beta_g2), + hex::encode(&vk.gamma_g2), + hex::encode(&vk.delta_g2), + hex::encode(&vk.gamma_abc_g1[0]), + hex::encode(&vk.gamma_abc_g1[1]), + KEYLESS_ACCOUNT_MODULE_NAME + ); + debug!("Move script for changing VK follows below:\n{:?}", script); + + print_account_resource::( + info.client(), + AccountAddress::ONE, + KEYLESS_ACCOUNT_MODULE_NAME, + "Groth16VerificationKey", + "Keyless Groth16 VK before", + ) + .await; + + let txn_summary = cli.run_script(root_idx, &script).await.unwrap(); + debug!("txn_summary={:?}", txn_summary); + + // Increment sequence number as we ran a governance proposal + info.root_account().increment_sequence_number(); + + print_account_resource::( + info.client(), + AccountAddress::ONE, + KEYLESS_ACCOUNT_MODULE_NAME, + "Groth16VerificationKey", + "Keyless Groth16 VK after", + ) + .await; +} + +async fn print_account_resource( + client: &Client, + address: AccountAddress, + module_name: &str, + resource_name: &str, + message: &str, +) -> T { + let type_tag = format!( + "{}::{}::{}", + address.to_hex_literal(), + module_name, + resource_name + ); + let maybe_response = client + .get_account_resource_bcs::(AccountAddress::ONE, type_tag.as_str()) + .await; + + let rsrc = maybe_response.unwrap().into_inner(); + println!("{}: {:?}", message, &rsrc); + + rsrc +} diff --git a/testsuite/smoke-test/src/randomness/e2e_basic_consumption.rs b/testsuite/smoke-test/src/randomness/e2e_basic_consumption.rs index 68e4038d41bdf..13221ec7582af 100644 --- a/testsuite/smoke-test/src/randomness/e2e_basic_consumption.rs +++ b/testsuite/smoke-test/src/randomness/e2e_basic_consumption.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::smoke_test_environment::SwarmBuilder; -use aptos::{move_tool::MemberId, test::CliTestFramework}; +use aptos::{common::types::GasOptions, move_tool::MemberId, test::CliTestFramework}; use aptos_forge::{NodeExt, Swarm, SwarmExt}; use aptos_logger::info; use aptos_types::on_chain_config::OnChainRandomnessConfig; @@ -48,8 +48,13 @@ async fn e2e_basic_consumption() { let account = cli.account_id(0).to_hex_literal(); let roll_func_id = MemberId::from_str(&format!("{}::dice::roll", account)).unwrap(); for _ in 0..10 { + let gas_options = GasOptions { + gas_unit_price: Some(100), + max_gas: Some(10_000), // should match the default required gas deposit. + expiration_secs: 60, + }; let txn_summary = cli - .run_function(0, None, roll_func_id.clone(), vec![], vec![]) + .run_function(0, Some(gas_options), roll_func_id.clone(), vec![], vec![]) .await .unwrap(); info!("Roll txn summary: {:?}", txn_summary); diff --git a/third_party/move/benchmarks/.gitignore b/third_party/move/benchmarks/.gitignore deleted file mode 100644 index 13a3d76264171..0000000000000 --- a/third_party/move/benchmarks/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Criterion puts its benchmark results under the target directory in here, not at the top (workspace) level. -/target/ diff --git a/third_party/move/benchmarks/Cargo.toml b/third_party/move/benchmarks/Cargo.toml deleted file mode 100644 index 58da47fb8df0b..0000000000000 --- a/third_party/move/benchmarks/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "language-benchmarks" -version = "0.1.0" -authors = ["Diem Association "] -description = "Move language benchmarks" -repository = "https://github.com/diem/diem" -homepage = "https://diem.com" -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -criterion = "0.3.4" -criterion-cpu-time = "0.1.0" -move-binary-format = { path = "../move-binary-format" } -once_cell = "1.7.2" - -move-compiler = { path = "../move-compiler" } -move-core-types = { path = "../move-core/types" } -move-stdlib = { path = "../move-stdlib" } -move-vm-runtime = { path = "../move-vm/runtime" } -move-vm-test-utils = { path = "../move-vm/test-utils" } -move-vm-types = { path = "../move-vm/types" } - -[[bench]] -name = "vm_benches" -harness = false diff --git a/third_party/move/benchmarks/README.md b/third_party/move/benchmarks/README.md deleted file mode 100644 index 271756946dba5..0000000000000 --- a/third_party/move/benchmarks/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Profiling MoveVM with Instrument -This doc is going to talk about how to run performance benchmarks on macOS. - -## Step 1: Get latest Xcode and open Instrument - -Instrument can be found in Xcode > Open Developer Tool > Instrument. -![](https://i.imgur.com/QCwJBim.png) - - - -## Step 2: Choose a benchmark suite. - -We currently have four local benchmark candidates: -- `executor_benchmark` in `diem/executor` -- `txn_bench` in `diem/language/benchmark` -- `Arith` and `call` benchmark in `diem/language/benchmark` - -The first item is a comprehensive benchmark of diem adapter, executor and storage that generates a block of p2p transactions and tries to execute and commit it to the DiemDB in local storage. The second item is a benchmark of Diem adapter only with a fake executor and an in-memory storage that executes randomly generated p2p transactions. The third item, although it’s still invoking Diem adapter, is mostly testing on the MoveVM’s ability of handling simple arithmetic operations and call stacks. - -## Step 3: Select the running process in Instrument. -Open instrument and create a time profiler project. - -![](https://i.imgur.com/dbLht9f.png) - -Launch the benchmark target in the terminal, and select it in Instrument. - -![](https://i.imgur.com/LU10tZC.jpg) - - -## Step 4: Get analysis! - -Here’s an example trace from running the benchmark - -![](https://i.imgur.com/BAoprNq.jpg) diff --git a/third_party/move/benchmarks/benches/vm_benches.rs b/third_party/move/benchmarks/benches/vm_benches.rs deleted file mode 100644 index 3482e15c0a3b8..0000000000000 --- a/third_party/move/benchmarks/benches/vm_benches.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use criterion::{criterion_group, criterion_main, measurement::Measurement, Criterion}; -use language_benchmarks::{measurement::cpu_time_measurement, move_vm::bench}; - -// -// MoveVM benchmarks -// - -fn arith(c: &mut Criterion) { - bench(c, "arith"); -} - -fn call(c: &mut Criterion) { - bench(c, "call"); -} - -fn natives(c: &mut Criterion) { - bench(c, "natives"); -} - -criterion_group!( - name = vm_benches; - config = cpu_time_measurement(); - targets = arith, - call, - natives -); - -criterion_main!(vm_benches); diff --git a/third_party/move/benchmarks/src/bench.move b/third_party/move/benchmarks/src/bench.move deleted file mode 100644 index fc9b4d205d460..0000000000000 --- a/third_party/move/benchmarks/src/bench.move +++ /dev/null @@ -1,112 +0,0 @@ -// `cargo bench` will call a public function in this module. -// The Module must be called `Bench` and the set of public functions are callable from the bench (Rust code). -// `benches/transaction.rs` contains the calling code. -// The idea is that you build your scenario with a public entry point and a bunch of private functions as needed. -module 0x1::Bench { - use std::vector; - - // - // Global helpers - // - fun check(check: bool, code: u64) { - if (check) () else abort code - } - - // - // `arith` benchmark - // - public fun arith() { - let i = 0; - // 10000 is the number of loops to make the benchmark run for a couple of minutes, which is an eternity. - // Adjust according to your needs, it's just a reference - while (i < 10000) { - 1; - 10 + 3; - 10; - 7 + 5; - let x = 1; - let y = x + 3; - check(x + y == 5, 10); - i = i + 1; - }; - } - - // - // `call` benchmark - // - public fun call() { - let i = 0; - // 3000 is the number of loops to make the benchmark run for a couple of minutes, which is an eternity. - // Adjust according to your needs, it's just a reference - while (i < 3000) { - let b = call_1(@0x0, 128); - call_2(b); - i = i + 1; - }; - } - - fun call_1(addr: address, val: u64): bool { - let b = call_1_1(&addr); - call_1_2(val, val); - b - } - - fun call_1_1(_addr: &address): bool { - true - } - - fun call_1_2(val1: u64, val2: u64): bool { - val1 == val2 - } - - fun call_2(b: bool) { - call_2_1(b); - check(call_2_2() == 400, 200); - } - - fun call_2_1(b: bool) { - check(b == b, 100) - } - - fun call_2_2(): u64 { - 100 + 300 - } - - // - // `natives` benchmark - // - fun test_vector_ops(x1: T, x2: T): (T, T) { - let v: vector = vector::empty(); - check(vector::length(&v) == 0, 100); - vector::push_back(&mut v, x1); - check(vector::length(&v) == 1, 101); - vector::push_back(&mut v, x2); - check(vector::length(&v) == 2, 102); - vector::swap(&mut v, 0, 1); - x1 = vector::pop_back(&mut v); - check(vector::length(&v) == 1, 103); - x2 = vector::pop_back(&mut v); - check(vector::length(&v) == 0, 104); - vector::destroy_empty(v); - (x1, x2) - } - - fun test_vector() { - test_vector_ops(1u8, 2u8); - test_vector_ops(1u64, 2u64); - test_vector_ops(1u128, 2u128); - test_vector_ops(true, false); - test_vector_ops
(@0x1, @0x2); - test_vector_ops>(vector::empty(), vector::empty()); - } - - public fun natives() { - let i = 0; - // 300 is the number of loops to make the benchmark run for a couple of minutes, which is an eternity. - // Adjust according to your needs, it's just a reference - while (i < 300) { - test_vector(); - i = i + 1; - } - } -} diff --git a/third_party/move/benchmarks/src/lib.rs b/third_party/move/benchmarks/src/lib.rs deleted file mode 100644 index 8f6293149ca01..0000000000000 --- a/third_party/move/benchmarks/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -#![forbid(unsafe_code)] - -pub mod measurement; -pub mod move_vm; diff --git a/third_party/move/benchmarks/src/measurement.rs b/third_party/move/benchmarks/src/measurement.rs deleted file mode 100644 index 83b10dda9418e..0000000000000 --- a/third_party/move/benchmarks/src/measurement.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use criterion::Criterion; -use criterion_cpu_time::PosixTime; - -pub fn cpu_time_measurement() -> Criterion { - Criterion::default().with_measurement(PosixTime::UserAndSystemTime) -} - -pub fn wall_time_measurement() -> Criterion { - Criterion::default() -} diff --git a/third_party/move/benchmarks/src/move_vm.rs b/third_party/move/benchmarks/src/move_vm.rs deleted file mode 100644 index b622fa6173260..0000000000000 --- a/third_party/move/benchmarks/src/move_vm.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use criterion::{measurement::Measurement, Criterion}; -use move_binary_format::CompiledModule; -use move_compiler::{compiled_unit::AnnotatedCompiledUnit, Compiler}; -use move_core_types::{ - account_address::AccountAddress, - identifier::{IdentStr, Identifier}, - language_storage::{ModuleId, CORE_CODE_ADDRESS}, -}; -use move_vm_runtime::move_vm::MoveVM; -use move_vm_test_utils::BlankStorage; -use move_vm_types::gas::UnmeteredGasMeter; -use once_cell::sync::Lazy; -use std::path::PathBuf; - -static MOVE_BENCH_SRC_PATH: Lazy = Lazy::new(|| { - vec![env!("CARGO_MANIFEST_DIR"), "src", "bench.move"] - .into_iter() - .collect() -}); - -/// Entry point for the bench, provide a function name to invoke in Module Bench in bench.move. -pub fn bench(c: &mut Criterion, fun: &str) { - let modules = compile_modules(); - let move_vm = MoveVM::new(move_stdlib::natives::all_natives( - AccountAddress::from_hex_literal("0x1").unwrap(), - move_stdlib::natives::GasParameters::zeros(), - )) - .unwrap(); - execute(c, &move_vm, modules, fun); -} - -// Compile `bench.move` and its dependencies -fn compile_modules() -> Vec { - let mut src_files = move_stdlib::move_stdlib_files(); - src_files.push(MOVE_BENCH_SRC_PATH.to_str().unwrap().to_owned()); - let (_files, compiled_units) = Compiler::from_files( - src_files, - vec![], - Flags::empty().set_skip_attribute_checks(false), - move_stdlib::move_stdlib_named_addresses(), - ) - .build_and_report() - .expect("Error compiling..."); - compiled_units - .into_iter() - .map(|unit| match unit { - AnnotatedCompiledUnit::Module(annot_unit) => annot_unit.named_module.module, - AnnotatedCompiledUnit::Script(_) => { - panic!("Expected a module but received a script") - }, - }) - .collect() -} - -// execute a given function in the Bench module -fn execute( - c: &mut Criterion, - move_vm: &MoveVM, - modules: Vec, - fun: &str, -) { - // establish running context - let storage = BlankStorage::new(); - let sender = CORE_CODE_ADDRESS; - let mut session = move_vm.new_session(&storage); - - // TODO: we may want to use a real gas meter to make benchmarks more realistic. - - for module in modules { - let mut mod_blob = vec![]; - module - .serialize(&mut mod_blob) - .expect("Module serialization error"); - session - .publish_module(mod_blob, sender, &mut UnmeteredGasMeter) - .expect("Module must load"); - } - - // module and function to call - let module_id = ModuleId::new(sender, Identifier::new("Bench").unwrap()); - let fun_name = IdentStr::new(fun).unwrap_or_else(|_| panic!("Invalid identifier name {}", fun)); - - // benchmark - c.bench_function(fun, |b| { - b.iter(|| { - session - .execute_function_bypass_visibility( - &module_id, - fun_name, - vec![], - Vec::>::new(), - &mut UnmeteredGasMeter, - ) - .unwrap_or_else(|err| { - panic!( - "{:?}::{} failed with {:?}", - &module_id, - fun, - err.into_vm_status() - ) - }) - }) - }); -} diff --git a/third_party/move/evm/exec-utils/Cargo.toml b/third_party/move/evm/exec-utils/Cargo.toml index d5786f5d5bda8..80736821c5912 100644 --- a/third_party/move/evm/exec-utils/Cargo.toml +++ b/third_party/move/evm/exec-utils/Cargo.toml @@ -8,14 +8,14 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.52" -evm = { version = "0.33.1", features = [ "tracing"] } -evm-runtime = { version = "0.33.0", features = [ "tracing"] } -hex = "0.4.3" -primitive-types = "0.10.1" +anyhow = { workspace = true } +evm = { workspace = true } +evm-runtime = { workspace = true } +hex = { workspace = true } +primitive-types = { workspace = true } # external dependencies -sha3 = "0.9.1" -tempfile = "3.2.0" +sha3 = { workspace = true } +tempfile = { workspace = true } # move dependencies move-command-line-common = { path = "../../move-command-line-common" } diff --git a/third_party/move/evm/extract-ethereum-abi/Cargo.toml b/third_party/move/evm/extract-ethereum-abi/Cargo.toml index bb960f5afa7af..6085e057f710b 100644 --- a/third_party/move/evm/extract-ethereum-abi/Cargo.toml +++ b/third_party/move/evm/extract-ethereum-abi/Cargo.toml @@ -12,8 +12,8 @@ license = "Apache-2.0" move-to-yul = { path = "../move-to-yul" } # external dependencies -anyhow = "1.0.38" -atty = "0.2.14" -clap = { version = "4.3.9", features = ["derive", "env"] } -codespan-reporting = "0.11.1" -serde_json = "1.0.64" +anyhow = { workspace = true } +atty = { workspace = true } +clap = { workspace = true } +codespan-reporting = { workspace = true } +serde_json = { workspace = true } diff --git a/third_party/move/evm/move-ethereum-abi/Cargo.toml b/third_party/move/evm/move-ethereum-abi/Cargo.toml index 0697d243cfd67..bbdf049cc13f9 100644 --- a/third_party/move/evm/move-ethereum-abi/Cargo.toml +++ b/third_party/move/evm/move-ethereum-abi/Cargo.toml @@ -9,9 +9,9 @@ license = "Apache-2.0" [dependencies] # external dependencies -ethabi = "17.0.0" -serde = { version = "1.0.124", features = ["derive"] } -serde_json = "1.0.64" +ethabi = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } [lib] doctest = false diff --git a/third_party/move/evm/move-to-yul/Cargo.toml b/third_party/move/evm/move-to-yul/Cargo.toml index da388dffeb7b6..b979d3af1ff3d 100644 --- a/third_party/move/evm/move-to-yul/Cargo.toml +++ b/third_party/move/evm/move-to-yul/Cargo.toml @@ -17,30 +17,29 @@ move-model = { path = "../../move-model" } move-stackless-bytecode = { path = "../../move-model/bytecode" } # external dependencies -anyhow = "1.0.38" -atty = "0.2.14" -clap = { version = "4.3.9", features = ["derive", "env"] } -codespan = "0.11.1" -codespan-reporting = "0.11.1" -ethnum = "1.0.4" -evm = "0.33.1" -itertools = "0.10.0" -maplit = "1.0.2" -once_cell = "1.7.2" -primitive-types = "0.10.1" -regex = "1.4.3" -serde_json = "1.0.64" -sha3 = "0.9.1" +anyhow = { workspace = true } +atty = { workspace = true } +clap = { workspace = true } +codespan = { workspace = true } +codespan-reporting = { workspace = true } +ethnum = { workspace = true } +evm = { workspace = true } +itertools = { workspace = true } +maplit = { workspace = true } +once_cell = { workspace = true } +primitive-types = { workspace = true } +regex = { workspace = true } +serde_json = { workspace = true } +sha3 = { workspace = true } [dev-dependencies] -datatest-stable = "0.1.1" -evm = "0.33.1" +datatest-stable = { workspace = true } +evm = { workspace = true } evm-exec-utils = { path = "../exec-utils" } move-prover-test-utils = { path = "../../move-prover/test-utils" } move-stdlib = { path = "../../move-stdlib" } -primitive-types = "0.10.1" -tempfile = "3.2.0" -walkdir = "2.3.1" +tempfile = { workspace = true } +walkdir = { workspace = true } [lib] doctest = false diff --git a/third_party/move/extensions/async/move-async-vm/Cargo.toml b/third_party/move/extensions/async/move-async-vm/Cargo.toml index 25d400792c9d6..e26411780b9f4 100644 --- a/third_party/move/extensions/async/move-async-vm/Cargo.toml +++ b/third_party/move/extensions/async/move-async-vm/Cargo.toml @@ -9,10 +9,10 @@ edition = "2021" publish = false [dependencies] -anyhow = "1.0.52" -better_any = "0.1.1" -bytes = "1.4.0" -itertools = "0.10.0" +anyhow = { workspace = true } +better_any = { workspace = true } +bytes = { workspace = true } +itertools = { workspace = true } move-binary-format = { path = "../../../move-binary-format" } move-command-line-common = { path = "../../../move-command-line-common" } move-compiler = { path = "../../../move-compiler" } @@ -20,11 +20,11 @@ move-core-types = { path = "../../../move-core/types" } move-vm-runtime = { path = "../../../move-vm/runtime", features = ["debugging"] } move-vm-test-utils = { path = "../../../move-vm/test-utils" } move-vm-types = { path = "../../../move-vm/types" } -sha3 = "0.9.1" -smallvec = "1.6.1" +sha3 = { workspace = true } +smallvec = { workspace = true } [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-prover-test-utils = { path = "../../../move-prover/test-utils" } move-stdlib = { path = "../../../move-stdlib", features = ["testing"] } diff --git a/third_party/move/extensions/async/move-async-vm/src/async_vm.rs b/third_party/move/extensions/async/move-async-vm/src/async_vm.rs index cfebc3fbbaa54..57a87509c91c7 100644 --- a/third_party/move/extensions/async/move-async-vm/src/async_vm.rs +++ b/third_party/move/extensions/async/move-async-vm/src/async_vm.rs @@ -18,6 +18,7 @@ use move_core_types::{ vm_status::StatusCode, }; use move_vm_runtime::{ + module_traversal::*, move_vm::MoveVM, native_extensions::NativeContextExtensions, native_functions::NativeFunction, @@ -198,6 +199,7 @@ impl<'r, 'l> AsyncSession<'r, 'l> { // Execute the initializer. let gas_before = gas_status.remaining_gas(); + let traversal_storage = TraversalStorage::new(); let result = self .vm_session .execute_function_bypass_visibility( @@ -206,6 +208,7 @@ impl<'r, 'l> AsyncSession<'r, 'l> { vec![], Vec::>::new(), gas_status, + &mut TraversalContext::new(&traversal_storage), ) .and_then(|ret| Ok((ret, self.vm_session.finish_with_extensions()?))); let gas_used = gas_before.checked_sub(gas_status.remaining_gas()).unwrap(); @@ -294,9 +297,17 @@ impl<'r, 'l> AsyncSession<'r, 'l> { // Execute the handler. let gas_before = gas_status.remaining_gas(); + let traversal_storage = TraversalStorage::new(); let result = self .vm_session - .execute_function_bypass_visibility(module_id, handler_id, vec![], args, gas_status) + .execute_function_bypass_visibility( + module_id, + handler_id, + vec![], + args, + gas_status, + &mut TraversalContext::new(&traversal_storage), + ) .and_then(|ret| Ok((ret, self.vm_session.finish_with_extensions()?))); let gas_used = gas_before.checked_sub(gas_status.remaining_gas()).unwrap(); diff --git a/third_party/move/extensions/move-table-extension/Cargo.toml b/third_party/move/extensions/move-table-extension/Cargo.toml index 3747c8286de08..1dee926a611e0 100644 --- a/third_party/move/extensions/move-table-extension/Cargo.toml +++ b/third_party/move/extensions/move-table-extension/Cargo.toml @@ -9,20 +9,18 @@ edition = "2021" publish = false [dependencies] -better_any = "0.1.1" -bytes = "1.4.0" +better_any = { workspace = true } +bytes = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-core-types = { path = "../../move-core/types" } move-vm-runtime = { path = "../../move-vm/runtime" } move-vm-types = { path = "../../move-vm/types" } -sha3 = "0.9.1" -smallvec = "1.6.1" +sha3 = { workspace = true } +smallvec = { workspace = true } [dev-dependencies] -#dir-diff = "0.3.2" -#file_diff = "1.0.0" move-cli = { path = "../../tools/move-cli" } move-package = { path = "../../tools/move-package" } move-stdlib = { path = "../../move-stdlib", features = ["testing"] } move-unit-test = { path = "../../tools/move-unit-test", features = ["table-extension"] } -tempfile = "3.2.0" +tempfile = { workspace = true } diff --git a/third_party/move/move-analyzer/Cargo.toml b/third_party/move/move-analyzer/Cargo.toml deleted file mode 100644 index 89040471bdde6..0000000000000 --- a/third_party/move/move-analyzer/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "move-analyzer" -version = "1.0.0" -authors = ["Diem Association "] -description = "A language server for Move" -repository = "https://github.com/move-language/move" -license = "Apache-2.0" -publish = false -edition = "2021" - -[dependencies] -anyhow = "1.0.52" -clap = { version = "4.3.9", features = ["derive"] } -codespan-reporting = "0.11.1" -crossbeam = "0.8" -derivative = "2.2.0" -dunce = "1.0.4" -im = "15.1.0" -lsp-server = "0.5.1" -lsp-types = "0.90.1" -move-command-line-common = { path = "../move-command-line-common" } -move-compiler = { path = "../move-compiler" } -move-ir-types = { path = "../move-ir/types" } -move-package = { path = "../tools/move-package" } -move-symbol-pool = { path = "../move-symbol-pool" } -serde_json = "1.0.64" -tempfile = "3.2.0" -url = "2.2.2" diff --git a/third_party/move/move-analyzer/editors/code/.eslintignore b/third_party/move/move-analyzer/editors/code/.eslintignore deleted file mode 100644 index e27093b7b85da..0000000000000 --- a/third_party/move/move-analyzer/editors/code/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -# There's no need for eslint to lint external module dependencies. -node_modules -# eslint lints our pre-compiled source files; it does not need to lint -# build output. -out -# Do not lint TypeScript type declarations. -*.d.ts diff --git a/third_party/move/move-analyzer/editors/code/.eslintrc.json b/third_party/move/move-analyzer/editors/code/.eslintrc.json deleted file mode 100644 index a6a2d7351c836..0000000000000 --- a/third_party/move/move-analyzer/editors/code/.eslintrc.json +++ /dev/null @@ -1,220 +0,0 @@ -{ - // Don't bother looking for eslint configuration files in parent - // directories; this is the root configuration. - "root": true, - - // Instruct eslint to use a parser that can parse TypeScript. - "parser": "@typescript-eslint/parser", - "parserOptions": { - // Match the ECMAScript standard specified in our TypeScript config. - "ecmaVersion": "2020", - // Use ECMAScript modules. - "sourceType": "module", - // To type-check while linting, specify the TypeScript compiler be - // invoked from the same directory as this lint configuration file, - // using the TypeScript configuration file at the "project" path. - "tsconfigRootDir": ".", - "project": [ - "./tsconfig.json" - ] - }, - - // Specify the environment in which our JavaScript will run. - "env": { - // The Node.js runtime environment provides globals such as `__dirname`. - "node": true - }, - - // Plug-in eslint rules from @typescript-eslint. - "plugins": [ - "@typescript-eslint", - "eslint-plugin-tsdoc" - ], - // Use the core rules that eslint and @typescript-eslint recommend. - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking" - ], - // Enable some additional rules beyond the recommended ones. - // For more information, see: https://eslint.org/docs/rules/ - "rules": { - // The following are in the "possible errors" category of eslint rules. - "no-promise-executor-return": "warn", - "no-template-curly-in-string": "warn", - "no-unreachable-loop": "warn", - "no-unsafe-optional-chaining": "warn", - "no-useless-backreference": "warn", - "require-atomic-updates": "warn", - - // The following are in the "best practices" category of eslint rules. - "array-callback-return": "warn", - "block-scoped-var": "warn", - "class-methods-use-this": "warn", - "consistent-return": "warn", - "curly": "warn", - "default-case": "warn", - "default-case-last": "warn", - "dot-location": "warn", - "eqeqeq": "warn", - "guard-for-in": "warn", - "no-constructor-return": "warn", - "no-else-return": "warn", - "no-eq-null": "warn", - "no-eval": "warn", - "no-extend-native": "warn", - "no-extra-bind": "warn", - "no-extra-label": "warn", - "no-floating-decimal": "warn", - "no-implicit-coercion": "warn", - "no-implicit-globals": "warn", - "no-labels": "warn", - "no-lone-blocks": "warn", - "no-multi-spaces": "warn", - "no-nonoctal-decimal-escape": "warn", - "no-octal-escape": "warn", - "no-param-reassign": "warn", - "no-return-assign": "warn", - "no-script-url": "warn", - "no-self-compare": "warn", - "no-sequences": "warn", - "no-throw-literal": "warn", - "no-unmodified-loop-condition": "warn", - "no-useless-call": "warn", - "no-useless-concat": "warn", - "no-useless-return": "warn", - "prefer-promise-reject-errors": "warn", - "radix": "warn", - - // The following are in the "stylistic issues" category of eslint rules. - "array-bracket-spacing": "warn", - "array-element-newline": [ - "warn", - "consistent" - ], - "block-spacing": "warn", - "capitalized-comments": [ - "warn", - "always", - { - "ignoreConsecutiveComments": true - } - ], - "comma-style": "warn", - "computed-property-spacing": "warn", - "eol-last": "warn", - "function-call-argument-newline": ["warn", "consistent"], - "function-paren-newline": ["warn", "consistent"], - "key-spacing": "warn", - "linebreak-style": "off", // We use different linebreak styles. ref https://eslint.org/docs/latest/rules/linebreak-style - "max-len": [ - "warn", - { - "code": 120, - "ignoreUrls": true - } - ], - "new-cap": "warn", - "new-parens": "warn", - "no-lonely-if": "warn", - "no-mixed-operators": "warn", - "no-multi-assign": "warn", - "no-multiple-empty-lines": "warn", - "no-negated-condition": "warn", - "no-new-object": "warn", - "no-tabs": "warn", - "no-trailing-spaces": "warn", - "no-unneeded-ternary": "warn", - "no-whitespace-before-property": "warn", - "prefer-exponentiation-operator": "warn", - "prefer-object-spread": "warn", - "semi-spacing": "warn", - "semi-style": "warn", - "space-in-parens": "warn", - "spaced-comment": "warn", - "switch-colon-spacing": "warn", - "unicode-bom": "warn", - - // The following are @typescript-eslint rules. For more information, see: - // * All @typescript-eslint rules: https://github.com/typescript-eslint/typescript-eslint/tree/v4.31.1/packages/eslint-plugin/docs/rules - // * The rules included in @typescript-eslint/recommended: https://github.com/typescript-eslint/typescript-eslint/blob/v4.31.1/packages/eslint-plugin/src/configs/recommended.ts - // * The rules included in @typescript-eslint/recommended-requiring-type-checking: https://github.com/typescript-eslint/typescript-eslint/blob/v4.31.1/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts - "@typescript-eslint/ban-tslint-comment": "warn", - "@typescript-eslint/brace-style": "warn", - "@typescript-eslint/comma-dangle": [ - "warn", - "always-multiline" - ], - "@typescript-eslint/comma-spacing": "warn", - "@typescript-eslint/consistent-indexed-object-style": "warn", - "@typescript-eslint/consistent-type-assertions": "warn", - "@typescript-eslint/consistent-type-definitions": "warn", - "@typescript-eslint/consistent-type-imports": "warn", - "@typescript-eslint/default-param-last": "warn", - "@typescript-eslint/dot-notation": "warn", - "@typescript-eslint/explicit-function-return-type": "warn", - "@typescript-eslint/func-call-spacing": "warn", - "@typescript-eslint/keyword-spacing": "warn", - "@typescript-eslint/lines-between-class-members": "warn", - "@typescript-eslint/member-delimiter-style": "warn", - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/no-base-to-string": "warn", - "@typescript-eslint/no-confusing-non-null-assertion": "warn", - "@typescript-eslint/no-duplicate-imports": "warn", - "@typescript-eslint/no-dynamic-delete": "warn", - "@typescript-eslint/no-extra-parens": "warn", - "@typescript-eslint/no-extraneous-class": "warn", - "@typescript-eslint/no-implicit-any-catch": "warn", - "@typescript-eslint/no-invalid-this": "warn", - "@typescript-eslint/no-invalid-void-type": "warn", - "@typescript-eslint/no-loop-func": "warn", - "@typescript-eslint/no-loss-of-precision": "warn", - "@typescript-eslint/no-meaningless-void-operator": "warn", - "@typescript-eslint/no-redeclare": "warn", - "@typescript-eslint/no-require-imports": "warn", - "@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn", - "@typescript-eslint/no-unnecessary-condition": "warn", - "@typescript-eslint/no-unnecessary-qualifier": "warn", - "@typescript-eslint/no-unnecessary-type-arguments": "warn", - "@typescript-eslint/no-unnecessary-type-constraint": "warn", - "@typescript-eslint/no-unused-expressions": "warn", - "@typescript-eslint/no-use-before-define": "warn", - "@typescript-eslint/non-nullable-type-assertion-style": "warn", - "@typescript-eslint/object-curly-spacing": ["warn", "always"], - "@typescript-eslint/prefer-for-of": "warn", - "@typescript-eslint/prefer-function-type": "warn", - "@typescript-eslint/prefer-includes": "warn", - "@typescript-eslint/prefer-literal-enum-member": "warn", - "@typescript-eslint/prefer-nullish-coalescing": "warn", - "@typescript-eslint/prefer-optional-chain": "warn", - "@typescript-eslint/prefer-readonly": "warn", - "@typescript-eslint/prefer-reduce-type-parameter": "warn", - "@typescript-eslint/prefer-string-starts-ends-with": "warn", - "@typescript-eslint/promise-function-async": "warn", - "@typescript-eslint/quotes": ["warn", "single"], - "@typescript-eslint/require-array-sort-compare": "warn", - "@typescript-eslint/return-await": "warn", - "@typescript-eslint/semi": "warn", - "@typescript-eslint/space-before-function-paren": [ - "warn", - { - "anonymous": "never", - "named": "never", - "asyncArrow": "always" - } - ], - "@typescript-eslint/strict-boolean-expressions": "warn", - "@typescript-eslint/switch-exhaustiveness-check": "warn", - "@typescript-eslint/unified-signatures": "warn", - - // The following are eslint-plugin-tsdoc rules: - "tsdoc/syntax": "warn", - - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/type-annotation-spacing": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/array-type": "off" - } -} diff --git a/third_party/move/move-analyzer/editors/code/.gitignore b/third_party/move/move-analyzer/editors/code/.gitignore deleted file mode 100644 index 8174e373d76bb..0000000000000 --- a/third_party/move/move-analyzer/editors/code/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# NPM dependencies -node_modules -# TypeScript build output directory -out -# Tests are run within a VS Code application that is downloaded -# into this directory -.vscode-test -# VS Code extension package (VSIX) archive -*.vsix -# Yarn cache directory -yarn.lock diff --git a/third_party/move/move-analyzer/editors/code/.vscodeignore b/third_party/move/move-analyzer/editors/code/.vscodeignore deleted file mode 100644 index ddd5d59296bb6..0000000000000 --- a/third_party/move/move-analyzer/editors/code/.vscodeignore +++ /dev/null @@ -1,14 +0,0 @@ -# Rather than listing out what files are *not* included in the extension, -# list out the small subset of files that *are* included. -# For more information on `.vscodeignore` files, see: -# https://code.visualstudio.com/api/working-with-extensions/publishing-extension#.vscodeignore - -**/* -!images/move.png -!out/src/**/* -!node_modules/**/* -!language-configuration.json -!move.tmLanguage.json -!package-lock.json -!package.json -!README.md diff --git a/third_party/move/move-analyzer/editors/code/CONTRIBUTING.md b/third_party/move/move-analyzer/editors/code/CONTRIBUTING.md deleted file mode 100644 index d65449b1c9a40..0000000000000 --- a/third_party/move/move-analyzer/editors/code/CONTRIBUTING.md +++ /dev/null @@ -1,95 +0,0 @@ -# How to contribute to the move-analyzer Visual Studio Code extension - -## Installing dependencies - -To begin contributing to the VS Code extension for Move, you'll need to have some prerequisite technologies installed: - -1. Visual Studio Code itself. To install, follow the directions on [the VS Code website](https://code.visualstudio.com). -2. Node.js and its package manager, NPM. To install, follow the directions on [the Node.js website](https://nodejs.org/en/). -3. The Node module dependencies this extension relies upon. To install, make sure you have Node.js and NPM installed, then open your favorite terminal app. Navigate to the extension's directory and install its dependencies using `npm install`. In short: `cd language/move-analyzer/editors/code && npm install`. - -> If you'll be using [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview) to connect to a computer over SSH, install Node.js on the computer you'll be connecting to. - -## Running tests on the command line using `package.json` scripts - -The best way to confirm that your dependency installation succeeded is by running the tests: - -```sh -npm run pretest -npm run test -``` - -This executes the `"pretest"` and `"test"` "scripts" from thr `package.json` in the extension's directory. This `package.json` file defines not only information about the extension, such as its name and a description, but also "scripts": aliases for commands that can be run with `npm run`. - -Currently, the scripts focus on compiling the project's [TypeScript](https://www.typescriptlang.org) into JavaScript (VS Code extensions run in a JavaScript environment). - -## Launching VS Code with the extension installed from source - -Running the extension's tests from the command-line is cumbersome because the test environment insists no other instance of VS Code is running while the tests run. Instead, to launch VS Code with the extension installed from source: - -1. Open this repository in VS Code. -2. Open the "Run and Debug" view: open the command palette (keyboard shortcut `⇧⌘P` on macOS) and type in "View: Show Run and Debug". -3. From the pull-down menu in the Run and Debug view, select "Launch with Extension" and click the green arrow button. This will launch a new VS Code window that has the `move-analyzer` extension installed. If you open a `.move` file, it will be highlighted according to the any changes you've made in your local checkout of this repository. -4. Once you've launched the extension, in the original VS Code window you'll see a small box with pause, refresh, and stop buttons. Clicking these allows you to quickly refresh the extension window with your latest changes, or quit the window. - -To test the Move TextMate grammar, open a file with a `.move` file extension and use the command palette to run the "Developer: Inspect Editor Tokens and Scopes" command. This displays a large window that shows what token is detected below the typing cursor in the VS Code window. - -## Running the tests from within VS Code - -You can run the extensions tests from within the "Run and Debug" view: - -1. Open this repository in VS Code. -2. Open the "Run and Debug" view: open the command palette (keyboard shortcut `⇧⌘P` on macOS) and type in "View: Show Run and Debug". -3. Toward the bottom of the Run and Debug view, you should see an option to enable breakpoints on "Uncaught Exceptions." Clicking the check-box to enable breakpoints will make test failures easier to debug. -4. From the pull-down menu in the Run and Debug view, select "VS Code Tokenizer Tests" and click the green arrow button to run the tests. Should they fail, you will see a stack trace. - -## Releasing new versions of the extension - -To add new versions of the move-analyzer Visual Studio Code extension, you will need to: - -1. Request to be added to the `move` publisher team. -2. Package and upload a new extension version. - -### 1: Become a member of the `move` publisher team - -As [Visual Studio Code's documentation](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) explains, the Visual Studio Marketplace uses [Azure DevOps](https://azure.microsoft.com/services/devops/) to authenticate users who are allowed to manage extensions. To register with Azure DevOps, you need a Microsoft account. - -> **NOTE:** If you work for a company that uses Microsoft Outlook to serve your corporate email, then you already have a Microsoft account associated with that email address. - -To be added to the group of maintainers allowed to release new versions of the move-analyzer Visual Studio Code extension: - -1. Open https://marketplace.visualstudio.com/vscode in your browser and click on "Sign in" on the upper-right of the page. -2. Sign in with your Microsoft account's email address. If using a corporate email address, you'll go through an authentication flow specific to your organization (two-factor authentication, for example). -3. Once you've signed in, contact someone who is already in the existing group of maintainers, and ask them to [please add you to this list of members](https://marketplace.visualstudio.com/manage/publishers/move). If you do not know anyone in this group personally, run `git log -- language/move-analyzer/editors/code` and send an email to one or more of the people who have committed to this directory. - -Once you've been added, confirm that you are able to access [the `move` publisher page](https://marketplace.visualstudio.com/manage/publishers/move). If you can see yourself listed in the "Members" tab, then you have successfully been added to the publisher team. - -### 2: Publish a new version - -To publish a new version of the extension, you'll need to: - -1. Create a personal access token (PAT) that allows your command line to authenticate with the Visual Studio Marketplace. -2. Publish and merge a pull request to update the version number of the extension. -3. Upload a new version of the extension to the Visual Studio Code Marketplace. - -#### 2.1: Create a personal access token - -Follow the instructions in [the Visual Studio Code documentation on creating a personal access token](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#get-a-personal-access-token). To summarize: - -1. From the [`move` publisher page](https://marketplace.visualstudio.com/manage/publishers/move), click on your username in the upper-right of the page. This will load [your Azure DevOps page](https://aex.dev.azure.com/me). -2. On that page, click on the `dev.azure.com/` link below "Azure DevOps Organizations." If you have more than one organization listed there, choose the one you feel is best. This will load the `https://dev.azure.com/` organization page. -3. On that page, click on the "User Settings" icon in the upper-right, and select "Personal access tokens" from the drop-down menu. This will load the "Personal Access Tokens" page. -4. On that page, click "New Token." Name it whatever you like but make sure to select an expiration of 30 days, select "All accessible organizations" under the "Organization" drop-down menu, and click the "Custom defined" button under "Scopes" followed by setting (only) "Marketplace" scope on the list of custom scopes to "Manage". Click "Create," and copy the token that is presented on the following page to your clipboard. -5. Using your command line, enter the directory containing this `CONTRIBUTING.md` file, make sure you've installed the project's dependencies using `npm install`, and then run `npx vsce login move`. You will be prompted to enter the token you just copied in the previous step. Do so, and you'll have successfully authenticated on the command line. - -#### 2.2: Update the version number of the extension - -The `package.json` file in this directory specifies the extension's version number. The Visual Studio Code Marketplace will only allow an extension with a greater version number to be published. - -Update the version number, commit that change in Git, and submit a pull request to update the version number. Once the version number update pull request is merged, proceed to the next step. - -#### 2.3: Upload a new version of the extension - -You can publish a new version with `npm run publish`. This will lint the source code, run the extension's tests and, if they succeed, validate the extension and publish it to the Visual Studio Code Marketplace. - -The extension package may fail to validate, in which case it will print an error message that explains the problem. Please fix the problems, submit a pull request, and only once that pull request is merged, attempt once again to publish the extension update. diff --git a/third_party/move/move-analyzer/editors/code/README.md b/third_party/move/move-analyzer/editors/code/README.md deleted file mode 100644 index 624f36b9c860c..0000000000000 --- a/third_party/move/move-analyzer/editors/code/README.md +++ /dev/null @@ -1,85 +0,0 @@ -# move-analyzer - -Provides language support for the Move programming language. - -Currently, this means a basic grammar and language configuration for Move (`.move`) that enables -syntax highlighting, commenting/uncommenting, simple context-unaware completion suggestions while -typing, and other basic language features in Move files. - -For information about Move visit [the Move repository](https://github.com/move-language/move). - -## How to Install - -The move-analyzer Visual Studio Code extension works via two components: the extension itself and -the `move-analyzer` language server. - -### 1. Installing the `move-analyzer` language server - -The `move-analyzer` language server is a Rust program that is part of the -[Move repository](https://github.com/move-language/move). It may be installed in one of two ways: - -* Clone [the Move repository](https://github.com/move-language/move) yourself and build - `move-analyzer` from its source code, which is especially useful if you will work on core Move. - To do so, follow the instructions in the Move tutorial's - [Step 0: Installation](https://github.com/move-language/move/tree/main/language/documentation/tutorial#step-0-installation). -* Use Rust's package manager `cargo` to install `move-analyzer` in your user's PATH. This - is recommended for people who do not work on core Move. - 1. If you don't already have a Rust toolchain installed, you should install - [Rustup](https://rustup.rs/), which will install the latest stable Rust toolchain. - 2. Invoke `cargo install --git https://github.com/move-language/move move-analyzer` to install the - `move-analyzer` language server in your Cargo binary directory. On macOS and Linux, this is - usually `~/.cargo/bin`. You'll want to make sure this location is in your `PATH` environment - variable. - -To confirm that you've installed the language server program successfully, execute -`move-analyzer --version` on the command line. You should see the output `move-analyzer 1.0.0`. - -### 2. Installing the move-analyzer Visual Studio Code extension - -1. Open a new window in any Visual Studio Code application version 1.55.2 or greater. -2. Open the command palette (`⇧⌘P` on macOS, or use the menu item *View > Command Palette...*) and - type **Extensions: Install Extensions**. This will open a panel named *Extensions* in the - sidebar of your Visual Studio Code window. -3. In the search bar labeled *Search Extensions in Marketplace*, type **move-analyzer**. The - move-analyzer extension should appear in the list below the search bar. Click **Install**. -4. Open any file that ends in `.move`. Or to create a new file, click **Select a language**, and - choose the **Move** language. As you type, you should see that keywords and types appear in - different colors. - -### Troubleshooting - -If you see an error message *language server executable 'move-analyzer' could not be found* in the -bottom-right of your Visual Studio Code screen when opening a Move file, it means that the -`move-analyzer` executable could not be found in your `PATH`. You may try the following: - -1. Confirm that invoking `move-analyzer --version` in a command line terminal prints out - `move-analyzer 1.0.0`. If it doesn't, then retry the instructions in [step 1](./Step1). If it - does successfully print this output, try closing and re-opening the Visual Studio Code - application, as it may not have picked up the update to your `PATH`. -2. If you installed the `move-analyzer` executable to a different location that is outside of your - `PATH`, then you may have the extension look at this location by using the Visual Studio Code - settings (`⌘,` on macOS, or use the menu item *Code > Preferences > Settings*). Search for the - `move-analyzer.server.path` setting, and set it to the location of the `move-analyzer` language - server you installed. -3. If the above steps don't work, then report - [a GitHub issue to the Move repository](https://github.com/move-language/move/issues) to get help. - -## Features - -Here are some of the features of the move-analyzer Visual Studio Code extension. To see them, open a -Move source file (a file with a `.move` file extension) and: - -- See Move keywords and types highlighted in appropriate colors. -- Comment and un-comment lines of code using the `⌘/` shortcut on macOS (or the menu command *Edit > - Toggle Line Comment*). -- Place your cursor on a delimiter, such as `<`, `(`, or `{`, and its corresponding delimiter -- - `>`, `)`, or `}` -- will be highlighted. -- As you type, Move keywords will appear as completion suggestions. -- If the opened Move source file is located within a buildable project (a `Move.toml` file can be - found in one of its parent directories), the following advanced features will also be available: - - compiler diagnostics - - go to definition - - go to type definition - - go to references - - type on hover - - outline view showing symbol tree for Move source files diff --git a/third_party/move/move-analyzer/editors/code/images/move.png b/third_party/move/move-analyzer/editors/code/images/move.png deleted file mode 100644 index c6bfb341aefab..0000000000000 Binary files a/third_party/move/move-analyzer/editors/code/images/move.png and /dev/null differ diff --git a/third_party/move/move-analyzer/editors/code/language-configuration.json b/third_party/move/move-analyzer/editors/code/language-configuration.json deleted file mode 100644 index bb8418a84785d..0000000000000 --- a/third_party/move/move-analyzer/editors/code/language-configuration.json +++ /dev/null @@ -1,32 +0,0 @@ -// A language configuration that specifies VS Code behaviors such as comment toggling -// and matching bracket highlighting. -// Use IntelliSense to learn about possible attributes. -// Hover to view descriptions of existing attributes. -// For more information, visit: -// https://code.visualstudio.com/api/language-extensions/language-configuration-guide -{ - "autoClosingPairs": [ - { "open": "{", "close": "}" }, - { "open": "[", "close": "]" }, - { "open": "(", "close": ")" }, - { "open": "\"", "close": "\"", "notIn": ["string", "comment"] }, - { "open": "/*", "close": "*/", "notIn": ["string"] } - ], - "brackets": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["<", ">"], - ], - "comments": { - "lineComment": "//", - "blockComment": ["/*", "*/"] - }, - "surroundingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["<", ">"], - ["\"", "\""] - ], -} diff --git a/third_party/move/move-analyzer/editors/code/package-lock.json b/third_party/move/move-analyzer/editors/code/package-lock.json deleted file mode 100644 index b4126498af0d5..0000000000000 --- a/third_party/move/move-analyzer/editors/code/package-lock.json +++ /dev/null @@ -1,7444 +0,0 @@ -{ - "name": "move-analyzer", - "version": "0.0.10", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "move-analyzer", - "version": "0.0.10", - "license": "Apache-2.0", - "dependencies": { - "command-exists": "^1.2.9", - "lru-cache": "^4.1.3", - "vscode-languageclient": "6.1.4" - }, - "devDependencies": { - "@types/command-exists": "^1.2.0", - "@types/fs-extra": "^9.0.13", - "@types/glob": "^7.1.4", - "@types/mocha": "^9.0.0", - "@types/node": "^14.17.22", - "@types/vscode": "^1.58.2", - "@typescript-eslint/eslint-plugin": "^4.33.0", - "@typescript-eslint/parser": "^4.33.0", - "@vscode/test-electron": "^2.0.0", - "copyfiles": "2.4.1", - "cross-env": "^7.0.3", - "eslint": "^7.32.0", - "eslint-plugin-tsdoc": "^0.2.14", - "fs-extra": "10.0.1", - "glob": "^7.1.7", - "mocha": "^9.1.1", - "typescript": "^4.4.4", - "typescript-formatter": "^7.2.2", - "vsce": "^2.5.1", - "vscode-test": "^1.6.1" - }, - "engines": { - "vscode": "^1.58.2" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "node_modules/@microsoft/tsdoc": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz", - "integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==", - "dev": true - }, - "node_modules/@microsoft/tsdoc-config": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz", - "integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.13.2", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@types/command-exists": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/command-exists/-/command-exists-1.2.0.tgz", - "integrity": "sha512-ugsxEJfsCuqMLSuCD4PIJkp5Uk2z6TCMRCgYVuhRo5cYQY3+1xXTQkSlPtkpGHuvWMjS2KTeVQXxkXRACMbM6A==", - "dev": true - }, - "node_modules/@types/fs-extra": { - "version": "9.0.13", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", - "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", - "dev": true, - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "node_modules/@types/mocha": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", - "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "14.17.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.27.tgz", - "integrity": "sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==", - "dev": true - }, - "node_modules/@types/vscode": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.61.0.tgz", - "integrity": "sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", - "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^4.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", - "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", - "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", - "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", - "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", - "dev": true, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", - "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", - "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "node_modules/@vscode/test-electron": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", - "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", - "dev": true, - "dependencies": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - }, - "engines": { - "node": ">=8.9.3" - } - }, - "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/azure-devops-node-api": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.0.tgz", - "integrity": "sha512-6/2YZuf+lJzJLrjXNYEA5RXAkMCb8j/4VcHD0qJQRsgG/KsRMYo0HgDh0by1FGHyZkQWY5LmQyJqCwRVUB3Y7Q==", - "dev": true, - "dependencies": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/big-integer": { - "version": "1.6.50", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", - "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", - "dev": true, - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", - "dev": true - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true, - "engines": { - "node": ">=0.2.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", - "dev": true, - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, - "dependencies": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cheerio/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/commandpost": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", - "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "node_modules/copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "dependencies": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "bin": { - "copyfiles": "copyfiles", - "copyup": "copyfiles" - } - }, - "node_modules/copyfiles/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dev": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "dependencies": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "bin": { - "editorconfig": "bin/editorconfig" - } - }, - "node_modules/editorconfig/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-tsdoc": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.14.tgz", - "integrity": "sha512-fJ3fnZRsdIoBZgzkQjv8vAj6NeeOoFkTfgosj6mKsFjX70QV256sA/wq+y/R2+OL4L8E79VVaVWrPeZnKNe8Ng==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.13.2", - "@microsoft/tsdoc-config": "0.15.2" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/eslint/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/fstream/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keytar": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.7.0.tgz", - "integrity": "sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "node-addon-api": "^3.0.0", - "prebuild-install": "^6.0.0" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", - "dev": true - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it/node_modules/entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "node_modules/mocha": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", - "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.2", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.25", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "dev": true, - "dependencies": { - "semver": "^5.4.1" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true - }, - "node_modules/noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } - }, - "node_modules/noms/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/noms/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/noms/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", - "dev": true, - "dependencies": { - "semver": "^5.1.0" - } - }, - "node_modules/parse-semver/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "dev": true, - "dependencies": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "node_modules/signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", - "dev": true - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", - "dev": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-rest-client": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.6.tgz", - "integrity": "sha512-xcQpTEAJw2DP7GqVNECh4dD+riS+C1qndXLfBCJ3xk0kqprtGN491P5KlmrDbKdtuW8NEcP/5ChxiJI3S9WYTA==", - "dev": true, - "dependencies": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "node_modules/typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/typescript-formatter": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", - "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", - "dev": true, - "dependencies": { - "commandpost": "^1.0.0", - "editorconfig": "^0.15.0" - }, - "bin": { - "tsfmt": "bin/tsfmt" - }, - "engines": { - "node": ">= 4.2.0" - }, - "peerDependencies": { - "typescript": "^2.1.6 || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev" - } - }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "node_modules/underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/vsce": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.5.1.tgz", - "integrity": "sha512-vJ+xY93Wv3NhgeriMyIC2oMA+niifOI9XGIqEToIq/rFRoQnXlmO4PSyis/OxBl9hw8OKKC/VcI9CijfFufEkw==", - "dev": true, - "dependencies": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^10.0.0", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "bin": { - "vsce": "vsce" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/vsce/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/vsce/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/vsce/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/vsce/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/vscode-jsonrpc": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz", - "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==", - "engines": { - "node": ">=8.0.0 || >=10.0.0" - } - }, - "node_modules/vscode-languageclient": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.4.tgz", - "integrity": "sha512-EUOU+bJu6axmt0RFNo3nrglQLPXMfanbYViJee3Fbn2VuQoX0ZOI4uTYhSRvYLP2vfwTP/juV62P/mksCdTZMA==", - "dependencies": { - "semver": "^6.3.0", - "vscode-languageserver-protocol": "3.15.3" - }, - "engines": { - "vscode": "^1.41.0" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz", - "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==", - "dependencies": { - "vscode-jsonrpc": "^5.0.1", - "vscode-languageserver-types": "3.15.1" - } - }, - "node_modules/vscode-languageserver-types": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz", - "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==" - }, - "node_modules/vscode-test": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", - "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", - "deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name", - "dev": true, - "dependencies": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - }, - "engines": { - "node": ">=8.9.3" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } - } - }, - "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - } - } - }, - "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", - "dev": true - }, - "@microsoft/tsdoc": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz", - "integrity": "sha512-WrHvO8PDL8wd8T2+zBGKrMwVL5IyzR3ryWUsl0PXgEV0QHup4mTLi0QcATefGI6Gx9Anu7vthPyyyLpY0EpiQg==", - "dev": true - }, - "@microsoft/tsdoc-config": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.15.2.tgz", - "integrity": "sha512-mK19b2wJHSdNf8znXSMYVShAHktVr/ib0Ck2FA3lsVBSEhSI/TfXT7DJQkAYgcztTuwazGcg58ZjYdk0hTCVrA==", - "dev": true, - "requires": { - "@microsoft/tsdoc": "0.13.2", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/command-exists": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/command-exists/-/command-exists-1.2.0.tgz", - "integrity": "sha512-ugsxEJfsCuqMLSuCD4PIJkp5Uk2z6TCMRCgYVuhRo5cYQY3+1xXTQkSlPtkpGHuvWMjS2KTeVQXxkXRACMbM6A==", - "dev": true - }, - "@types/fs-extra": { - "version": "9.0.13", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", - "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "@types/mocha": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz", - "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==", - "dev": true - }, - "@types/node": { - "version": "14.17.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.27.tgz", - "integrity": "sha512-94+Ahf9IcaDuJTle/2b+wzvjmutxXAEXU6O81JHblYXUg2BDG+dnBy7VxIPHKAyEEDHzCMQydTJuWvrE+Aanzw==", - "dev": true - }, - "@types/vscode": { - "version": "1.61.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.61.0.tgz", - "integrity": "sha512-9k5Nwq45hkRwdfCFY+eKXeQQSbPoA114mF7U/4uJXRBJeGIO7MuJdhF1PnaDN+lllL9iKGQtd6FFXShBXMNaFg==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", - "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "4.33.0", - "@typescript-eslint/scope-manager": "4.33.0", - "debug": "^4.3.1", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.1.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz", - "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.7", - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz", - "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "4.33.0", - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/typescript-estree": "4.33.0", - "debug": "^4.3.1" - } - }, - "@typescript-eslint/scope-manager": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz", - "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0" - } - }, - "@typescript-eslint/types": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz", - "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz", - "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.33.0", - "@typescript-eslint/visitor-keys": "4.33.0", - "debug": "^4.3.1", - "globby": "^11.0.3", - "is-glob": "^4.0.1", - "semver": "^7.3.5", - "tsutils": "^3.21.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "4.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz", - "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "4.33.0", - "eslint-visitor-keys": "^2.0.0" - } - }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "@vscode/test-electron": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.1.5.tgz", - "integrity": "sha512-O/ioqFpV+RvKbRykX2ItYPnbcZ4Hk5V0rY4uhQjQTLhGL9WZUvS7exzuYQCCI+ilSqJpctvxq2llTfGXf9UnnA==", - "dev": true, - "requires": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - } - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "azure-devops-node-api": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.0.tgz", - "integrity": "sha512-6/2YZuf+lJzJLrjXNYEA5RXAkMCb8j/4VcHD0qJQRsgG/KsRMYo0HgDh0by1FGHyZkQWY5LmQyJqCwRVUB3Y7Q==", - "dev": true, - "requires": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "big-integer": { - "version": "1.6.50", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.50.tgz", - "integrity": "sha512-+O2uoQWFRo8ysZNo/rjtri2jIwjr3XfeAgRjAUADRqGG+ZITvyn8J1kvXLTaKVr3hhGXk+f23tKfdzmklVM9vQ==", - "dev": true - }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", - "dev": true, - "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", - "dev": true - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true - }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, - "requires": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - } - } - }, - "cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "requires": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - } - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "command-exists": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==" - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "commandpost": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz", - "integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "requires": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, - "decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dev": true, - "requires": { - "mimic-response": "^2.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "dev": true - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "dev": true, - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "eslint-plugin-tsdoc": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.14.tgz", - "integrity": "sha512-fJ3fnZRsdIoBZgzkQjv8vAj6NeeOoFkTfgosj6mKsFjX70QV256sA/wq+y/R2+OL4L8E79VVaVWrPeZnKNe8Ng==", - "dev": true, - "requires": { - "@microsoft/tsdoc": "0.13.2", - "@microsoft/tsdoc-config": "0.15.2" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", - "dev": true - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", - "dev": true - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hosted-git-info": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", - "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", - "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha1-o6vicYryQaKykE+EpiWXDzia4yo=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "keytar": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.7.0.tgz", - "integrity": "sha512-YEY9HWqThQc5q5xbXbRwsZTh2PJ36OSYRjSv3NN2xf5s5dpLTjEZnC2YikR29OaVybf9nQ0dJ/80i40RS97t/A==", - "dev": true, - "requires": { - "node-addon-api": "^3.0.0", - "prebuild-install": "^6.0.0" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - } - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "mocha": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", - "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.2", - "debug": "4.3.2", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.7", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.25", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.1.5", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "nanoid": { - "version": "3.1.25", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", - "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", - "dev": true - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node-abi": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", - "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "dev": true, - "requires": { - "semver": "^5.4.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true - }, - "noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", - "dev": true, - "requires": { - "semver": "^5.1.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "requires": { - "parse5": "^6.0.1" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "prebuild-install": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz", - "integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^2.21.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^3.0.3", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "requires": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", - "dev": true - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true - }, - "simple-get": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", - "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", - "dev": true, - "requires": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz", - "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", - "dev": true - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typed-rest-client": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.6.tgz", - "integrity": "sha512-xcQpTEAJw2DP7GqVNECh4dD+riS+C1qndXLfBCJ3xk0kqprtGN491P5KlmrDbKdtuW8NEcP/5ChxiJI3S9WYTA==", - "dev": true, - "requires": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", - "dev": true - }, - "typescript-formatter": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz", - "integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==", - "dev": true, - "requires": { - "commandpost": "^1.0.0", - "editorconfig": "^0.15.0" - } - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", - "dev": true - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true - }, - "unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "requires": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "vsce": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-2.5.1.tgz", - "integrity": "sha512-vJ+xY93Wv3NhgeriMyIC2oMA+niifOI9XGIqEToIq/rFRoQnXlmO4PSyis/OxBl9hw8OKKC/VcI9CijfFufEkw==", - "dev": true, - "requires": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^10.0.0", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "vscode-jsonrpc": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz", - "integrity": "sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==" - }, - "vscode-languageclient": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.1.4.tgz", - "integrity": "sha512-EUOU+bJu6axmt0RFNo3nrglQLPXMfanbYViJee3Fbn2VuQoX0ZOI4uTYhSRvYLP2vfwTP/juV62P/mksCdTZMA==", - "requires": { - "semver": "^6.3.0", - "vscode-languageserver-protocol": "3.15.3" - } - }, - "vscode-languageserver-protocol": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.3.tgz", - "integrity": "sha512-zrMuwHOAQRhjDSnflWdJG+O2ztMWss8GqUUB8dXLR/FPenwkiBNkMIJJYfSN6sgskvsF0rHAoBowNQfbyZnnvw==", - "requires": { - "vscode-jsonrpc": "^5.0.1", - "vscode-languageserver-types": "3.15.1" - } - }, - "vscode-languageserver-types": { - "version": "3.15.1", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz", - "integrity": "sha512-+a9MPUQrNGRrGU630OGbYVQ+11iOIovjCkqxajPa9w57Sd5ruK8WQNsslzpa0x/QJqC8kRc2DUxWjIFwoNm4ZQ==" - }, - "vscode-test": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", - "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", - "dev": true, - "requires": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "workerpool": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", - "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/third_party/move/move-analyzer/editors/code/package.json b/third_party/move/move-analyzer/editors/code/package.json deleted file mode 100644 index 9e54615e571e5..0000000000000 --- a/third_party/move/move-analyzer/editors/code/package.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "name": "move-analyzer", - "displayName": "move-analyzer", - "description": "A language server and basic grammar for the Move programming language.", - "publisher": "move", - "icon": "images/move.png", - "license": "Apache-2.0", - "version": "0.0.10", - "preview": true, - "homepage": "https://github.com/move-language/move", - "repository": { - "url": "https://github.com/move-language/move.git", - "type": "git" - }, - "bugs": { - "url": "https://github.com/move-language/move/issues" - }, - "engines": { - "vscode": "^1.58.2" - }, - "categories": [ - "Programming Languages" - ], - "keywords": [ - "move" - ], - "main": "./out/src/main.js", - "activationEvents": [ - "onLanguage:move", - "workspaceContains:Move.toml" - ], - "contributes": { - "commands": [ - { - "command": "move-analyzer.serverVersion", - "title": "Show Server Version", - "category": "Move Analyzer" - } - ], - "configuration": { - "type": "object", - "title": "Move Analyzer", - "properties": { - "move-analyzer.server.path": { - "type": "string", - "default": "move-analyzer", - "markdownDescription": "Path and filename of the move-analyzer executable, e.g. `/usr/bin/move-analyzer`." - }, - "move-analyzer.trace.server": { - "type": "string", - "scope": "window", - "enum": [ - "off", - "messages", - "verbose" - ], - "enumDescriptions": [ - "Do not log any messages.", - "Log short summaries of each message.", - "Log each message and its contents." - ], - "default": "off", - "description": "Traces the communication between the move-analyzer language server and Visual Studio Code. Note that this log can be very verbose, and so not recommended for anyone besides people working on or debugging move-analyzer itself." - } - } - }, - "languages": [ - { - "id": "move", - "aliases": [ - "Move", - "move" - ], - "extensions": [ - ".move" - ], - "configuration": "./language-configuration.json" - } - ], - "menus": { - "commandPalette": [ - { - "command": "move-analyzer.serverVersion" - } - ] - } - }, - "scripts": { - "compile": "tsc -p ./ && cd ../../ && cargo build", - "watch": "tsc -watch -p ./", - "lint": "eslint . --ext ts --max-warnings 0", - "fix": "eslint . --ext ts --fix", - "copy-tests-files": "copyfiles \"tests/**/*.move\" \"tests/**/*.exp\" \"tests/**/*.toml\" \"tests/**/*.code-workspace\" out", - "pretest": "npm run compile && npm run lint && npm run copy-tests-files", - "test": "node ./out/tests/runTests.js", - "dev": "npm run pretest && cross-env mode=dev node ./out/tests/runTests.js", - "vscode:prepublish": "npm run pretest", - "package": "npm run pretest && vsce package -o move-analyzer.vsix", - "publish": "npm run pretest && npm run test && vsce publish" - }, - "extensionDependencies": [ - "damirka.move-syntax" - ], - "dependencies": { - "command-exists": "^1.2.9", - "vscode-languageclient": "6.1.4", - "lru-cache": "^4.1.3" - }, - "devDependencies": { - "@types/command-exists": "^1.2.0", - "@types/fs-extra": "^9.0.13", - "@types/glob": "^7.1.4", - "@types/mocha": "^9.0.0", - "@types/node": "^14.17.22", - "@types/vscode": "^1.58.2", - "@typescript-eslint/eslint-plugin": "^4.33.0", - "@typescript-eslint/parser": "^4.33.0", - "@vscode/test-electron": "^2.0.0", - "copyfiles": "2.4.1", - "cross-env": "^7.0.3", - "eslint": "^7.32.0", - "eslint-plugin-tsdoc": "^0.2.14", - "fs-extra": "10.0.1", - "glob": "^7.1.7", - "mocha": "^9.1.1", - "typescript": "^4.4.4", - "typescript-formatter": "^7.2.2", - "vsce": "^2.5.1", - "vscode-test": "^1.6.1" - }, - "__metadata": { - "id": "71e74fc8-23c2-47b7-8594-ed00192d96a6", - "publisherDisplayName": "move", - "publisherId": "40d7def1-c662-4965-9ead-c06109c7cc6d", - "isPreReleaseVersion": false - } -} diff --git a/third_party/move/move-analyzer/editors/code/src/commands/index.ts b/third_party/move/move-analyzer/editors/code/src/commands/index.ts deleted file mode 100644 index 71d5f7fdfb688..0000000000000 --- a/third_party/move/move-analyzer/editors/code/src/commands/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './lsp_command'; diff --git a/third_party/move/move-analyzer/editors/code/src/commands/lsp_command.ts b/third_party/move/move-analyzer/editors/code/src/commands/lsp_command.ts deleted file mode 100644 index 157551759a21c..0000000000000 --- a/third_party/move/move-analyzer/editors/code/src/commands/lsp_command.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { - DocumentSymbolParams, - SymbolInformation, - DocumentSymbol, - CompletionParams, - CompletionList, - CompletionItem, -} from 'vscode-languageclient'; -import { DocumentSymbolRequest, HoverRequest, CompletionRequest } from 'vscode-languageclient'; -import type { Context } from '../context'; - -/** - * An LSP command textDocument/documentSymbol - */ -export async function textDocumentDocumentSymbol( - context: Readonly, - params: DocumentSymbolParams, -): Promise { - const client = context.getClient(); - if (client === undefined) { - return Promise.reject(new Error('No language client connected.')); - } - - // Send the request to the language client. - return client.sendRequest(DocumentSymbolRequest.type, params); -} - -/** - * An LSP command textDocument/completion - */ -export async function textDocumentCompletion( - context: Readonly, - params: CompletionParams, -): Promise { - const client = context.getClient(); - if (client === undefined) { - return Promise.reject(new Error('No language client connected.')); - } - - // Send the request to the language client. - return client.sendRequest(CompletionRequest.type, params); -} - - -/** - * An LSP command textDocument/hover - */ -export async function textDocumentHover( - context: Readonly, - params: DocumentSymbolParams, -) - : Promise { - const client = context.getClient(); - if (client === undefined) { - return Promise.reject(new Error('No language client connected.')); - } - - // Send the request to the language client. - return client.sendRequest(HoverRequest.method, params); -} diff --git a/third_party/move/move-analyzer/editors/code/src/configuration.ts b/third_party/move/move-analyzer/editors/code/src/configuration.ts deleted file mode 100644 index 595a791cf5ceb..0000000000000 --- a/third_party/move/move-analyzer/editors/code/src/configuration.ts +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -import * as os from 'os'; -import * as vscode from 'vscode'; -import * as Path from 'path'; - -/** - * User-defined configuration values, such as those specified in VS Code settings. - * - * This provides a more strongly typed interface to the configuration values specified in this - * extension's `package.json`, under the key `"contributes.configuration.properties"`. - */ -export class Configuration { - private readonly configuration: vscode.WorkspaceConfiguration; - - constructor() { - this.configuration = vscode.workspace.getConfiguration('move-analyzer'); - } - - /** A string representation of the configured values, for logging purposes. */ - toString(): string { - return JSON.stringify(this.configuration); - } - - /** The path to the move-analyzer executable. */ - get serverPath(): string { - const defaultName = 'move-analyzer'; - let serverPath = this.configuration.get('server.path', defaultName); - if (serverPath.length === 0) { - // The default value of the `server.path` setting is 'move-analyzer'. - // A user may have over-written this default with an empty string value, ''. - // An empty string cannot be an executable name, so instead use the default. - return defaultName; - } - - if (serverPath === defaultName) { - // If the program set by the user is through PATH, - // it will return directly if specified - return defaultName; - } - - if (serverPath.startsWith('~/')) { - serverPath = os.homedir() + serverPath.slice('~'.length); - } - - if (process.platform === 'win32' && !serverPath.endsWith('.exe')) { - serverPath = serverPath + '.exe'; - } - - return Path.resolve(serverPath); - } -} diff --git a/third_party/move/move-analyzer/editors/code/src/context.ts b/third_party/move/move-analyzer/editors/code/src/context.ts deleted file mode 100644 index 2f894923b8750..0000000000000 --- a/third_party/move/move-analyzer/editors/code/src/context.ts +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { Configuration } from './configuration'; -import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; -import { log } from './log'; -import { sync as commandExistsSync } from 'command-exists'; -import { IndentAction } from 'vscode'; - -/** Information passed along to each VS Code command defined by this extension. */ -export class Context { - private client: lc.LanguageClient | undefined; - - private constructor( - private readonly extensionContext: Readonly, - readonly configuration: Readonly, - client: lc.LanguageClient | undefined = undefined, - ) { - this.client = client; - } - - static create( - extensionContext: Readonly, - configuration: Readonly, - ): Context | Error { - if (!commandExistsSync(configuration.serverPath)) { - return new Error( - `language server executable '${configuration.serverPath}' could not be found, so ` + - 'most extension features will be unavailable to you. Follow the instructions in ' + - 'the move-analyzer Visual Studio Code extension README to install the language ' + - 'server.', - ); - } - return new Context(extensionContext, configuration); - } - - /** - * Registers the given command with VS Code. - * - * "Registering" the function means that the VS Code machinery will execute it when the command - * with the given name is requested by the user. The command names themselves are specified in - * this extension's `package.json` file, under the key `"contributes.commands"`. - */ - registerCommand( - name: Readonly, - command: (context: Readonly, ...args: Array) => any, - ): void { - const disposable = vscode.commands.registerCommand( - `move-analyzer.${name}`, - async (...args: Array) : Promise => { - const ret = await command(this, ...args); - return ret; - }, - ); - - this.extensionContext.subscriptions.push(disposable); - } - - /** - * Sets up additional language configuration that's impossible to do via a - * separate language-configuration.json file. See [1] for more information. - * - * This code originates from [2](vscode-rust). - * - * [1]: https://github.com/Microsoft/vscode/issues/11514#issuecomment-244707076 - * [2]: https://github.com/rust-lang/vscode-rust/blob/660b412701fe2ea62fad180c40ee4f8a60571c61/src/extension.ts#L287:L287 - */ - configureLanguage(): void { - const disposable = vscode.languages.setLanguageConfiguration('move', { - onEnterRules: [ - { - // Doc single-line comment - // e.g. ///| - beforeText: /^\s*\/{3}.*$/, - action: { indentAction: IndentAction.None, appendText: '/// ' }, - }, - { - // Parent doc single-line comment - // e.g. //!| - beforeText: /^\s*\/{2}!.*$/, - action: { indentAction: IndentAction.None, appendText: '//! ' }, - }, - ], - }); - this.extensionContext.subscriptions.push(disposable); - } - - /** - * Configures and starts the client that interacts with the language server. - * - * The "client" is an object that sends messages to the language server, which in Move's case is - * the `move-analyzer` executable. Unlike registered extension commands such as - * `move-analyzer.serverVersion`, which are manually executed by a VS Code user via the command - * palette or menu, this client sends many of its messages on its own (for example, when it - * starts, it sends the "initialize" request). - * - * To read more about the messages sent and responses received by this client, such as - * "initialize," read [the Language Server Protocol specification](https://microsoft.github.io/language-server-protocol/specifications/specification-current/#initialize). - * - * In order to synchronously wait for the client to be completely ready, - * we need to mark the function as asynchronous - **/ - async startClient(): Promise { - const executable: lc.Executable = { - command: this.configuration.serverPath, - }; - const serverOptions: lc.ServerOptions = { - run: executable, - debug: executable, - }; - - // The vscode-languageclient module reads a configuration option named - // ".trace.server" to determine whether to log messages. If a trace output - // channel is specified, these messages are printed there, otherwise they appear in the - // output channel that it automatically created by the `LanguageClient` (in this extension, - // that is 'Move Language Server'). For more information, see: - // https://code.visualstudio.com/api/language-extensions/language-server-extension-guide#logging-support-for-language-server - const traceOutputChannel = vscode.window.createOutputChannel( - 'Move Analyzer Language Server Trace', - ); - const clientOptions: lc.LanguageClientOptions = { - documentSelector: [{ scheme: 'file', language: 'move' }], - traceOutputChannel, - }; - - const client = new lc.LanguageClient( - 'move-analyzer', - 'Move Language Server', - serverOptions, - clientOptions, - ); - log.info('Starting client...'); - const disposable = client.start(); - this.extensionContext.subscriptions.push(disposable); - this.client = client; - - // Wait for the Move Language Server initialization to complete, - // especially the first symbol table parsing is completed - await this.client.onReady(); - } - - /** - * Returns the client that this extension interacts with. - * - * @returns lc.LanguageClient - */ - getClient(): lc.LanguageClient | undefined { - return this.client; - } -} // Context diff --git a/third_party/move/move-analyzer/editors/code/src/extension.ts b/third_party/move/move-analyzer/editors/code/src/extension.ts deleted file mode 100644 index e7a33415c3dfa..0000000000000 --- a/third_party/move/move-analyzer/editors/code/src/extension.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -import * as assert from 'assert'; -import * as vscode from 'vscode'; - -/** Information related to this extension itself, such as its identifier and version. */ -export class Extension { - /** The string used to uniquely identify this particular extension to VS Code. */ - readonly identifier = 'move.move-analyzer'; - - private readonly extension: vscode.Extension; - - constructor() { - const extension = vscode.extensions.getExtension(this.identifier); - assert(extension !== undefined, `extension ${this.identifier} is not available`); - this.extension = extension; - } - - /** The version string. */ - get version(): string { - for (const entry of Object.entries(this.extension.packageJSON)) { - if (entry[0] === 'version') { - return entry[1] as string; - } - } - return 'unknown'; - } -} diff --git a/third_party/move/move-analyzer/editors/code/src/log.ts b/third_party/move/move-analyzer/editors/code/src/log.ts deleted file mode 100644 index ccdbd985c4f6e..0000000000000 --- a/third_party/move/move-analyzer/editors/code/src/log.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -import * as vscode from 'vscode'; - -/** - * A logger for the VS Code extension. - * - * Messages that are logged appear in an output channel created below that is dedicated to the - * extension (or "client"), in the extension user's "Output View." This logger should be used for - * messages related to VS Code and this extension, as opposed to messages regarding the language - * server, which appear in a separate output channel. - **/ -export const log = new class { - private readonly output = vscode.window.createOutputChannel('Move Analyzer Client'); - - /** Log an informational message (as opposed to an error or a warning). */ - info(message: string): void { - this.write('INFO', message); - } - - private write(label: string, message: string): void { - this.output.appendLine(`${label} [${new Date().toLocaleString()}]: ${message}`); - } -}(); diff --git a/third_party/move/move-analyzer/editors/code/src/main.ts b/third_party/move/move-analyzer/editors/code/src/main.ts deleted file mode 100644 index 64981a2263291..0000000000000 --- a/third_party/move/move-analyzer/editors/code/src/main.ts +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -import { Configuration } from './configuration'; -import { Context } from './context'; -import { Extension } from './extension'; -import { log } from './log'; - -import * as childProcess from 'child_process'; -import * as vscode from 'vscode'; -import * as commands from './commands'; - - -/** - * An extension command that displays the version of the server that this extension - * interfaces with. - */ -async function serverVersion(context: Readonly): Promise { - const version = childProcess.spawnSync( - context.configuration.serverPath, ['--version'], { encoding: 'utf8' }, - ); - if (version.stdout) { - await vscode.window.showInformationMessage(version.stdout); - } else if (version.error) { - await vscode.window.showErrorMessage( - `Could not execute move-analyzer: ${version.error.message}.`, - ); - } else { - await vscode.window.showErrorMessage( - `A problem occurred when executing '${context.configuration.serverPath}'.`, - ); - } -} - -/** - * The entry point to this VS Code extension. - * - * As per [the VS Code documentation on activation - * events](https://code.visualstudio.com/api/references/activation-events), "an extension must - * export an `activate()` function from its main module and it will be invoked only once by - * VS Code when any of the specified activation events [are] emitted." - * - * Activation events for this extension are listed in its `package.json` file, under the key - * `"activationEvents"`. - * - * In order to achieve synchronous activation, mark the function as an asynchronous function, - * so that you can wait for the activation to complete by await - */ -export async function activate(extensionContext: Readonly): Promise { - const extension = new Extension(); - log.info(`${extension.identifier} version ${extension.version}`); - - const configuration = new Configuration(); - log.info(`configuration: ${configuration.toString()}`); - - const context = Context.create(extensionContext, configuration); - // An error here -- for example, if the path to the `move-analyzer` binary that the user - // specified in their settings is not valid -- prevents the extension from providing any - // more utility, so return early. - if (context instanceof Error) { - void vscode.window.showErrorMessage( - `Could not activate move-analyzer: ${context.message}.`, - ); - return; - } - - // Register handlers for VS Code commands that the user explicitly issues. - context.registerCommand('serverVersion', serverVersion); - - // Configure other language features. - context.configureLanguage(); - - // All other utilities provided by this extension occur via the language server. - await context.startClient(); - context.registerCommand('textDocumentDocumentSymbol', commands.textDocumentDocumentSymbol); - context.registerCommand('textDocumentHover', commands.textDocumentHover); - context.registerCommand('textDocumentCompletion', commands.textDocumentCompletion); -} diff --git a/third_party/move/move-analyzer/editors/code/tests/ext.test.ts b/third_party/move/move-analyzer/editors/code/tests/ext.test.ts deleted file mode 100644 index c73d6c7078c12..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/ext.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -import * as assert from 'assert'; -import * as Mocha from 'mocha'; -import * as vscode from 'vscode'; - -Mocha.suite('ext', () => { - Mocha.test('ext_exists', () => { - const ext = vscode.extensions.getExtension('move.move-analyzer'); - assert.ok(ext); - }); -}); diff --git a/third_party/move/move-analyzer/editors/code/tests/index.ts b/third_party/move/move-analyzer/editors/code/tests/index.ts deleted file mode 100644 index 1660a4dc499e8..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -/** - * This file contains what VS Code's documentation refers to as "the test runner," which - * programmatically executes each test file in our extension. For more information, see: - * https://code.visualstudio.com/api/working-with-extensions/testing-extension#the-test-runner-script - */ - -import * as glob from 'glob'; -import * as Mocha from 'mocha'; -import * as path from 'path'; -/* eslint-disable */ -// deno-lint-ignore require-await -export async function run(): Promise { - // dev mode - const mode = process.env['mode'] || 'test'; - if (mode === 'dev') { - return new Promise((resolve) => { - setTimeout(resolve, 1000 * 60 * 15); // Development mode, set a timeout of 15 minutes - }); - } - - /* eslint-disable */ - const suite = new Mocha({ - ui: 'tdd', - color: true, - // The default timeout of 2000 miliseconds can sometimes be too quick, since the extension - // tests need to launch VS Code first. - timeout: 10000, - }); - - const testsRoot = path.resolve(__dirname, '..'); - return new Promise((resolve, reject) => { - // The test suite is composed of all files ending with '.test.js'. - glob('**/**.test.js', { cwd: testsRoot }, (err, files: ReadonlyArray) => { - if (err) { - return reject(err); - } - - // Add each file to the test suite. - files.forEach(f => suite.addFile(path.resolve(testsRoot, f))); - - // Run the test suite. Uncaught exceptions or a non-zero number of - // test rejectures is considered a test suite rejecture. - try { - return suite.run(failures => { - if (failures > 0) { - reject(new Error(`${failures} tests failed.`)); - } else { - resolve(); - } - }); - } catch (err: unknown) { - console.error(err); - return reject(err); - } - }); - }); -} diff --git a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/Move.toml b/third_party/move/move-analyzer/editors/code/tests/lsp-demo/Move.toml deleted file mode 100644 index 47ddc673957e7..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Symbols" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../../../../move-stdlib/", addr_subst = { "std" = "0x1" } } - -[addresses] -Symbols = "0xCAFE" diff --git a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/lsp-demo-win.code-workspace b/third_party/move/move-analyzer/editors/code/tests/lsp-demo/lsp-demo-win.code-workspace deleted file mode 100644 index 4651fb61d000d..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/lsp-demo-win.code-workspace +++ /dev/null @@ -1,10 +0,0 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": { - "move-analyzer.server.path": "../../../../../../target/debug/move-analyzer" - } -} diff --git a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/lsp-demo.code-workspace b/third_party/move/move-analyzer/editors/code/tests/lsp-demo/lsp-demo.code-workspace deleted file mode 100644 index 087aded48f988..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/lsp-demo.code-workspace +++ /dev/null @@ -1,10 +0,0 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": { - "move-analyzer.server.path": "../../../../target/debug/move-analyzer" - } -} diff --git a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/Completions.move b/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/Completions.move deleted file mode 100644 index b0ff2df28f651..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/Completions.move +++ /dev/null @@ -1,13 +0,0 @@ -module Symbols::Completions { - fun add(a: u64, b: u64): u64 { - a + b - } - - fun subtract(a: u64, b: u64): u64 { - a - b - } - - fun divide(a: u64, b: u64): u64 { - a / b - } -} diff --git a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M1.move b/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M1.move deleted file mode 100644 index d1454454b67ba..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M1.move +++ /dev/null @@ -1,18 +0,0 @@ -module Symbols::M1 { - - const SOME_CONST: u64 = 42; - - struct SomeOtherStruct has drop { - some_field: u64, - } - - public fun some_other_struct(v: u64): SomeOtherStruct { - SomeOtherStruct { some_field: v } - } - - #[test] - #[expected_failure] - fun this_is_a_test() { - 1/0; - } -} diff --git a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M2.move b/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M2.move deleted file mode 100644 index 4d00f275e7eae..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M2.move +++ /dev/null @@ -1,22 +0,0 @@ -module Symbols::M2 { - - /// Constant containing the answer to the universe - const DOCUMENTED_CONSTANT: u64 = 42; - - /** - This is a multiline docstring - - This docstring has empty lines. - - It uses the ** format instead of /// - */ - fun other_doc_struct(): Symbols::M3::OtherDocStruct { - Symbols::M3::create_other_struct(DOCUMENTED_CONSTANT) - } - - use Symbols::M3::{Self, OtherDocStruct}; - - fun other_doc_struct_import(): OtherDocStruct { - M3::create_other_struct(7) - } -} diff --git a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M3.move b/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M3.move deleted file mode 100644 index 1fd363e82e98d..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/lsp-demo/sources/M3.move +++ /dev/null @@ -1,12 +0,0 @@ -module Symbols::M3 { - - /// Documented struct in another module - struct OtherDocStruct has drop { - some_field: u64, - } - - /// Documented initializer in another module - public fun create_other_struct(v: u64): OtherDocStruct { - OtherDocStruct { some_field: v } - } -} diff --git a/third_party/move/move-analyzer/editors/code/tests/lsp.test.ts b/third_party/move/move-analyzer/editors/code/tests/lsp.test.ts deleted file mode 100644 index c07e29730f4b5..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/lsp.test.ts +++ /dev/null @@ -1,218 +0,0 @@ -import * as assert from 'assert'; -import * as Mocha from 'mocha'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import * as lc from 'vscode-languageclient'; -import type { MarkupContent } from 'vscode-languageclient'; -import { CompletionItemKind } from 'vscode-languageclient'; - -const isFunctionInCompletionItems = (fnName: string, items: vscode.CompletionItem[]): boolean => { - return ( - items.find((item) => item.label === fnName && item.kind === CompletionItemKind.Function) !== - undefined - ); -}; - -const isKeywordInCompletionItems = (label: string, items: vscode.CompletionItem[]): boolean => { - return ( - items.find((item) => item.label === label && item.kind === CompletionItemKind.Keyword) !== - undefined - ); -}; - -const PRIMITIVE_TYPES = ['u8', 'u16', 'u32', 'u64', 'u128', 'u256', 'bool', 'vector']; - -Mocha.suite('LSP', () => { - Mocha.test('textDocument/documentSymbol', async () => { - const ext = vscode.extensions.getExtension('move.move-analyzer'); - assert.ok(ext); - - await ext.activate(); // Synchronous waiting for activation to complete - - // 1. get workdir - const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; - - // 2. open doc - const docs = await vscode.workspace.openTextDocument(path.join(workDir, 'sources/M1.move')); - await vscode.window.showTextDocument(docs); - - // 3. execute command - const params: lc.DocumentSymbolParams = { - textDocument: { - uri: docs.uri.toString(), - }, - }; - - const syms: Array | undefined = await - vscode.commands.executeCommand( - 'move-analyzer.textDocumentDocumentSymbol', params, - ); - - assert.ok(syms); - assert.deepStrictEqual(syms[0]?.kind, lc.SymbolKind.Module); - assert.deepStrictEqual(syms[0].name, 'M1'); - - assert.ok(syms[0].children); - assert.deepStrictEqual(syms[0]?.children[0]?.kind, lc.SymbolKind.Constant); - assert.deepStrictEqual(syms[0]?.children[0].name, 'SOME_CONST'); - assert.deepStrictEqual(syms[0]?.children[1]?.kind, lc.SymbolKind.Struct); - assert.deepStrictEqual(syms[0]?.children[1].name, 'SomeOtherStruct'); - assert.ok(syms[0].children[1].children); - assert.deepStrictEqual(syms[0]?.children[1]?.children[0]?.kind, lc.SymbolKind.Field); - assert.deepStrictEqual(syms[0]?.children[1]?.children[0]?.name, 'some_field'); - assert.deepStrictEqual(syms[0]?.children[1].name, 'SomeOtherStruct'); - assert.deepStrictEqual(syms[0]?.children[2]?.kind, lc.SymbolKind.Function); - assert.deepStrictEqual(syms[0]?.children[2].name, 'some_other_struct'); - assert.deepStrictEqual(syms[0]?.children[3]?.kind, lc.SymbolKind.Function); - assert.deepStrictEqual(syms[0]?.children[3].name, 'this_is_a_test'); - assert.deepStrictEqual(syms[0]?.children[3]?.detail, '["test", "expected_failure"]'); - }); - - Mocha.test('textDocument/hover for definition in the same module', async () => { - const ext = vscode.extensions.getExtension('move.move-analyzer'); - assert.ok(ext); - - await ext.activate(); // Synchronous waiting for activation to complete - - // 1. get workdir - const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; - - // 2. open doc - const docs = await vscode.workspace.openTextDocument( - path.join(workDir, 'sources/M2.move'), - ); - await vscode.window.showTextDocument(docs); - - // 3. execute command - const params: lc.HoverParams = { - textDocument: { - uri: docs.uri.toString(), - }, - position: { - line: 12, - character: 8, - }, - }; - - const hoverResult: lc.Hover | undefined = - await vscode.commands.executeCommand( - 'move-analyzer.textDocumentHover', - params, - ); - - assert.ok(hoverResult); - assert.deepStrictEqual((hoverResult.contents as MarkupContent).value, - // eslint-disable-next-line max-len - 'fun Symbols::M2::other_doc_struct(): Symbols::M3::OtherDocStruct\n\n\nThis is a multiline docstring\n\nThis docstring has empty lines.\n\nIt uses the ** format instead of ///\n\n'); - - }); - - Mocha.test('textDocument/hover for definition in an external module', async () => { - const ext = vscode.extensions.getExtension('move.move-analyzer'); - assert.ok(ext); - - await ext.activate(); // Synchronous waiting for activation to complete - - // 1. get workdir - const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; - - // 2. open doc - const docs = await vscode.workspace.openTextDocument( - path.join(workDir, 'sources/M2.move'), - ); - await vscode.window.showTextDocument(docs); - - // 3. execute command - const params: lc.HoverParams = { - textDocument: { - uri: docs.uri.toString(), - }, - position: { - line: 18, - character: 35, - }, - }; - - const hoverResult: lc.Hover | undefined = - await vscode.commands.executeCommand( - 'move-analyzer.textDocumentHover', - params, - ); - - - assert.ok(hoverResult); - assert.deepStrictEqual((hoverResult.contents as MarkupContent).value, - 'Symbols::M3::OtherDocStruct\n\nDocumented struct in another module\n'); - }); - - Mocha.test('textDocument/completion', async () => { - const ext = vscode.extensions.getExtension('move.move-analyzer'); - assert.ok(ext); - - await ext.activate(); // Synchronous waiting for activation to complete - - // 1. get workdir - const workDir = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath ?? ''; - - // 2. open doc - const docs = await vscode.workspace.openTextDocument( - path.join(workDir, 'sources/Completions.move'), - ); - await vscode.window.showTextDocument(docs); - - // 3. execute command - const params: lc.CompletionParams = { - textDocument: { - uri: docs.uri.toString(), - }, - position: { - line: 12, - character: 1, - }, - }; - - const items = await vscode.commands.executeCommand>( - 'move-analyzer.textDocumentCompletion', - params, - ); - - assert.ok(items); - - // Items should return all functions defined in the file - assert.strictEqual(isFunctionInCompletionItems('add', items), true); - assert.strictEqual(isFunctionInCompletionItems('subtract', items), true); - assert.strictEqual(isFunctionInCompletionItems('divide', items), true); - - // Items also include all primitive types because they are keywords - PRIMITIVE_TYPES.forEach((primitive) => { - assert.strictEqual(isKeywordInCompletionItems(primitive, items), true); - }); - - const colonParams: lc.CompletionParams = { - textDocument: { - uri: docs.uri.toString(), - }, - // The position of the character ":" - position: { - line: 9, - character: 15, - }, - }; - - const itemsOnColon = await vscode.commands.executeCommand>( - 'move-analyzer.textDocumentCompletion', - colonParams, - ); - - assert.ok(itemsOnColon); - - const keywordsOnColon = itemsOnColon.filter(i => i.kind === CompletionItemKind.Keyword); - // Primitive types are the only keywords returned after inserting the colon - assert.strictEqual(keywordsOnColon.length, PRIMITIVE_TYPES.length); - - // Final safety check - PRIMITIVE_TYPES.forEach((primitive) => { - assert.strictEqual(isKeywordInCompletionItems(primitive, keywordsOnColon), true); - }); - }); -}); diff --git a/third_party/move/move-analyzer/editors/code/tests/runTests.ts b/third_party/move/move-analyzer/editors/code/tests/runTests.ts deleted file mode 100644 index a8cd46f28528f..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tests/runTests.ts +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -/** - * This file contains what VS Code's documentation refers to as "the test script," which downloads, - * unzips, launches a VS Code instance with our extension installed, and executes the "test runner." - * For more information, see: - * https://code.visualstudio.com/api/working-with-extensions/testing-extension#the-test-script - */ - -import * as os from 'os'; -import * as path from 'path'; -import * as cp from 'child_process'; -import * as fs from 'fs'; -import * as fse from 'fs-extra'; -import { - runTests, - downloadAndUnzipVSCode, - resolveCliArgsFromVSCodeExecutablePath, -} from '@vscode/test-electron'; - -/** - * Launches a VS Code instance to run tests. - * - * This is essentially a TypeScript program that executes the "VS Code Tokenizer Tests" launch - * target defined in this repository's `.vscode/launch.json`. - */ -async function runVSCodeTest(vscodeVersion: string): Promise { - try { - // The `--extensionDevelopmentPath` argument passed to VS Code. This should point to the - // directory that contains the extension manifest file, `package.json`. - const extensionDevelopmentPath = path.resolve(__dirname, '..', '..'); - - // The `--extensionTestsPath` argument passed to VS Code. This should point to a JavaScript - // program that is considered to be the "test suite" for the extension. - const extensionTestsPath = path.resolve(__dirname, 'index.js'); - - // The workspace - let testWorkspacePath = path.resolve(__dirname, './lsp-demo/lsp-demo.code-workspace'); - if (process.platform === 'win32') { - testWorkspacePath = path.resolve(__dirname, './lsp-demo/lsp-demo-win.code-workspace'); - } - - // Install vscode and depends extension - const vscodeExecutablePath = await downloadAndUnzipVSCode(vscodeVersion); - const [cli, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); - const newCli = cli ?? 'code'; - cp.spawnSync(newCli, [...args, '--install-extension', 'damirka.move-syntax', '--force'], { - encoding: 'utf-8', - stdio: 'inherit', - }); - - // Because the default vscode userDataDir is too long, - // v1.69.2 will report an error when running test. - // So generate a short - const userDataDir = path.join(os.tmpdir(), 'vscode-test', vscodeVersion); - if (!fs.existsSync(userDataDir)) { - fse.mkdirsSync(userDataDir); - } - - // Download VS Code, unzip it, and run the "test suite" program. - await runTests({ - vscodeExecutablePath: vscodeExecutablePath, - extensionDevelopmentPath, - extensionTestsPath, - launchArgs: [testWorkspacePath, '--user-data-dir', userDataDir], - }); - } catch (_err: unknown) { - console.error('Failed to run tests'); - process.exit(1); - } -} - -async function main(): Promise { - await runVSCodeTest('1.64.0'); // Test with vscode v1.64.0 - await runVSCodeTest('1.69.2'); // Test with vscode v1.69.2 -} - -void main(); diff --git a/third_party/move/move-analyzer/editors/code/tsconfig.json b/third_party/move/move-analyzer/editors/code/tsconfig.json deleted file mode 100644 index 47562cb37faad..0000000000000 --- a/third_party/move/move-analyzer/editors/code/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "compilerOptions": { - "module": "CommonJS", - "target": "es2020", - "outDir": "out", - "lib": [ - "es2020" - ], - "sourceMap": true, - "rootDir": ".", - "newLine": "LF", - "strict": true, - "allowUnreachableCode": false, - "allowUnusedLabels": false, - "exactOptionalPropertyTypes": true, - "noFallthroughCasesInSwitch": true, - "noImplicitAny": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noImplicitThis": true, - "noPropertyAccessFromIndexSignature": true, - "noUncheckedIndexedAccess": true, - "noUnusedLocals": true, - "noUnusedParameters": true - }, - "exclude": [ - "node_modules", - ".vscode-test" - ], - "include": [ - "src", - "tests", - "types" - ] -} diff --git a/third_party/move/move-analyzer/src/bin/move-analyzer.rs b/third_party/move/move-analyzer/src/bin/move-analyzer.rs deleted file mode 100644 index 2921c1d04a932..0000000000000 --- a/third_party/move/move-analyzer/src/bin/move-analyzer.rs +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use clap::Parser; -use crossbeam::channel::{bounded, select}; -use lsp_server::{Connection, Message, Notification, Request, Response}; -use lsp_types::{ - notification::Notification as _, request::Request as _, CompletionOptions, Diagnostic, - HoverProviderCapability, OneOf, SaveOptions, TextDocumentSyncCapability, TextDocumentSyncKind, - TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions, -}; -use move_analyzer::{ - completion::on_completion_request, - context::Context, - symbols, - vfs::{on_text_document_sync_notification, VirtualFileSystem}, -}; -use move_symbol_pool::Symbol; -use std::{ - collections::BTreeMap, - path::Path, - sync::{Arc, Mutex}, - thread, -}; -use url::Url; - -#[derive(Parser)] -#[clap(author, version, about)] -struct Options {} - -fn main() { - // For now, move-analyzer only responds to options built-in to clap, - // such as `--help` or `--version`. - Options::parse(); - - // stdio is used to communicate Language Server Protocol requests and responses. - // stderr is used for logging (and, when Visual Studio Code is used to communicate with this - // server, it captures this output in a dedicated "output channel"). - let exe = std::env::current_exe() - .unwrap() - .to_string_lossy() - .to_string(); - eprintln!( - "Starting language server '{}' communicating via stdio...", - exe - ); - - let (connection, io_threads) = Connection::stdio(); - let symbols = Arc::new(Mutex::new(symbols::Symbolicator::empty_symbols())); - let mut context = Context { - connection, - files: VirtualFileSystem::default(), - symbols: symbols.clone(), - }; - - let (id, client_response) = context - .connection - .initialize_start() - .expect("could not start connection initialization"); - - let capabilities = serde_json::to_value(lsp_types::ServerCapabilities { - // The server receives notifications from the client as users open, close, - // and modify documents. - text_document_sync: Some(TextDocumentSyncCapability::Options( - TextDocumentSyncOptions { - open_close: Some(true), - // TODO: We request that the language server client send us the entire text of any - // files that are modified. We ought to use the "incremental" sync kind, which would - // have clients only send us what has changed and where, thereby requiring far less - // data be sent "over the wire." However, to do so, our language server would need - // to be capable of applying deltas to its view of the client's open files. See the - // 'move_analyzer::vfs' module for details. - change: Some(TextDocumentSyncKind::Full), - will_save: None, - will_save_wait_until: None, - save: Some( - SaveOptions { - include_text: Some(true), - } - .into(), - ), - }, - )), - selection_range_provider: None, - hover_provider: Some(HoverProviderCapability::Simple(true)), - // The server provides completions as a user is typing. - completion_provider: Some(CompletionOptions { - resolve_provider: None, - // In Move, `foo::` and `foo.` should trigger completion suggestions for after - // the `:` or `.` - // (Trigger characters are just that: characters, such as `:`, and not sequences of - // characters, such as `::`. So when the language server encounters a completion - // request, it checks whether completions are being requested for `foo:`, and returns no - // completions in that case.) - trigger_characters: Some(vec![":".to_string(), ".".to_string()]), - all_commit_characters: None, - work_done_progress_options: WorkDoneProgressOptions { - work_done_progress: None, - }, - }), - definition_provider: Some(OneOf::Left(symbols::DEFS_AND_REFS_SUPPORT)), - type_definition_provider: Some(TypeDefinitionProviderCapability::Simple( - symbols::DEFS_AND_REFS_SUPPORT, - )), - references_provider: Some(OneOf::Left(symbols::DEFS_AND_REFS_SUPPORT)), - document_symbol_provider: Some(OneOf::Left(true)), - ..Default::default() - }) - .expect("could not serialize server capabilities"); - - let (diag_sender, diag_receiver) = bounded::>>>(0); - let mut symbolicator_runner = symbols::SymbolicatorRunner::idle(); - if symbols::DEFS_AND_REFS_SUPPORT { - let initialize_params: lsp_types::InitializeParams = - serde_json::from_value(client_response) - .expect("could not deserialize client capabilities"); - - symbolicator_runner = symbols::SymbolicatorRunner::new(symbols.clone(), diag_sender); - - // If initialization information from the client contains a path to the directory being - // opened, try to initialize symbols before sending response to the client. Do not bother - // with diagnostics as they will be recomputed whenever the first source file is opened. The - // main reason for this is to enable unit tests that rely on the symbolication information - // to be available right after the client is initialized. - if let Some(uri) = initialize_params.root_uri { - if let Some(p) = symbols::SymbolicatorRunner::root_dir(&uri.to_file_path().unwrap()) { - // need to evaluate in a separate thread to allow for a larger stack size (needed on - // Windows) - thread::Builder::new() - .stack_size(symbols::STACK_SIZE_BYTES) - .spawn(move || { - if let Ok((Some(new_symbols), _)) = - symbols::Symbolicator::get_symbols(p.as_path()) - { - let mut old_symbols = symbols.lock().unwrap(); - (*old_symbols).merge(new_symbols); - } - }) - .unwrap() - .join() - .unwrap(); - } - } - }; - - context - .connection - .initialize_finish( - id, - serde_json::json!({ - "capabilities": capabilities, - }), - ) - .expect("could not finish connection initialization"); - - loop { - select! { - recv(diag_receiver) -> message => { - match message { - Ok(result) => { - match result { - Ok(diags) => { - for (k, v) in diags { - let url = Url::from_file_path(Path::new(&k.to_string())).unwrap(); - let params = lsp_types::PublishDiagnosticsParams::new(url, v, None); - let notification = Notification::new(lsp_types::notification::PublishDiagnostics::METHOD.to_string(), params); - if let Err(err) = context - .connection - .sender - .send(lsp_server::Message::Notification(notification)) { - eprintln!("could not send diagnostics response: {:?}", err); - }; - } - }, - Err(err) => { - let typ = lsp_types::MessageType::Error; - let message = format!("{err}"); - // report missing manifest only once to avoid re-generating - // user-visible error in cases when the developer decides to - // keep editing a file that does not belong to a packages - let params = lsp_types::ShowMessageParams { typ, message }; - let notification = Notification::new(lsp_types::notification::ShowMessage::METHOD.to_string(), params); - if let Err(err) = context - .connection - .sender - .send(lsp_server::Message::Notification(notification)) { - eprintln!("could not send compiler error response: {:?}", err); - }; - }, - } - }, - Err(error) => eprintln!("symbolicator message error: {:?}", error), - } - }, - recv(context.connection.receiver) -> message => { - match message { - Ok(Message::Request(request)) => on_request(&context, &request), - Ok(Message::Response(response)) => on_response(&context, &response), - Ok(Message::Notification(notification)) => { - match notification.method.as_str() { - lsp_types::notification::Exit::METHOD => break, - lsp_types::notification::Cancel::METHOD => { - // TODO: Currently the server does not implement request cancellation. - // It ought to, especially once it begins processing requests that may - // take a long time to respond to. - } - _ => on_notification(&mut context, &symbolicator_runner, ¬ification), - } - } - Err(error) => eprintln!("IDE message error: {:?}", error), - } - } - }; - } - - io_threads.join().expect("I/O threads could not finish"); - symbolicator_runner.quit(); - eprintln!("Shut down language server '{}'.", exe); -} - -fn on_request(context: &Context, request: &Request) { - match request.method.as_str() { - lsp_types::request::Completion::METHOD => { - on_completion_request(context, request, &context.symbols.lock().unwrap()) - }, - lsp_types::request::GotoDefinition::METHOD => { - symbols::on_go_to_def_request(context, request, &context.symbols.lock().unwrap()); - }, - lsp_types::request::GotoTypeDefinition::METHOD => { - symbols::on_go_to_type_def_request(context, request, &context.symbols.lock().unwrap()); - }, - lsp_types::request::References::METHOD => { - symbols::on_references_request(context, request, &context.symbols.lock().unwrap()); - }, - lsp_types::request::HoverRequest::METHOD => { - symbols::on_hover_request(context, request, &context.symbols.lock().unwrap()); - }, - lsp_types::request::DocumentSymbolRequest::METHOD => { - symbols::on_document_symbol_request(context, request, &context.symbols.lock().unwrap()); - }, - _ => eprintln!("handle request '{}' from client", request.method), - } -} - -fn on_response(_context: &Context, _response: &Response) { - eprintln!("handle response from client"); -} - -fn on_notification( - context: &mut Context, - symbolicator_runner: &symbols::SymbolicatorRunner, - notification: &Notification, -) { - match notification.method.as_str() { - lsp_types::notification::DidOpenTextDocument::METHOD - | lsp_types::notification::DidChangeTextDocument::METHOD - | lsp_types::notification::DidSaveTextDocument::METHOD - | lsp_types::notification::DidCloseTextDocument::METHOD => { - on_text_document_sync_notification( - &mut context.files, - symbolicator_runner, - notification, - ) - }, - _ => eprintln!("handle notification '{}' from client", notification.method), - } -} - -#[test] -fn verify_tool() { - use clap::CommandFactory; - Options::command().debug_assert() -} diff --git a/third_party/move/move-analyzer/src/completion.rs b/third_party/move/move-analyzer/src/completion.rs deleted file mode 100644 index 8a3380253a32f..0000000000000 --- a/third_party/move/move-analyzer/src/completion.rs +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use crate::{context::Context, symbols::Symbols}; -use lsp_server::Request; -use lsp_types::{CompletionItem, CompletionItemKind, CompletionParams, Position}; -use move_command_line_common::files::FileHash; -use move_compiler::parser::{ - keywords::{BUILTINS, CONTEXTUAL_KEYWORDS, KEYWORDS, PRIMITIVE_TYPES}, - lexer::{Lexer, Tok}, -}; -use move_symbol_pool::Symbol; -use std::{collections::HashSet, path::PathBuf}; - -/// Constructs an `lsp_types::CompletionItem` with the given `label` and `kind`. -fn completion_item(label: &str, kind: CompletionItemKind) -> CompletionItem { - CompletionItem { - label: label.to_owned(), - kind: Some(kind), - ..Default::default() - } -} - -/// Return a list of completion items corresponding to each one of Move's keywords. -/// -/// Currently, this does not filter keywords out based on whether they are valid at the completion -/// request's cursor position, but in the future it ought to. For example, this function returns -/// all specification language keywords, but in the future it should be modified to only do so -/// within a spec block. -fn keywords() -> Vec { - KEYWORDS - .iter() - .chain(CONTEXTUAL_KEYWORDS.iter()) - .chain(PRIMITIVE_TYPES.iter()) - .map(|label| { - let kind = if label == &"copy" || label == &"move" { - CompletionItemKind::Operator - } else { - CompletionItemKind::Keyword - }; - completion_item(label, kind) - }) - .collect() -} - -/// Return a list of completion items of Move's primitive types -fn primitive_types() -> Vec { - PRIMITIVE_TYPES - .iter() - .map(|label| completion_item(label, CompletionItemKind::Keyword)) - .collect() -} - -/// Return a list of completion items corresponding to each one of Move's builtin functions. -fn builtins() -> Vec { - BUILTINS - .iter() - .map(|label| completion_item(label, CompletionItemKind::Function)) - .collect() -} - -/// Lexes the Move source file at the given path and returns a list of completion items -/// corresponding to the non-keyword identifiers therein. -/// -/// Currently, this does not perform semantic analysis to determine whether the identifiers -/// returned are valid at the request's cursor position. However, this list of identifiers is akin -/// to what editors like Visual Studio Code would provide as completion items if this language -/// server did not initialize with a response indicating it's capable of providing completions. In -/// the future, the server should be modified to return semantically valid completion items, not -/// simple textual suggestions. -fn identifiers(buffer: &str, symbols: &Symbols, path: &PathBuf) -> Vec { - let mut lexer = Lexer::new(buffer, FileHash::new(buffer)); - if lexer.advance().is_err() { - return vec![]; - } - - let mut ids = HashSet::new(); - while lexer.peek() != Tok::EOF { - // Some tokens, such as "phantom", are contextual keywords that are only reserved in - // certain contexts. Since for now this language server doesn't analyze semantic context, - // tokens such as "phantom" are always present in keyword suggestions. To avoid displaying - // these keywords to the user twice in the case that the token "phantom" is present in the - // source program (once as a keyword, and once as an identifier), we filter out any - // identifier token that has the same text as a keyword. - if lexer.peek() == Tok::Identifier && !KEYWORDS.contains(&lexer.content()) { - // The completion item kind "text" indicates the item is not based on any semantic - // context of the request cursor's position. - ids.insert(lexer.content()); - } - if lexer.advance().is_err() { - break; - } - } - - let mods_opt = symbols.file_mods().get(path); - - // The completion item kind "text" indicates that the item is based on simple textual matching, - // not any deeper semantic analysis. - ids.iter() - .map(|label| { - if let Some(mods) = mods_opt { - if mods - .iter() - .any(|m| m.functions().contains_key(&Symbol::from(*label))) - { - completion_item(label, CompletionItemKind::Function) - } else { - completion_item(label, CompletionItemKind::Text) - } - } else { - completion_item(label, CompletionItemKind::Text) - } - }) - .collect() -} - -/// Returns the token corresponding to the "trigger character" that precedes the user's cursor, -/// if it is one of `.`, `:`, or `::`. Otherwise, returns `None`. -fn get_cursor_token(buffer: &str, position: &Position) -> Option { - // If the cursor is at the start of a new line, it cannot be preceded by a trigger character. - if position.character == 0 { - return None; - } - - let line = match buffer.lines().nth(position.line as usize) { - Some(line) => line, - None => return None, // Our buffer does not contain the line, and so must be out of date. - }; - match line.chars().nth(position.character as usize - 1) { - Some('.') => Some(Tok::Period), - Some(':') => { - if position.character > 1 - && line.chars().nth(position.character as usize - 2) == Some(':') - { - Some(Tok::ColonColon) - } else { - Some(Tok::Colon) - } - }, - _ => None, - } -} - -/// Sends the given connection a response to a completion request. -/// -/// The completions returned depend upon where the user's cursor is positioned. -pub fn on_completion_request(context: &Context, request: &Request, symbols: &Symbols) { - eprintln!("handling completion request"); - let parameters = serde_json::from_value::(request.params.clone()) - .expect("could not deserialize completion request"); - - let path = parameters - .text_document_position - .text_document - .uri - .to_file_path() - .unwrap(); - let buffer = context.files.get(&path); - if buffer.is_none() { - eprintln!( - "Could not read '{:?}' when handling completion request", - path - ); - } - - // The completion items we provide depend upon where the user's cursor is positioned. - let cursor = - buffer.and_then(|buf| get_cursor_token(buf, ¶meters.text_document_position.position)); - - let mut items = vec![]; - match cursor { - Some(Tok::Colon) => { - items.extend_from_slice(&primitive_types()); - }, - Some(Tok::Period) | Some(Tok::ColonColon) => { - // `.` or `::` must be followed by identifiers, which are added to the completion items - // below. - }, - _ => { - // If the user's cursor is positioned anywhere other than following a `.`, `:`, or `::`, - // offer them Move's keywords, operators, and builtins as completion items. - items.extend_from_slice(&keywords()); - items.extend_from_slice(&builtins()); - }, - } - - if let Some(buffer) = &buffer { - let identifiers = identifiers(buffer, symbols, &path); - items.extend_from_slice(&identifiers); - } - - let result = serde_json::to_value(items).expect("could not serialize completion response"); - eprintln!("about to send completion response"); - let response = lsp_server::Response::new_ok(request.id.clone(), result); - if let Err(err) = context - .connection - .sender - .send(lsp_server::Message::Response(response)) - { - eprintln!("could not send completion response: {:?}", err); - } -} diff --git a/third_party/move/move-analyzer/src/context.rs b/third_party/move/move-analyzer/src/context.rs deleted file mode 100644 index 36b3eaf0abe8a..0000000000000 --- a/third_party/move/move-analyzer/src/context.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use crate::{symbols::Symbols, vfs::VirtualFileSystem}; -use lsp_server::Connection; -use std::sync::{Arc, Mutex}; - -/// The context within which the language server is running. -pub struct Context { - /// The connection with the language server's client. - pub connection: Connection, - /// The files that the language server is providing information about. - pub files: VirtualFileSystem, - /// Symbolication information - pub symbols: Arc>, -} diff --git a/third_party/move/move-analyzer/src/diagnostics.rs b/third_party/move/move-analyzer/src/diagnostics.rs deleted file mode 100644 index db3bd96461a98..0000000000000 --- a/third_party/move/move-analyzer/src/diagnostics.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use crate::utils::get_loc; -use codespan_reporting::{diagnostic::Severity, files::SimpleFiles}; -use lsp_types::{Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, Location, Range}; -use move_command_line_common::files::FileHash; -use move_ir_types::location::Loc; -use move_symbol_pool::Symbol; -use std::collections::{BTreeMap, HashMap}; -use url::Url; - -/// Converts diagnostics from the codespan format to the format understood by the language server. -pub fn lsp_diagnostics( - diagnostics: &Vec<( - codespan_reporting::diagnostic::Severity, - &'static str, - (Loc, String), - Vec<(Loc, String)>, - Vec, - )>, - files: &SimpleFiles, - file_id_mapping: &HashMap, - file_name_mapping: &BTreeMap, -) -> BTreeMap> { - let mut lsp_diagnostics = BTreeMap::new(); - for (s, _, (loc, msg), labels, _) in diagnostics { - let fpath = file_name_mapping.get(&loc.file_hash()).unwrap(); - if let Some(start) = get_loc(&loc.file_hash(), loc.start(), files, file_id_mapping) { - if let Some(end) = get_loc(&loc.file_hash(), loc.end(), files, file_id_mapping) { - let range = Range::new(start, end); - let related_info_opt = if labels.is_empty() { - None - } else { - Some( - labels - .iter() - .filter_map(|(lloc, lmsg)| { - let lstart = get_loc( - &lloc.file_hash(), - lloc.start(), - files, - file_id_mapping, - )?; - let lend = - get_loc(&lloc.file_hash(), lloc.end(), files, file_id_mapping)?; - let lpath = file_name_mapping.get(&lloc.file_hash()).unwrap(); - let lpos = Location::new( - Url::from_file_path(lpath.as_str()).unwrap(), - Range::new(lstart, lend), - ); - Some(DiagnosticRelatedInformation { - location: lpos, - message: lmsg.to_string(), - }) - }) - .collect(), - ) - }; - lsp_diagnostics - .entry(*fpath) - .or_insert_with(Vec::new) - .push(Diagnostic::new( - range, - Some(severity(*s)), - None, - None, - msg.to_string(), - related_info_opt, - None, - )); - } - } - } - lsp_diagnostics -} - -/// Produces empty diagnostics in the format understood by the language server for all files that -/// the language server is aware of. -pub fn lsp_empty_diagnostics( - file_name_mapping: &BTreeMap, -) -> BTreeMap> { - let mut lsp_diagnostics = BTreeMap::new(); - for n in file_name_mapping.values() { - lsp_diagnostics.insert(*n, vec![]); - } - lsp_diagnostics -} - -/// Converts diagnostic severity level from the codespan format to the format understood by the -/// language server. -fn severity(s: Severity) -> DiagnosticSeverity { - match s { - Severity::Bug => DiagnosticSeverity::Error, - Severity::Error => DiagnosticSeverity::Error, - Severity::Warning => DiagnosticSeverity::Warning, - Severity::Note => DiagnosticSeverity::Information, - Severity::Help => DiagnosticSeverity::Hint, - } -} diff --git a/third_party/move/move-analyzer/src/lib.rs b/third_party/move/move-analyzer/src/lib.rs deleted file mode 100644 index 845f5d154c776..0000000000000 --- a/third_party/move/move-analyzer/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -#[macro_use(sp)] -extern crate move_ir_types; - -pub mod completion; -pub mod context; -pub mod diagnostics; -pub mod symbols; -pub mod utils; -pub mod vfs; diff --git a/third_party/move/move-analyzer/src/symbols.rs b/third_party/move/move-analyzer/src/symbols.rs deleted file mode 100644 index 1d866b79d0166..0000000000000 --- a/third_party/move/move-analyzer/src/symbols.rs +++ /dev/null @@ -1,3676 +0,0 @@ -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -#![allow(clippy::non_canonical_partial_ord_impl)] - -//! This module is responsible for building symbolication information on top of compiler's typed -//! AST, in particular identifier definitions to be used for implementing go-to-def and -//! go-to-references language server commands. -//! -//! There are two main structs that are used at different phases of the process, the Symbolicator -//! struct is used when building symbolication information and the Symbols struct is summarizes the -//! symbolication results and is used by the language server find definitions and references. -//! -//! Here is a brief description of how the symbolication information is encoded. Each identifier is -//! in the source code of a given module is represented by its location (UseLoc struct): line -//! number, starting and ending column, and hash of the source file where this identifier is -//! located). A definition for each identifier (if any - e.g., built-in type definitions are -//! excluded as there is no place in source code where they are defined) is also represented by its -//! location in the source code (DefLoc struct): line, starting column and a hash of the source -//! file where it's located. The symbolication process maps each identifier with its definition - a -//! per module map is keyed on the line number where the identifier is located, and the map entry -//! contains a list of identifier/definition pairs ordered by the column where the identifier starts. -//! -//! For example consider the following code fragment (0-based line numbers on the left and 0-based -//! column numbers at the bottom): -//! -//! 7: const SOME_CONST: u64 = 42; -//! 8: -//! 9: SOME_CONST + SOME_CONST -//! | | | | | | -//! 0 6 9 13 15 22 -//! -//! Symbolication information for this code fragment would look as follows assuming that this code -//! is stored in a file with hash FHASH (note that identifier in the definition of the constant maps -//! to itself): -//! -//! [7] -> [UseLoc(7:6-13, FHASH), DefLoc(7:6, FHASH)] -//! [9] -> [UseLoc(9:0-9 , FHASH), DefLoc((7:6, FHASH)], [UseLoc(9:13-22, FHASH), DefLoc((7:6, FHASH)] -//! -//! Including line number (and file hash) with the (use) identifier location may appear redundant, -//! but it's needed to allow accumulating uses with each definition to support -//! go-to-references. This is done in a global map from an identifier location (DefLoc) to a set of -//! use locations (UseLoc) - we find a all references of a given identifier by first finding its -//! definition and then using this definition as a key to the global map. -//! -//! Symbolication algorithm first analyzes all top-level definitions from all modules and then -//! processes function bodies and struct definitions to match uses to definitions. For local -//! definitions, the symbolicator builds a scope stack, entering encountered definitions and -//! matching uses to a definition in the innermost scope. - -use crate::{ - context::Context, - diagnostics::{lsp_diagnostics, lsp_empty_diagnostics}, - utils::get_loc, -}; -use anyhow::{anyhow, Result}; -use codespan_reporting::files::SimpleFiles; -use crossbeam::channel::Sender; -use derivative::*; -use im::ordmap::OrdMap; -use lsp_server::{Request, RequestId}; -use lsp_types::{ - request::GotoTypeDefinitionParams, Diagnostic, DocumentSymbol, DocumentSymbolParams, - GotoDefinitionParams, Hover, HoverContents, HoverParams, LanguageString, Location, - MarkedString, Position, Range, ReferenceParams, SymbolKind, -}; -use move_command_line_common::files::FileHash; -use move_compiler::{ - expansion::ast::{Address, Fields, ModuleIdent, ModuleIdent_}, - naming::ast::{StructDefinition, StructFields, TParam, Type, TypeName_, Type_}, - parser::ast::StructName, - shared::Identifier, - typing::ast::{ - BuiltinFunction_, Exp, ExpListItem, Function, FunctionBody_, LValue, LValueList, LValue_, - ModuleCall, ModuleDefinition, SequenceItem, SequenceItem_, UnannotatedExp_, - }, - PASS_TYPING, -}; -use move_ir_types::location::*; -use move_package::{ - compilation::{build_plan::BuildPlan, compiled_package::unimplemented_v2_driver}, - CompilerConfig, -}; -use move_symbol_pool::Symbol; -use std::{ - cmp, - collections::{BTreeMap, BTreeSet, HashMap}, - fmt, - path::{Path, PathBuf}, - sync::{Arc, Condvar, Mutex}, - thread, -}; -use tempfile::tempdir; -use url::Url; - -/// Enabling/disabling the language server reporting readiness to support go-to-def and -/// go-to-references to the IDE. -pub const DEFS_AND_REFS_SUPPORT: bool = true; -// Building Move code requires a larger stack size on Windows (16M has been chosen somewhat -// arbitrarily) -pub const STACK_SIZE_BYTES: usize = 16 * 1024 * 1024; - -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)] -/// Location of a definition's identifier -struct DefLoc { - /// File where the definition of the identifier starts - fhash: FileHash, - /// Location where the definition of the identifier starts - start: Position, -} - -/// Location of a use's identifier -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)] -struct UseLoc { - /// File where this use identifier starts - fhash: FileHash, - /// Location where this use identifier starts - start: Position, - /// Column (on the same line as start) where this use identifier ends - col_end: u32, -} - -/// Information about a type of an identifier. The reason we need an additional enum is that there -/// is not direct representation of a function type in the Type enum. -#[derive(Debug, Clone, Eq, PartialEq)] -#[allow(clippy::large_enum_variant)] -pub enum IdentType { - RegularType(Type), - FunctionType( - ModuleIdent_, /* defining module */ - Symbol, /* name */ - Vec, /* type args */ - Vec, /* arg names */ - Vec, /* arg types */ - Type, /* ret */ - Vec, /* acquires */ - ), -} - -/// Information about both the use identifier (source file is specified wherever an instance of this -/// struct is used) and the definition identifier -#[derive(Debug, Clone, Eq)] -pub struct UseDef { - /// Column where the (use) identifier location starts on a given line (use this field for - /// sorting uses on the line) - col_start: u32, - /// Column where the (use) identifier location ends on a given line - col_end: u32, - /// Type of the (use) identifier - use_type: IdentType, - /// Location of the definition - def_loc: DefLoc, - /// Location of the type definition - type_def_loc: Option, - /// Doc string for the relevant identifier/function - doc_string: String, -} - -/// Definition of a struct field -#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] -struct FieldDef { - name: Symbol, - start: Position, -} - -/// Definition of a struct -#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] -struct StructDef { - name_start: Position, - field_defs: Vec, -} - -#[derive(Derivative)] -#[derivative(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] -pub struct FunctionDef { - name: Symbol, - start: Position, - attrs: Vec, - #[derivative(PartialEq = "ignore")] - #[derivative(PartialOrd = "ignore")] - #[derivative(Ord = "ignore")] - ident_type: IdentType, -} - -/// Module-level definitions -#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] -pub struct ModuleDefs { - /// File where this module is located - fhash: FileHash, - /// Location where this module is located - start: Position, - /// Module name - name: ModuleIdent_, - /// Struct definitions - structs: BTreeMap, - /// Const definitions - constants: BTreeMap, - /// Function definitions - functions: BTreeMap, -} - -/// Data used during symbolication -pub struct Symbolicator { - /// Outermost definitions in a module (structs, consts, functions) - mod_outer_defs: BTreeMap, - /// A mapping from file names to file content (used to obtain source file locations) - files: SimpleFiles, - /// A mapping from file hashes to file IDs (used to obtain source file locations) - file_id_mapping: HashMap, - // A mapping from file IDs to a split vector of the lines in each file (used to build docstrings) - file_id_to_lines: HashMap>, - /// Contains type params where relevant (e.g. when processing function definition) - type_params: BTreeMap, - /// Current processed module (always set before module processing starts) - current_mod: Option, -} - -/// Maps a line number to a list of use-def pairs on a given line (use-def set is sorted by -/// col_start) -#[derive(Debug, Clone, Eq, PartialEq)] -struct UseDefMap(BTreeMap>); - -/// Maps a function name to its usage definition -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct FunctionIdentTypeMap(BTreeMap); - -/// Result of the symbolication process -pub struct Symbols { - /// A map from def locations to all the references (uses) - references: BTreeMap>, - /// A mapping from uses to definitions in a file - file_use_defs: BTreeMap, - /// A mapping from file hashes to file names - file_name_mapping: BTreeMap, - /// A mapping from filePath to ModuleDefs - file_mods: BTreeMap>, -} - -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] -enum RunnerState { - Run(PathBuf), - Wait, - Quit, -} - -/// Data used during symbolication running and symbolication info updating -pub struct SymbolicatorRunner { - mtx_cvar: Arc<(Mutex, Condvar)>, -} - -impl ModuleDefs { - pub fn functions(&self) -> &BTreeMap { - &self.functions - } -} - -impl fmt::Display for IdentType { - fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result { - match self { - Self::RegularType(t) => { - // Technically, we could use error_format function here to display the "regular" - // type, but the original intent of this function is subtly different that we need - // (i.e., to be used by compiler error messages) which, for example, results in - // verbosity that is not needed here. - // - // It also seems like a reasonable idea to be able to tune user experience in the - // IDE independently on how compiler error messages are generated. - write!(f, "{}", type_to_ide_string(t)) - }, - Self::FunctionType(mod_ident, name, type_args, arg_names, arg_types, ret, acquires) => { - let type_args_str = if !type_args.is_empty() { - let mut s = '<'.to_string(); - s.push_str(&type_list_to_ide_string(type_args)); - s.push('>'); - s - } else { - "".to_string() - }; - let acquires_str = if !acquires.is_empty() { - let mut s = " acquires ".to_string(); - s.push_str(&type_list_to_ide_string(acquires)); - s - } else { - "".to_string() - }; - let ret_str = match ret { - sp!(_, Type_::Unit) => "".to_string(), - _ => format!(": {}", type_to_ide_string(ret)), - }; - - write!( - f, - "fun {}::{}::{}{}({}){}{}", - addr_to_ide_string(&mod_ident.address), - mod_ident.module.value(), - name, - type_args_str, - arg_list_to_ide_string(arg_names, arg_types), - ret_str, - acquires_str - ) - }, - } - } -} - -fn arg_list_to_ide_string(names: &[Symbol], types: &[Type]) -> String { - names - .iter() - .zip(types.iter()) - .map(|(n, t)| format!("{}: {}", n, type_to_ide_string(t))) - .collect::>() - .join(", ") -} - -fn type_to_ide_string(sp!(_, t): &Type) -> String { - match t { - Type_::Unit => "()".to_string(), - Type_::Ref(m, r) => format!("&{} {}", if *m { "mut" } else { "" }, type_to_ide_string(r)), - Type_::Param(tp) => { - format!("{}", tp.user_specified_name) - }, - Type_::Apply(_, sp!(_, type_name), ss) => match type_name { - TypeName_::Multiple(_) => { - format!("({})", type_list_to_ide_string(ss)) - }, - TypeName_::Builtin(name) => { - if ss.is_empty() { - format!("{}", name) - } else { - format!("{}<{}>", name, type_list_to_ide_string(ss)) - } - }, - TypeName_::ModuleType(sp!(_, module_ident), struct_name) => { - let addr = addr_to_ide_string(&module_ident.address); - format!( - "{}::{}::{}{}", - addr, - module_ident.module.value(), - struct_name, - if ss.is_empty() { - "".to_string() - } else { - format!("<{}>", type_list_to_ide_string(ss)) - } - ) - }, - }, - Type_::Anything => "_".to_string(), - Type_::Var(_) => "invalid type (var)".to_string(), - Type_::UnresolvedError => "invalid type (unresolved)".to_string(), - } -} - -fn addr_to_ide_string(addr: &Address) -> String { - match addr { - Address::Numerical(None, sp!(_, bytes)) => format!("{}", bytes), - Address::Numerical(Some(name), _) => format!("{}", name), - Address::NamedUnassigned(name) => format!("{}", name), - } -} - -fn type_list_to_ide_string(types: &[Type]) -> String { - types - .iter() - .map(type_to_ide_string) - .collect::>() - .join(", ") -} - -impl SymbolicatorRunner { - /// Create a new idle runner (one that does not actually symbolicate) - pub fn idle() -> Self { - let mtx_cvar = Arc::new((Mutex::new(RunnerState::Wait), Condvar::new())); - SymbolicatorRunner { mtx_cvar } - } - - /// Create a new runner - pub fn new( - symbols: Arc>, - sender: Sender>>>, - ) -> Self { - let mtx_cvar = Arc::new((Mutex::new(RunnerState::Wait), Condvar::new())); - let thread_mtx_cvar = mtx_cvar.clone(); - let runner = SymbolicatorRunner { mtx_cvar }; - - thread::Builder::new() - .stack_size(STACK_SIZE_BYTES) - .spawn(move || { - let (mtx, cvar) = &*thread_mtx_cvar; - // Locations opened in the IDE (files or directories) for which manifest file is missing - let mut missing_manifests = BTreeSet::new(); - // infinite loop to wait for symbolication requests - eprintln!("starting symbolicator runner loop"); - loop { - let starting_path_opt = { - // hold the lock only as long as it takes to get the data, rather than through - // the whole symbolication process (hence a separate scope here) - let mut symbolicate = mtx.lock().unwrap(); - match symbolicate.clone() { - RunnerState::Quit => break, - RunnerState::Run(root_dir) => { - *symbolicate = RunnerState::Wait; - Some(root_dir) - }, - RunnerState::Wait => { - // wait for next request - symbolicate = cvar.wait(symbolicate).unwrap(); - match symbolicate.clone() { - RunnerState::Quit => break, - RunnerState::Run(root_dir) => { - *symbolicate = RunnerState::Wait; - Some(root_dir) - }, - RunnerState::Wait => None, - } - }, - } - }; - if let Some(starting_path) = starting_path_opt { - let root_dir = Self::root_dir(&starting_path); - if root_dir.is_none() && !missing_manifests.contains(&starting_path) { - eprintln!("reporting missing manifest"); - - // report missing manifest file only once to avoid cluttering IDE's UI in - // cases when developer indeed intended to open a standalone file that was - // not meant to compile - missing_manifests.insert(starting_path); - if let Err(err) = sender.send(Err(anyhow!( - "Unable to find package manifest. Make sure that - the source files are located in a sub-directory of a package containing - a Move.toml file. " - ))) { - eprintln!("could not pass missing manifest error: {:?}", err); - } - continue; - } - eprintln!("symbolication started"); - match Symbolicator::get_symbols(root_dir.unwrap().as_path()) { - Ok((symbols_opt, lsp_diagnostics)) => { - eprintln!("symbolication finished"); - if let Some(new_symbols) = symbols_opt { - // merge the new symbols with the old ones to support a - // (potentially) new project/package that symbolication information - // was built for - // - // TODO: we may consider "unloading" symbolication information when - // files/directories are being closed but as with other performance - // optimizations (e.g. incrementalizatino of the vfs), let's wait - // until we know we actually need it - let mut old_symbols = symbols.lock().unwrap(); - (*old_symbols).merge(new_symbols); - } - // set/reset (previous) diagnostics - if let Err(err) = sender.send(Ok(lsp_diagnostics)) { - eprintln!("could not pass diagnostics: {:?}", err); - } - }, - Err(err) => { - eprintln!("symbolication failed: {:?}", err); - if let Err(err) = sender.send(Err(err)) { - eprintln!("could not pass compiler error: {:?}", err); - } - }, - } - } - } - }) - .unwrap(); - - runner - } - - pub fn run(&self, starting_path: PathBuf) { - eprintln!("scheduling run for {:?}", starting_path); - let (mtx, cvar) = &*self.mtx_cvar; - let mut symbolicate = mtx.lock().unwrap(); - *symbolicate = RunnerState::Run(starting_path); - cvar.notify_one(); - eprintln!("scheduled run"); - } - - pub fn quit(&self) { - let (mtx, cvar) = &*self.mtx_cvar; - let mut symbolicate = mtx.lock().unwrap(); - *symbolicate = RunnerState::Quit; - cvar.notify_one(); - } - - /// Finds manifest file in a (sub)directory of the starting path passed as argument - pub fn root_dir(starting_path: &Path) -> Option { - let mut current_path_opt = Some(starting_path); - while current_path_opt.is_some() { - let current_path = current_path_opt.unwrap(); - let manifest_path = current_path.join("Move.toml"); - if manifest_path.is_file() { - return Some(current_path.to_path_buf()); - } - current_path_opt = current_path.parent(); - } - None - } -} - -impl UseDef { - fn new( - references: &mut BTreeMap>, - use_fhash: FileHash, - use_start: Position, - def_fhash: FileHash, - def_start: Position, - use_name: &Symbol, - use_type: IdentType, - type_def_loc: Option, - doc_string: String, - ) -> Self { - let def_loc = DefLoc { - fhash: def_fhash, - start: def_start, - }; - let col_end = use_start.character + use_name.len() as u32; - let use_loc = UseLoc { - fhash: use_fhash, - start: use_start, - col_end, - }; - - references.entry(def_loc).or_default().insert(use_loc); - Self { - col_start: use_start.character, - col_end, - use_type, - def_loc, - type_def_loc, - doc_string, - } - } -} - -impl Ord for UseDef { - fn cmp(&self, other: &Self) -> cmp::Ordering { - self.col_start.cmp(&other.col_start) - } -} - -impl PartialOrd for UseDef { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for UseDef { - fn eq(&self, other: &Self) -> bool { - self.col_start == other.col_start - } -} - -impl UseDefMap { - fn new() -> Self { - Self(BTreeMap::new()) - } - - fn insert(&mut self, key: u32, val: UseDef) { - self.0.entry(key).or_default().insert(val); - } - - fn get(&self, key: u32) -> Option> { - self.0.get(&key).cloned() - } - - fn elements(self) -> BTreeMap> { - self.0 - } - - fn extend(&mut self, use_defs: BTreeMap>) { - self.0.extend(use_defs); - } -} - -impl FunctionIdentTypeMap { - fn new() -> Self { - Self(BTreeMap::new()) - } - - fn insert(&mut self, key: String, val: IdentType) { - self.0.entry(key).or_insert_with(|| val); - } - - pub fn contains_key(self, key: &String) -> bool { - self.0.contains_key(key) - } -} - -impl Symbols { - pub fn merge(&mut self, other: Self) { - for (k, v) in other.references { - self.references.entry(k).or_default().extend(v); - } - self.file_use_defs.extend(other.file_use_defs); - self.file_name_mapping.extend(other.file_name_mapping); - self.file_mods.extend(other.file_mods); - } - - pub fn file_mods(&self) -> &BTreeMap> { - &self.file_mods - } -} - -impl Symbolicator { - /// Main driver to get symbols for the whole package. Returned symbols is an option as only the - /// correctly computed symbols should be a replacement for the old set - if symbols are not - /// actually (re)computed and the diagnostics are returned, the old symbolic information should - /// be retained even if it's getting out-of-date. - pub fn get_symbols( - pkg_path: &Path, - ) -> Result<(Option, BTreeMap>)> { - let build_config = move_package::BuildConfig { - test_mode: true, - install_dir: Some(tempdir().unwrap().path().to_path_buf()), - ..Default::default() - }; - - eprintln!("symbolicating {:?}", pkg_path); - - // resolution graph diagnostics are only needed for CLI commands so ignore them by passing a - // vector as the writer - let resolution_graph = - build_config.resolution_graph_for_package(pkg_path, &mut Vec::new())?; - - // get source files to be able to correlate positions (in terms of byte offsets) with actual - // file locations (in terms of line/column numbers) - let source_files = &resolution_graph.file_sources(); - let mut files = SimpleFiles::new(); - let mut file_id_mapping = HashMap::new(); - let mut file_id_to_lines = HashMap::new(); - let mut file_name_mapping = BTreeMap::new(); - for (fhash, (fname, source)) in source_files { - let id = files.add(*fname, source.clone()); - file_id_mapping.insert(*fhash, id); - file_name_mapping.insert(*fhash, *fname); - let lines: Vec = source.lines().map(String::from).collect(); - file_id_to_lines.insert(id, lines); - } - - let build_plan = BuildPlan::create(resolution_graph)?; - let mut typed_ast = None; - let mut diagnostics = None; - build_plan.compile_with_driver( - &mut std::io::sink(), - &CompilerConfig::default(), - |compiler| { - let (files, compilation_result) = compiler.run::()?; - let (_, compiler) = match compilation_result { - Ok(v) => v, - Err(diags) => { - let failure = true; - diagnostics = Some((diags, failure)); - eprintln!("typed AST compilation failed"); - return Ok((files, vec![], None)); - }, - }; - eprintln!("compiled to typed AST"); - let (compiler, typed_program) = compiler.into_ast(); - typed_ast = Some(typed_program.clone()); - eprintln!("compiling to bytecode"); - let compilation_result = compiler.at_typing(typed_program).build(); - let (units, diags) = match compilation_result { - Ok(v) => v, - Err(diags) => { - let failure = false; - diagnostics = Some((diags, failure)); - eprintln!("bytecode compilation failed"); - return Ok((files, vec![], None)); - }, - }; - // warning diagnostics (if any) since compilation succeeded - if !diags.is_empty() { - // assign only if non-empty, otherwise return None to reset previous diagnostics - let failure = false; - diagnostics = Some((diags, failure)); - } - eprintln!("compiled to bytecode"); - Ok((files, units, None)) - }, - unimplemented_v2_driver, - )?; - - let mut ide_diagnostics = lsp_empty_diagnostics(&file_name_mapping); - if let Some((compiler_diagnostics, failure)) = diagnostics { - let lsp_diagnostics = lsp_diagnostics( - &compiler_diagnostics.into_codespan_format(), - &files, - &file_id_mapping, - &file_name_mapping, - ); - // start with empty diagnostics for all files and replace them with actual diagnostics - // only for files that have failures/warnings so that diagnostics for all other files - // (that no longer have failures/warnings) are reset - ide_diagnostics.extend(lsp_diagnostics); - if failure { - // just return diagnostics as we don't have typed AST that we can use to compute - // symbolication information - debug_assert!(typed_ast.is_none()); - return Ok((None, ide_diagnostics)); - } - } - - let modules = &typed_ast.unwrap().modules; - - let mut mod_outer_defs = BTreeMap::new(); - let mut mod_use_defs = BTreeMap::new(); - let mut file_mods = BTreeMap::new(); - - for (pos, module_ident, module_def) in modules { - let (defs, symbols) = Self::get_mod_outer_defs( - &pos, - &sp(pos, *module_ident), - module_def, - &files, - &file_id_mapping, - ); - - let cloned_defs = defs.clone(); - let path = file_name_mapping.get(&cloned_defs.fhash.clone()).unwrap(); - file_mods - .entry( - dunce::canonicalize(path.as_str()) - .unwrap_or_else(|_| PathBuf::from(path.as_str())), - ) - .or_insert_with(BTreeSet::new) - .insert(cloned_defs); - - mod_outer_defs.insert(*module_ident, defs); - mod_use_defs.insert(*module_ident, symbols); - } - - eprintln!("get_symbols loaded file_mods length: {}", file_mods.len()); - - let mut symbolicator = Symbolicator { - mod_outer_defs, - files, - file_id_mapping, - file_id_to_lines, - type_params: BTreeMap::new(), - current_mod: None, - }; - - let mut references = BTreeMap::new(); - let mut file_use_defs = BTreeMap::new(); - let mut function_ident_type = FunctionIdentTypeMap::new(); - - for (pos, module_ident, module_def) in modules { - let mut use_defs = mod_use_defs.remove(module_ident).unwrap(); - symbolicator.current_mod = Some(sp(pos, *module_ident)); - symbolicator.mod_symbols( - module_def, - &mut references, - &mut use_defs, - &mut function_ident_type, - ); - - let fpath = match source_files.get(&pos.file_hash()) { - Some((p, _)) => p, - None => continue, - }; - - let fpath_buffer = dunce::canonicalize(fpath.as_str()) - .unwrap_or_else(|_| PathBuf::from(fpath.as_str())); - - file_use_defs - .entry(fpath_buffer) - .or_insert_with(UseDefMap::new) - .extend(use_defs.elements()); - } - - let symbols = Symbols { - references, - file_use_defs, - file_name_mapping, - file_mods, - }; - - eprintln!("get_symbols load complete"); - - Ok((Some(symbols), ide_diagnostics)) - } - - /// Get empty symbols - pub fn empty_symbols() -> Symbols { - Symbols { - file_use_defs: BTreeMap::new(), - references: BTreeMap::new(), - file_name_mapping: BTreeMap::new(), - file_mods: BTreeMap::new(), - } - } - - /// Main AST traversal functions - - /// Get symbols for outer definitions in the module (functions, structs, and consts) - fn get_mod_outer_defs( - loc: &Loc, - mod_ident: &ModuleIdent, - mod_def: &ModuleDefinition, - files: &SimpleFiles, - file_id_mapping: &HashMap, - ) -> (ModuleDefs, UseDefMap) { - let mut structs = BTreeMap::new(); - let mut constants = BTreeMap::new(); - let mut functions = BTreeMap::new(); - - for (pos, name, def) in &mod_def.structs { - // process field structs first - let mut field_defs = vec![]; - if let StructFields::Defined(fields) = &def.fields { - for (fpos, fname, (_, _)) in fields { - let start = match Self::get_start_loc(&fpos, files, file_id_mapping) { - Some(s) => s, - None => { - debug_assert!(false); - continue; - }, - }; - field_defs.push(FieldDef { - name: *fname, - start, - }); - } - }; - - // process the struct itself - let name_start = match Self::get_start_loc(&pos, files, file_id_mapping) { - Some(s) => s, - None => { - debug_assert!(false); - continue; - }, - }; - - structs.insert(*name, StructDef { - name_start, - field_defs, - }); - } - - for (pos, name, _) in &mod_def.constants { - let name_start = match Self::get_start_loc(&pos, files, file_id_mapping) { - Some(s) => s, - None => { - debug_assert!(false); - continue; - }, - }; - constants.insert(*name, name_start); - } - - for (pos, name, fun) in &mod_def.functions { - let name_start = match Self::get_start_loc(&pos, files, file_id_mapping) { - Some(s) => s, - None => { - debug_assert!(false); - continue; - }, - }; - let ident_type = IdentType::FunctionType( - mod_ident.value, - *name, - fun.signature - .type_parameters - .iter() - .map(|t| sp(t.user_specified_name.loc, Type_::Param(t.clone()))) - .collect(), - fun.signature - .parameters - .iter() - .map(|(n, _)| n.value()) - .collect(), - fun.signature - .parameters - .iter() - .map(|(_, t)| t.clone()) - .collect(), - fun.signature.return_type.clone(), - fun.acquires - .iter() - .map(|(k, v)| Self::create_struct_type(*mod_ident, *k, *v, vec![])) - .collect(), - ); - functions.insert(*name, FunctionDef { - name: *name, - start: name_start, - attrs: fun - .attributes - .clone() - .iter() - .map(|(_loc, name, _attr)| name.to_string()) - .collect(), - ident_type, - }); - } - - let use_def_map = UseDefMap::new(); - - let name = mod_ident.value; - let fhash = loc.file_hash(); - let start = match Self::get_start_loc(loc, files, file_id_mapping) { - Some(s) => s, - None => { - debug_assert!(false); - return ( - ModuleDefs { - fhash, - start: Position { - line: 0, - character: 0, - }, - name, - structs, - constants, - functions, - }, - use_def_map, - ); - }, - }; - - let module_defs = ModuleDefs { - name, - start, - fhash, - structs, - constants, - functions, - }; - - (module_defs, use_def_map) - } - - /// Get symbols for the whole module - fn mod_symbols( - &mut self, - mod_def: &ModuleDefinition, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - function_ident_type: &mut FunctionIdentTypeMap, - ) { - for (pos, name, fun) in &mod_def.functions { - // enter self-definition for function name (unwrap safe - done when inserting def) - let name_start = Self::get_start_loc(&pos, &self.files, &self.file_id_mapping).unwrap(); - let doc_string = self.extract_doc_string(&name_start, &pos.file_hash()); - - let mod_ident = self.current_mod.unwrap(); - - let mod_def = self.mod_outer_defs.get(&mod_ident.value).unwrap(); - let fun_def = mod_def.functions.get(name).unwrap(); - let use_type = fun_def.ident_type.clone(); - - let fun_type_def = self.ident_type_def_loc(&use_type); - let use_def = UseDef::new( - references, - pos.file_hash(), - name_start, - pos.file_hash(), - name_start, - name, - use_type.clone(), - fun_type_def, - doc_string, - ); - - use_defs.insert(name_start.line, use_def); - self.fun_symbols(fun, references, use_defs); - function_ident_type.insert(name.to_string(), use_type); - } - - for (pos, name, c) in &mod_def.constants { - // enter self-definition for const name (unwrap safe - done when inserting def) - let name_start = Self::get_start_loc(&pos, &self.files, &self.file_id_mapping).unwrap(); - let doc_string = self.extract_doc_string(&name_start, &pos.file_hash()); - let ident_type = IdentType::RegularType(c.signature.clone()); - let ident_type_def = self.ident_type_def_loc(&ident_type); - use_defs.insert( - name_start.line, - UseDef::new( - references, - pos.file_hash(), - name_start, - pos.file_hash(), - name_start, - name, - ident_type, - ident_type_def, - doc_string, - ), - ); - } - - for (pos, name, struct_def) in &mod_def.structs { - // enter self-definition for struct name (unwrap safe - done when inserting def) - let name_start = Self::get_start_loc(&pos, &self.files, &self.file_id_mapping).unwrap(); - let doc_string = self.extract_doc_string(&name_start, &pos.file_hash()); - let ident_type = IdentType::RegularType(Self::create_struct_type( - self.current_mod.unwrap(), - StructName(sp(pos, *name)), - pos, - vec![], - )); - let ident_type_def = self.ident_type_def_loc(&ident_type); - use_defs.insert( - name_start.line, - UseDef::new( - references, - pos.file_hash(), - name_start, - pos.file_hash(), - name_start, - name, - ident_type, - ident_type_def, - doc_string, - ), - ); - - self.struct_symbols(struct_def, references, use_defs); - } - } - - /// Get symbols for function a definition - fn struct_symbols( - &mut self, - struct_def: &StructDefinition, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - // create scope designated to contain type parameters (if any) - let mut tp_scope = BTreeMap::new(); - for stp in &struct_def.type_parameters { - self.add_type_param(&stp.param, &mut tp_scope, references, use_defs); - } - self.type_params = tp_scope; - if let StructFields::Defined(fields) = &struct_def.fields { - for (fpos, fname, (_, t)) in fields { - self.add_type_id_use_def(t, references, use_defs); - // enter self-definition for field name (unwrap safe - done when inserting def) - let start = Self::get_start_loc(&fpos, &self.files, &self.file_id_mapping).unwrap(); - let ident_type = IdentType::RegularType(t.clone()); - let ident_type_def = self.ident_type_def_loc(&ident_type); - let doc_string = self.extract_doc_string(&start, &fpos.file_hash()); - use_defs.insert( - start.line, - UseDef::new( - references, - fpos.file_hash(), - start, - fpos.file_hash(), - start, - fname, - ident_type, - ident_type_def, - doc_string, - ), - ); - } - } - } - - /// Get symbols for function a definition - fn fun_symbols( - &mut self, - fun: &Function, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - // create scope designated to contain type parameters (if any) - let mut tp_scope = BTreeMap::new(); - for tp in &fun.signature.type_parameters { - self.add_type_param(tp, &mut tp_scope, references, use_defs); - } - self.type_params = tp_scope; - - // scope for the main function scope (for parameters and - // function body) - let mut scope = OrdMap::new(); - - for (pname, ptype) in &fun.signature.parameters { - self.add_type_id_use_def(ptype, references, use_defs); - - // add definition of the parameter - self.add_def( - &pname.loc(), - &pname.value(), - &mut scope, - references, - use_defs, - ptype.clone(), - ); - } - - match &fun.body.value { - FunctionBody_::Defined(sequence) => { - for seq_item in sequence { - self.seq_item_symbols(&mut scope, seq_item, references, use_defs); - } - }, - FunctionBody_::Native => (), - } - - // process return types - self.add_type_id_use_def(&fun.signature.return_type, references, use_defs); - // process optional "acquires" clause - for (name, loc) in fun.acquires.clone() { - let typ = Self::create_struct_type(self.current_mod.unwrap(), name, loc, vec![]); - self.add_struct_use_def( - &self.current_mod.unwrap(), - &name.value(), - &name.loc(), - references, - use_defs, - &typ, - ); - } - - // clear type params from the scope - self.type_params.clear(); - } - - fn get_start_loc( - pos: &Loc, - files: &SimpleFiles, - file_id_mapping: &HashMap, - ) -> Option { - get_loc(&pos.file_hash(), pos.start(), files, file_id_mapping) - } - - /// Extracts the docstring (/// or /** ... */) for a given definition by traversing up from the line definition - fn extract_doc_string(&self, name_start: &Position, file_hash: &FileHash) -> String { - let mut doc_string = String::new(); - let file_id = match self.file_id_mapping.get(file_hash) { - None => return doc_string, - Some(v) => v, - }; - - let file_lines = match self.file_id_to_lines.get(file_id) { - None => return doc_string, - Some(v) => v, - }; - - if name_start.line == 0 { - return doc_string; - } - - let mut iter = (name_start.line - 1) as usize; - let mut line_before = file_lines[iter].trim(); - - // Detect the two different types of docstrings - if line_before.starts_with("///") { - while let Some(stripped_line) = line_before.strip_prefix("///") { - doc_string = format!("{}\n{}", stripped_line.trim(), doc_string); - if iter == 0 { - break; - } - iter -= 1; - line_before = file_lines[iter].trim(); - } - } else if line_before.ends_with("*/") { - let mut doc_string_found = false; - line_before = file_lines[iter].strip_suffix("*/").unwrap_or("").trim(); - - // Loop condition is a safe guard. - while !doc_string_found { - // We found the start of the multi-line comment/docstring - if line_before.starts_with("/*") { - let is_doc = line_before.starts_with("/**") && !line_before.starts_with("/***"); - - // Invalid doc_string start prefix so return empty doc string. - if !is_doc { - return String::new(); - } - - line_before = line_before.strip_prefix("/**").unwrap_or("").trim(); - doc_string_found = true; - } - - doc_string = format!("{}\n{}", line_before, doc_string); - - if iter == 0 { - break; - } - - iter -= 1; - line_before = file_lines[iter].trim(); - } - - // No doc_string found - return String::new(); - if !doc_string_found { - return String::new(); - } - } - - doc_string - } - - /// Get symbols for a sequence representing function body - fn seq_item_symbols( - &self, - scope: &mut OrdMap, - seq_item: &SequenceItem, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - use SequenceItem_ as I; - match &seq_item.value { - I::Seq(e) => self.exp_symbols(e, scope, references, use_defs), - I::Declare(lvalues) => { - self.lvalue_list_symbols(true, lvalues, scope, references, use_defs) - }, - I::Bind(lvalues, opt_types, e) => { - // process RHS first to avoid accidentally binding its identifiers to LHS (which now - // will be put into the current scope only after RHS is processed) - self.exp_symbols(e, scope, references, use_defs); - for opt_t in opt_types { - match opt_t { - Some(t) => self.add_type_id_use_def(t, references, use_defs), - None => (), - } - } - self.lvalue_list_symbols(true, lvalues, scope, references, use_defs); - }, - } - } - - /// Get symbols for a list of lvalues - fn lvalue_list_symbols( - &self, - define: bool, - lvalues: &LValueList, - scope: &mut OrdMap, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - for lval in &lvalues.value { - self.lvalue_symbols(define, lval, scope, references, use_defs); - } - } - - /// Get symbols for a single lvalue - fn lvalue_symbols( - &self, - define: bool, - lval: &LValue, - scope: &mut OrdMap, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - match &lval.value { - LValue_::Var(var, t) => { - if define { - self.add_def( - &var.loc(), - &var.value(), - scope, - references, - use_defs, - *t.clone(), - ); - } else { - self.add_local_use_def( - &var.value(), - &var.loc(), - references, - scope, - use_defs, - *t.clone(), - ) - } - }, - LValue_::Unpack(ident, name, tparams, fields) => { - self.unpack_symbols( - define, ident, name, tparams, fields, scope, references, use_defs, - ); - }, - LValue_::BorrowUnpack(_, ident, name, tparams, fields) => { - self.unpack_symbols( - define, ident, name, tparams, fields, scope, references, use_defs, - ); - }, - LValue_::Ignore => (), - } - } - - /// Get symbols for the unpack statement - fn unpack_symbols( - &self, - define: bool, - ident: &ModuleIdent, - name: &StructName, - tparams: &Vec, - fields: &Fields<(Type, LValue)>, - scope: &mut OrdMap, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - // add use of the struct name - let typ = Self::create_struct_type(*ident, *name, name.loc(), tparams.clone()); - self.add_struct_use_def( - ident, - &name.value(), - &name.loc(), - references, - use_defs, - &typ, - ); - for (fpos, fname, (_, (t, lvalue))) in fields { - // add use of the field name - self.add_field_use_def( - &ident.value, - &name.value(), - fname, - &fpos, - references, - use_defs, - t, - ); - // add definition or use of a variable used for struct field unpacking - self.lvalue_symbols(define, lvalue, scope, references, use_defs); - } - // add type params - for t in tparams { - self.add_type_id_use_def(t, references, use_defs); - } - } - - /// Get symbols for an expression - fn exp_symbols( - &self, - exp: &Exp, - scope: &mut OrdMap, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - use UnannotatedExp_ as E; - match &exp.exp.value { - E::Move { - from_user: _, - var: v, - } => self.add_local_use_def( - &v.value(), - &v.loc(), - references, - scope, - use_defs, - exp.ty.clone(), - ), - E::Copy { - from_user: _, - var: v, - } => self.add_local_use_def( - &v.value(), - &v.loc(), - references, - scope, - use_defs, - exp.ty.clone(), - ), - E::Use(v) => self.add_local_use_def( - &v.value(), - &v.loc(), - references, - scope, - use_defs, - exp.ty.clone(), - ), - E::Constant(mod_ident_opt, name) => self.add_const_use_def( - mod_ident_opt, - &name.value(), - &name.loc(), - references, - use_defs, - exp.ty.clone(), - ), - E::ModuleCall(mod_call) => self.mod_call_symbols(mod_call, scope, references, use_defs), - E::Builtin(builtin_fun, exp) => { - use BuiltinFunction_ as BF; - match &builtin_fun.value { - BF::MoveTo(t) => self.add_type_id_use_def(t, references, use_defs), - BF::MoveFrom(t) => self.add_type_id_use_def(t, references, use_defs), - BF::BorrowGlobal(_, t) => self.add_type_id_use_def(t, references, use_defs), - BF::Exists(t) => self.add_type_id_use_def(t, references, use_defs), - BF::Freeze(t) => self.add_type_id_use_def(t, references, use_defs), - _ => (), - } - self.exp_symbols(exp, scope, references, use_defs); - }, - E::Vector(_, _, t, exp) => { - self.add_type_id_use_def(t, references, use_defs); - self.exp_symbols(exp, scope, references, use_defs); - }, - E::IfElse(cond, t, f) => { - self.exp_symbols(cond, scope, references, use_defs); - self.exp_symbols(t, scope, references, use_defs); - self.exp_symbols(f, scope, references, use_defs); - }, - E::While(cond, body) => { - self.exp_symbols(cond, scope, references, use_defs); - self.exp_symbols(body, scope, references, use_defs); - }, - E::Loop { has_break: _, body } => { - self.exp_symbols(body, scope, references, use_defs); - }, - E::Block(sequence) => { - // a block is a new var scope - let mut new_scope = scope.clone(); - for seq_item in sequence { - self.seq_item_symbols(&mut new_scope, seq_item, references, use_defs); - } - }, - E::Assign(lvalues, opt_types, e) => { - self.lvalue_list_symbols(false, lvalues, scope, references, use_defs); - for opt_t in opt_types { - match opt_t { - Some(t) => self.add_type_id_use_def(t, references, use_defs), - None => (), - } - } - self.exp_symbols(e, scope, references, use_defs); - }, - E::Mutate(lhs, rhs) => { - self.exp_symbols(lhs, scope, references, use_defs); - self.exp_symbols(rhs, scope, references, use_defs); - }, - E::Return(exp) => { - self.exp_symbols(exp, scope, references, use_defs); - }, - E::Abort(exp) => { - self.exp_symbols(exp, scope, references, use_defs); - }, - E::Dereference(exp) => { - self.exp_symbols(exp, scope, references, use_defs); - }, - E::UnaryExp(_, exp) => { - self.exp_symbols(exp, scope, references, use_defs); - }, - E::BinopExp(lhs, _, _, rhs) => { - self.exp_symbols(lhs, scope, references, use_defs); - self.exp_symbols(rhs, scope, references, use_defs); - }, - E::Pack(ident, name, tparams, fields) => { - self.pack_symbols(ident, name, tparams, fields, scope, references, use_defs); - }, - E::ExpList(list_items) => { - for item in list_items { - let exp = match item { - // TODO: are types important for symbolication here (and, more generally, - // what's a splat?) - ExpListItem::Single(e, _) => e, - ExpListItem::Splat(_, e, _) => e, - }; - self.exp_symbols(exp, scope, references, use_defs); - } - }, - E::Borrow(_, exp, field) => { - self.exp_symbols(exp, scope, references, use_defs); - // get expression type to match fname to a struct def - self.add_field_type_use_def( - &exp.ty, - &field.value(), - &field.loc(), - references, - use_defs, - ); - }, - E::TempBorrow(_, exp) => { - self.exp_symbols(exp, scope, references, use_defs); - }, - E::BorrowLocal(_, var) => self.add_local_use_def( - &var.value(), - &var.loc(), - references, - scope, - use_defs, - exp.ty.clone(), - ), - E::Cast(exp, t) => { - self.exp_symbols(exp, scope, references, use_defs); - self.add_type_id_use_def(t, references, use_defs); - }, - E::Annotate(exp, t) => { - self.exp_symbols(exp, scope, references, use_defs); - self.add_type_id_use_def(t, references, use_defs); - }, - - _ => (), - } - } - - /// Add a type for a struct field given its type - fn add_field_type_use_def( - &self, - field_type: &Type, - use_name: &Symbol, - use_pos: &Loc, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - let sp!(_, typ) = field_type; - match typ { - Type_::Ref(_, t) => { - self.add_field_type_use_def(t, use_name, use_pos, references, use_defs) - }, - Type_::Apply(_, sp!(_, TypeName_::ModuleType(sp!(_, mod_ident), struct_name)), _) => { - self.add_field_use_def( - mod_ident, - &struct_name.value(), - use_name, - use_pos, - references, - use_defs, - field_type, - ); - }, - _ => (), - } - } - - fn mod_call_symbols( - &self, - mod_call: &ModuleCall, - scope: &mut OrdMap, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - let mod_ident = mod_call.module; - let mod_def = self.mod_outer_defs.get(&mod_ident.value).unwrap(); - - let fun_def = match mod_def.functions.get(&mod_call.name.value()) { - Some(v) => v, - None => return, - }; - let use_type = fun_def.ident_type.clone(); - - self.add_fun_use_def( - &mod_call.module, - &mod_call.name.value(), - &mod_call.name.loc(), - references, - use_defs, - use_type, - ); - - // handle type parameters - for t in &mod_call.type_arguments { - self.add_type_id_use_def(t, references, use_defs); - } - - // handle arguments - self.exp_symbols(&mod_call.arguments, scope, references, use_defs); - } - - /// Get symbols for the pack expression - fn pack_symbols( - &self, - ident: &ModuleIdent, - name: &StructName, - tparams: &Vec, - fields: &Fields<(Type, Exp)>, - scope: &mut OrdMap, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - // add use of the struct name - let typ = Self::create_struct_type(*ident, *name, name.loc(), tparams.clone()); - self.add_struct_use_def( - ident, - &name.value(), - &name.loc(), - references, - use_defs, - &typ, - ); - for (fpos, fname, (_, (t, init_exp))) in fields { - // add use of the field name - self.add_field_use_def( - &ident.value, - &name.value(), - fname, - &fpos, - references, - use_defs, - t, - ); - // add field initialization expression - self.exp_symbols(init_exp, scope, references, use_defs); - } - // add type params - for t in tparams { - self.add_type_id_use_def(t, references, use_defs); - } - } - - /// Helper functions - - /// Add type parameter to a scope holding type params - fn add_type_param( - &mut self, - tp: &TParam, - tp_scope: &mut BTreeMap, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - match Self::get_start_loc( - &tp.user_specified_name.loc, - &self.files, - &self.file_id_mapping, - ) { - Some(start) => { - let tname = tp.user_specified_name.value; - let fhash = tp.user_specified_name.loc.file_hash(); - // enter self-definition for type param - let ident_type = IdentType::RegularType(sp( - tp.user_specified_name.loc, - Type_::Param(tp.clone()), - )); - let ident_type_def = self.ident_type_def_loc(&ident_type); - - let doc_string = self.extract_doc_string(&start, &fhash); - use_defs.insert( - start.line, - UseDef::new( - references, - fhash, - start, - fhash, - start, - &tname, - ident_type, - ident_type_def, - doc_string, - ), - ); - let exists = tp_scope.insert(tname, DefLoc { fhash, start }); - debug_assert!(exists.is_none()); - }, - None => { - debug_assert!(false); - }, - }; - } - - /// Add use of one of identifiers defined at the module level - fn add_outer_use_def( - &self, - module_ident: &ModuleIdent_, - use_name: &Symbol, - use_pos: &Loc, - mut add_fn: impl FnMut(&Symbol, Position, &ModuleDefs), - ) { - let name_start = match Self::get_start_loc(use_pos, &self.files, &self.file_id_mapping) { - Some(v) => v, - None => { - debug_assert!(false); - return; - }, - }; - - let mod_defs = match self.mod_outer_defs.get(module_ident) { - Some(v) => v, - None => { - debug_assert!(false); - return; - }, - }; - add_fn(use_name, name_start, mod_defs); - } - - /// Add use of a const identifier - fn add_const_use_def( - &self, - module_ident_opt: &Option, - use_name: &Symbol, - use_pos: &Loc, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - use_type: Type, - ) { - let module_ident = match module_ident_opt { - Some(v) => v.value, - None => self.current_mod.unwrap().value, - }; - - self.add_outer_use_def( - &module_ident, - use_name, - use_pos, - |use_name, name_start, mod_defs| match mod_defs.constants.get(use_name) { - Some(def_start) => { - let ident_type = IdentType::RegularType(use_type.clone()); - let def_fhash = self.mod_outer_defs.get(&module_ident).unwrap().fhash; - let doc_string = self.extract_doc_string(def_start, &def_fhash); - let ident_type_def = self.ident_type_def_loc(&ident_type); - - use_defs.insert( - name_start.line, - UseDef::new( - references, - use_pos.file_hash(), - name_start, - def_fhash, - *def_start, - use_name, - ident_type, - ident_type_def, - doc_string, - ), - ); - }, - None => debug_assert!(false), - }, - ); - } - - /// Add use of a function identifier - fn add_fun_use_def( - &self, - module_ident: &ModuleIdent, - use_name: &Symbol, - use_pos: &Loc, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - use_type: IdentType, - ) { - self.add_outer_use_def( - &module_ident.value, - use_name, - use_pos, - |use_name, name_start, mod_defs| match mod_defs.functions.get(use_name) { - Some(func_def) => { - let def_fhash = self.mod_outer_defs.get(&module_ident.value).unwrap().fhash; - let doc_string = self.extract_doc_string(&func_def.start, &def_fhash); - use_defs.insert( - name_start.line, - UseDef::new( - references, - use_pos.file_hash(), - name_start, - def_fhash, - func_def.start, - use_name, - use_type.clone(), - self.ident_type_def_loc(&use_type), - doc_string, - ), - ); - }, - None => debug_assert!(false), - }, - ); - } - - /// Add use of a struct identifier - fn add_struct_use_def( - &self, - sp!(_, module_ident): &ModuleIdent, - use_name: &Symbol, - use_pos: &Loc, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - use_type: &Type, - ) { - self.add_outer_use_def( - module_ident, - use_name, - use_pos, - |use_name, name_start, mod_defs| match mod_defs.structs.get(use_name) { - Some(def) => { - let ident_type = IdentType::RegularType(use_type.clone()); - - let ident_type_def = self.ident_type_def_loc(&ident_type); - let def_fhash = self.mod_outer_defs.get(module_ident).unwrap().fhash; - let doc_string = self.extract_doc_string(&def.name_start, &def_fhash); - use_defs.insert( - name_start.line, - UseDef::new( - references, - use_pos.file_hash(), - name_start, - def_fhash, - def.name_start, - use_name, - ident_type, - ident_type_def, - doc_string, - ), - ); - }, - None => debug_assert!(false), - }, - ); - } - - /// Add use of a struct field identifier - fn add_field_use_def( - &self, - module_ident: &ModuleIdent_, - struct_name: &Symbol, - use_name: &Symbol, - use_pos: &Loc, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - use_type: &Type, - ) { - self.add_outer_use_def( - module_ident, - use_name, - use_pos, - |use_name, name_start, mod_defs| match mod_defs.structs.get(struct_name) { - Some(def) => { - for fdef in &def.field_defs { - if fdef.name == *use_name { - let ident_type = IdentType::RegularType(use_type.clone()); - let ident_type_def = self.ident_type_def_loc(&ident_type); - - let def_fhash = self.mod_outer_defs.get(module_ident).unwrap().fhash; - let doc_string = self.extract_doc_string(&fdef.start, &def_fhash); - use_defs.insert( - name_start.line, - UseDef::new( - references, - use_pos.file_hash(), - name_start, - def_fhash, - fdef.start, - use_name, - ident_type, - ident_type_def, - doc_string, - ), - ); - } - } - }, - None => debug_assert!(false), - }, - ); - } - - /// Add use of a type identifier - fn add_type_id_use_def( - &self, - id_type: &Type, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - ) { - let sp!(pos, typ) = id_type; - match typ { - Type_::Ref(_, t) => self.add_type_id_use_def(t, references, use_defs), - Type_::Param(tparam) => { - let sp!(use_pos, use_name) = tparam.user_specified_name; - match Self::get_start_loc(pos, &self.files, &self.file_id_mapping) { - Some(name_start) => match self.type_params.get(&use_name) { - Some(def_loc) => { - let ident_type = IdentType::RegularType(id_type.clone()); - let ident_type_def = self.ident_type_def_loc(&ident_type); - let doc_string = - self.extract_doc_string(&def_loc.start, &def_loc.fhash); - use_defs.insert( - name_start.line, - UseDef::new( - references, - use_pos.file_hash(), - name_start, - def_loc.fhash, - def_loc.start, - &use_name, - ident_type, - ident_type_def, - doc_string, - ), - ); - }, - None => debug_assert!(false), - }, - None => debug_assert!(false), // a type param should not be missing - } - }, - Type_::Apply(_, sp!(_, type_name), tparams) => { - if let TypeName_::ModuleType(mod_ident, struct_name) = type_name { - self.add_struct_use_def( - mod_ident, - &struct_name.value(), - &struct_name.loc(), - references, - use_defs, - id_type, - ); - } // otherwise nothing to be done for other type names - for t in tparams { - self.add_type_id_use_def(t, references, use_defs); - } - }, - _ => (), // nothing to be done for the other types - } - } - - /// Add a "generic" definition - fn add_def( - &self, - pos: &Loc, - name: &Symbol, - scope: &mut OrdMap, - references: &mut BTreeMap>, - use_defs: &mut UseDefMap, - use_type: Type, - ) { - match Self::get_start_loc(pos, &self.files, &self.file_id_mapping) { - Some(name_start) => { - let def_loc = DefLoc { - fhash: pos.file_hash(), - start: name_start, - }; - scope.insert(*name, def_loc); - // in other languages only one definition is allowed per scope but in move an (and - // in rust) a variable can be re-defined in the same scope replacing the previous - // definition - - let doc_string = self.extract_doc_string(&name_start, &pos.file_hash()); - - // enter self-definition for def name - let ident_type = IdentType::RegularType(use_type); - let ident_type_def = self.ident_type_def_loc(&ident_type); - use_defs.insert( - name_start.line, - UseDef::new( - references, - pos.file_hash(), - name_start, - pos.file_hash(), - name_start, - name, - ident_type, - ident_type_def, - doc_string, - ), - ); - }, - None => { - debug_assert!(false); - }, - } - } - - /// Add a use for and identifier whose definition is expected to be local to a function, and - /// pair it with an appropriate definition - fn add_local_use_def( - &self, - use_name: &Symbol, - use_pos: &Loc, - references: &mut BTreeMap>, - scope: &OrdMap, - use_defs: &mut UseDefMap, - use_type: Type, - ) { - let name_start = match Self::get_start_loc(use_pos, &self.files, &self.file_id_mapping) { - Some(v) => v, - None => { - debug_assert!(false); - return; - }, - }; - - if let Some(def_loc) = scope.get(use_name) { - let doc_string = self.extract_doc_string(&def_loc.start, &def_loc.fhash); - let ident_type = IdentType::RegularType(use_type); - let ident_type_def = self.ident_type_def_loc(&ident_type); - use_defs.insert( - name_start.line, - UseDef::new( - references, - use_pos.file_hash(), - name_start, - def_loc.fhash, - def_loc.start, - use_name, - ident_type, - ident_type_def, - doc_string, - ), - ); - } else { - debug_assert!(false); - } - } - - fn create_struct_type( - module_ident: ModuleIdent, - struct_name: StructName, - loc: Loc, - types: Vec, - ) -> Type { - let type_name = sp( - module_ident.loc, - TypeName_::ModuleType(module_ident, struct_name), - ); - sp(loc, Type_::Apply(None, type_name, types)) - } - - fn ident_type_def_loc(&self, ident_type: &IdentType) -> Option { - match ident_type { - IdentType::RegularType(t) => self.type_def_loc(t), - IdentType::FunctionType(_, _, _, _, _, ret, _) => self.type_def_loc(ret), - } - } - - fn type_def_loc(&self, sp!(_, t): &Type) -> Option { - match t { - Type_::Ref(_, r) => self.type_def_loc(r), - Type_::Apply(_, sp!(_, TypeName_::ModuleType(sp!(_, mod_ident), struct_name)), _) => { - let mod_defs = match self.mod_outer_defs.get(mod_ident) { - Some(v) => v, - None => return None, - }; - mod_defs - .structs - .get(&struct_name.value()) - .map(|struct_def| { - let fhash = mod_defs.fhash; - let start = struct_def.name_start; - DefLoc { fhash, start } - }) - }, - _ => None, - } - } -} - -/// Handles go-to-def request of the language server -pub fn on_go_to_def_request(context: &Context, request: &Request, symbols: &Symbols) { - let parameters = serde_json::from_value::(request.params.clone()) - .expect("could not deserialize go-to-def request"); - - let fpath = parameters - .text_document_position_params - .text_document - .uri - .to_file_path() - .unwrap(); - let loc = parameters.text_document_position_params.position; - let line = loc.line; - let col = loc.character; - - on_use_request( - context, - symbols, - &fpath, - line, - col, - request.id.clone(), - |u| { - // TODO: Do we need beginning and end of the definition? Does not seem to make a - // difference from the IDE perspective as the cursor goes to the beginning anyway (at - // least in VSCode). - let range = Range { - start: u.def_loc.start, - end: u.def_loc.start, - }; - let path = symbols.file_name_mapping.get(&u.def_loc.fhash).unwrap(); - let loc = Location { - uri: Url::from_file_path(path.as_str()).unwrap(), - range, - }; - Some(serde_json::to_value(loc).unwrap()) - }, - ); -} - -/// Handles go-to-type-def request of the language server -pub fn on_go_to_type_def_request(context: &Context, request: &Request, symbols: &Symbols) { - let parameters = serde_json::from_value::(request.params.clone()) - .expect("could not deserialize go-to-type-def request"); - - let fpath = parameters - .text_document_position_params - .text_document - .uri - .to_file_path() - .unwrap(); - let loc = parameters.text_document_position_params.position; - let line = loc.line; - let col = loc.character; - - on_use_request( - context, - symbols, - &fpath, - line, - col, - request.id.clone(), - |u| match u.type_def_loc { - Some(def_loc) => { - let range = Range { - start: def_loc.start, - end: def_loc.start, - }; - let path = symbols.file_name_mapping.get(&u.def_loc.fhash).unwrap(); - let loc = Location { - uri: Url::from_file_path(path.as_str()).unwrap(), - range, - }; - Some(serde_json::to_value(loc).unwrap()) - }, - None => Some(serde_json::to_value(Option::::None).unwrap()), - }, - ); -} - -/// Handles go-to-references request of the language server -pub fn on_references_request(context: &Context, request: &Request, symbols: &Symbols) { - let parameters = serde_json::from_value::(request.params.clone()) - .expect("could not deserialize references request"); - - let fpath = parameters - .text_document_position - .text_document - .uri - .to_file_path() - .unwrap(); - let loc = parameters.text_document_position.position; - let line = loc.line; - let col = loc.character; - let include_decl = parameters.context.include_declaration; - - on_use_request( - context, - symbols, - &fpath, - line, - col, - request.id.clone(), - |u| match symbols.references.get(&u.def_loc) { - Some(s) => { - let mut locs = vec![]; - for ref_loc in s { - if include_decl - || !(u.def_loc.start == ref_loc.start && u.def_loc.fhash == ref_loc.fhash) - { - let end_pos = Position { - line: ref_loc.start.line, - character: ref_loc.col_end, - }; - let range = Range { - start: ref_loc.start, - end: end_pos, - }; - let path = symbols.file_name_mapping.get(&ref_loc.fhash).unwrap(); - locs.push(Location { - uri: Url::from_file_path(path.as_str()).unwrap(), - range, - }); - } - } - if locs.is_empty() { - Some(serde_json::to_value(Option::::None).unwrap()) - } else { - Some(serde_json::to_value(locs).unwrap()) - } - }, - None => Some(serde_json::to_value(Option::::None).unwrap()), - }, - ); -} - -/// Handles hover request of the language server -pub fn on_hover_request(context: &Context, request: &Request, symbols: &Symbols) { - let parameters = serde_json::from_value::(request.params.clone()) - .expect("could not deserialize hover request"); - - let fpath = parameters - .text_document_position_params - .text_document - .uri - .to_file_path() - .unwrap(); - let loc = parameters.text_document_position_params.position; - let line = loc.line; - let col = loc.character; - - on_use_request( - context, - symbols, - &fpath, - line, - col, - request.id.clone(), - |u| { - let lang_string = LanguageString { - language: "".to_string(), - value: if !u.doc_string.is_empty() { - format!("{}\n\n{}", u.use_type, u.doc_string) - } else { - format!("{}", u.use_type) - }, - }; - let contents = HoverContents::Scalar(MarkedString::LanguageString(lang_string)); - let range = None; - Some(serde_json::to_value(Hover { contents, range }).unwrap()) - }, - ); -} - -/// Helper function to handle language server queries related to identifier uses -pub fn on_use_request( - context: &Context, - symbols: &Symbols, - use_fpath: &PathBuf, - use_line: u32, - use_col: u32, - id: RequestId, - use_def_action: impl Fn(&UseDef) -> Option, -) { - let mut result = None; - - let mut use_def_found = false; - if let Some(mod_symbols) = symbols.file_use_defs.get(use_fpath) { - if let Some(uses) = mod_symbols.get(use_line) { - for u in uses { - if use_col >= u.col_start && use_col <= u.col_end { - result = use_def_action(&u); - use_def_found = true; - } - } - } - } - if !use_def_found { - result = Some(serde_json::to_value(Option::::None).unwrap()); - } - - eprintln!("about to send use response"); - // unwrap will succeed based on the logic above which the compiler is unable to figure out - // without using Option - let response = lsp_server::Response::new_ok(id, result.unwrap()); - if let Err(err) = context - .connection - .sender - .send(lsp_server::Message::Response(response)) - { - eprintln!("could not send use response: {:?}", err); - } -} - -/// Handles document symbol request of the language server -#[allow(deprecated)] -pub fn on_document_symbol_request(context: &Context, request: &Request, symbols: &Symbols) { - let parameters = serde_json::from_value::(request.params.clone()) - .expect("could not deserialize document symbol request"); - - let fpath = parameters.text_document.uri.to_file_path().unwrap(); - eprintln!("on_document_symbol_request: {:?}", fpath); - - let empty_mods: BTreeSet = BTreeSet::new(); - let mods = symbols.file_mods.get(&fpath).unwrap_or(&empty_mods); - - let mut defs: Vec = vec![]; - for mod_def in mods { - let name = mod_def.name.module.clone().to_string(); - let detail = Some(mod_def.name.clone().to_string()); - let kind = SymbolKind::Module; - let range = Range { - start: mod_def.start, - end: mod_def.start, - }; - - let mut children = vec![]; - - // handle constants - let cloned_const_def = mod_def.constants.clone(); - for (sym, const_def_pos) in cloned_const_def { - let const_range = Range { - start: const_def_pos, - end: const_def_pos, - }; - - children.push(DocumentSymbol { - name: sym.clone().to_string(), - detail: None, - kind: SymbolKind::Constant, - range: const_range, - selection_range: const_range, - children: None, - tags: Some(vec![]), - deprecated: Some(false), - }); - } - - // handle structs - let cloned_struct_def = mod_def.structs.clone(); - for (sym, struct_def) in cloned_struct_def { - let struct_range = Range { - start: struct_def.name_start, - end: struct_def.name_start, - }; - - let mut fields: Vec = vec![]; - handle_struct_fields(struct_def, &mut fields); - - children.push(DocumentSymbol { - name: sym.clone().to_string(), - detail: None, - kind: SymbolKind::Struct, - range: struct_range, - selection_range: struct_range, - children: Some(fields), - tags: Some(vec![]), - deprecated: Some(false), - }); - } - - // handle functions - let cloned_func_def = mod_def.functions.clone(); - for (sym, func_def) in cloned_func_def { - let func_range = Range { - start: func_def.start, - end: func_def.start, - }; - - let mut detail = None; - if !func_def.attrs.is_empty() { - detail = Some(format!("{:?}", func_def.attrs)); - } - - children.push(DocumentSymbol { - name: sym.clone().to_string(), - detail, - kind: SymbolKind::Function, - range: func_range, - selection_range: func_range, - children: None, - tags: Some(vec![]), - deprecated: Some(false), - }); - } - - defs.push(DocumentSymbol { - name, - detail, - kind, - range, - selection_range: range, - children: Some(children), - tags: Some(vec![]), - deprecated: Some(false), - }); - } - - // unwrap will succeed based on the logic above which the compiler is unable to figure out - let response = lsp_server::Response::new_ok(request.id.clone(), defs); - if let Err(err) = context - .connection - .sender - .send(lsp_server::Message::Response(response)) - { - eprintln!("could not send use response: {:?}", err); - } -} - -/// Helper function to handle struct fields -#[allow(deprecated)] -fn handle_struct_fields(struct_def: StructDef, fields: &mut Vec) { - let clonded_fileds = struct_def.field_defs; - - for field_def in clonded_fileds { - let field_range = Range { - start: field_def.start, - end: field_def.start, - }; - - fields.push(DocumentSymbol { - name: field_def.name.clone().to_string(), - detail: None, - kind: SymbolKind::Field, - range: field_range, - selection_range: field_range, - children: None, - tags: Some(vec![]), - deprecated: Some(false), - }); - } -} - -#[cfg(test)] -fn assert_use_def_with_doc_string( - mod_symbols: &UseDefMap, - file_name_mapping: &BTreeMap, - use_idx: usize, - use_line: u32, - use_col: u32, - def_line: u32, - def_col: u32, - def_file: &str, - type_str: &str, - type_def: Option<(u32, u32, &str)>, - doc_string: &str, -) { - let uses = mod_symbols.get(use_line).unwrap(); - let use_def = uses.iter().nth(use_idx).unwrap(); - assert!(use_def.col_start == use_col); - assert!(use_def.def_loc.start.line == def_line); - assert!(use_def.def_loc.start.character == def_col); - assert!(file_name_mapping - .get(&use_def.def_loc.fhash) - .unwrap() - .as_str() - .ends_with(def_file)); - assert!(type_str == format!("{}", use_def.use_type)); - - assert!(doc_string == use_def.doc_string); - match use_def.type_def_loc { - Some(type_def_loc) => { - let tdef_line = type_def.unwrap().0; - let tdef_col = type_def.unwrap().1; - let tdef_file = type_def.unwrap().2; - assert!(type_def_loc.start.line == tdef_line); - assert!(type_def_loc.start.character == tdef_col); - assert!(file_name_mapping - .get(&type_def_loc.fhash) - .unwrap() - .as_str() - .ends_with(tdef_file)); - }, - None => assert!(type_def.is_none()), - } -} - -#[cfg(test)] -fn assert_use_def( - mod_symbols: &UseDefMap, - file_name_mapping: &BTreeMap, - use_idx: usize, - use_line: u32, - use_col: u32, - def_line: u32, - def_col: u32, - def_file: &str, - type_str: &str, - type_def: Option<(u32, u32, &str)>, -) { - assert_use_def_with_doc_string( - mod_symbols, - file_name_mapping, - use_idx, - use_line, - use_col, - def_line, - def_col, - def_file, - type_str, - type_def, - "", - ) -} - -#[test] -/// Tests if symbolication + doc_string information for documented Move constructs is constructed correctly. -fn docstring_test() { - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - - path.push("tests/symbols"); - - let (symbols_opt, _) = Symbolicator::get_symbols(path.as_path()).unwrap(); - let symbols = symbols_opt.unwrap(); - - let mut fpath = path.clone(); - fpath.push("sources/M6.move"); - let cpath = dunce::canonicalize(&fpath).unwrap(); - - let mod_symbols = symbols.file_use_defs.get(&cpath).unwrap(); - - // struct def name - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 0, - 4, - 11, - 4, - 11, - "M6.move", - "Symbols::M6::DocumentedStruct", - Some((4, 11, "M6.move")), - "This is a documented struct\nWith a multi-line docstring\n", - ); - - // const def name - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 0, - 10, - 10, - 10, - 10, - "M6.move", - "u64", - None, - "Constant containing the answer to the universe\n", - ); - - // function def name - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 0, - 14, - 8, - 14, - 8, - "M6.move", - "fun Symbols::M6::unpack(s: Symbols::M6::DocumentedStruct): u64", - None, - "A documented function that unpacks a DocumentedStruct\n", - ); - // param var (unpack function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 1, - 14, - 15, - 14, - 15, - "M6.move", - "Symbols::M6::DocumentedStruct", - Some((4, 11, "M6.move")), - "A documented function that unpacks a DocumentedStruct\n", - ); - // struct name in param type (unpack function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 2, - 14, - 18, - 4, - 11, - "M6.move", - "Symbols::M6::DocumentedStruct", - Some((4, 11, "M6.move")), - "This is a documented struct\nWith a multi-line docstring\n", - ); - // struct name in unpack (unpack function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 0, - 15, - 12, - 4, - 11, - "M6.move", - "Symbols::M6::DocumentedStruct", - Some((4, 11, "M6.move")), - "This is a documented struct\nWith a multi-line docstring\n", - ); - // field name in unpack (unpack function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 1, - 15, - 31, - 6, - 8, - "M6.move", - "u64", - None, - "A documented field\n", - ); - // moved var in unpack assignment (unpack function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 3, - 15, - 59, - 14, - 15, - "M6.move", - "Symbols::M6::DocumentedStruct", - Some((4, 11, "M6.move")), - "A documented function that unpacks a DocumentedStruct\n", - ); - - // docstring construction for multi-line /** .. */ based strings - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 0, - 26, - 8, - 26, - 8, - "M6.move", - "fun Symbols::M6::other_doc_struct(): Symbols::M7::OtherDocStruct", - Some((3, 11, "M7.move")), - "\nThis is a multiline docstring\n\nThis docstring has empty lines.\n\nIt uses the ** format instead of ///\n\n", - ); - - // docstring construction for single-line /** .. */ based strings - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 0, - 31, - 8, - 31, - 8, - "M6.move", - "fun Symbols::M6::acq(addr: address): u64 acquires Symbols::M6::DocumentedStruct", - None, - "Asterix based single-line docstring\n", - ); - - /* Test doc_string construction for struct/function imported from another module */ - - // other module struct name (other_doc_struct function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 1, - 26, - 41, - 3, - 11, - "M7.move", - "Symbols::M7::OtherDocStruct", - Some((3, 11, "M7.move")), - "Documented struct in another module\n", - ); - - // function name in a call (other_doc_struct function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 0, - 27, - 21, - 9, - 15, - "M7.move", - "fun Symbols::M7::create_other_struct(v: u64): Symbols::M7::OtherDocStruct", - Some((3, 11, "M7.move")), - "Documented initializer in another module\n", - ); - - // const in param (other_doc_struct function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 1, - 27, - 41, - 10, - 10, - "M6.move", - "u64", - None, - "Constant containing the answer to the universe\n", - ); - - // // other documented struct name imported (other_doc_struct_import function) - assert_use_def_with_doc_string( - mod_symbols, - &symbols.file_name_mapping, - 1, - 38, - 35, - 3, - 11, - "M7.move", - "Symbols::M7::OtherDocStruct", - Some((3, 11, "M7.move")), - "Documented struct in another module\n", - ); -} - -#[test] -/// Tests if symbolication information for specific Move constructs has been constructed correctly. -fn symbols_test() { - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - - path.push("tests/symbols"); - - let (symbols_opt, _) = Symbolicator::get_symbols(path.as_path()).unwrap(); - let symbols = symbols_opt.unwrap(); - - let mut fpath = path.clone(); - fpath.push("sources/M1.move"); - let cpath = dunce::canonicalize(&fpath).unwrap(); - - let mod_symbols = symbols.file_use_defs.get(&cpath).unwrap(); - - // struct def name - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 2, - 11, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // const def name - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 6, - 10, - 6, - 10, - "M1.move", - "u64", - None, - ); - // function def name - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 9, - 8, - 9, - 8, - "M1.move", - "fun Symbols::M1::unpack(s: Symbols::M1::SomeStruct): u64", - None, - ); - // param var (unpack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 9, - 15, - 9, - 15, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // struct name in param type (unpack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 9, - 18, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // struct name in unpack (unpack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 10, - 12, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // field name in unpack (unpack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 10, - 25, - 3, - 8, - "M1.move", - "u64", - None, - ); - // bound variable in unpack (unpack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 10, - 37, - 10, - 37, - "M1.move", - "u64", - None, - ); - // moved var in unpack assignment (unpack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 3, - 10, - 47, - 9, - 15, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // copied var in an assignment (cp function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 15, - 18, - 14, - 11, - "M1.move", - "u64", - None, - ); - // struct name return type (pack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 20, - 18, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // struct name in pack (pack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 20, - 18, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // field name in pack (pack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 20, - 31, - 3, - 8, - "M1.move", - "u64", - None, - ); - // const in pack (pack function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 3, - 20, - 43, - 6, - 10, - "M1.move", - "u64", - None, - ); - // other module struct name (other_mod_struct function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 24, - 41, - 2, - 11, - "M2.move", - "Symbols::M2::SomeOtherStruct", - Some((2, 11, "M2.move")), - ); - // function name in a call (other_mod_struct function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 25, - 21, - 6, - 15, - "M2.move", - "fun Symbols::M2::some_other_struct(v: u64): Symbols::M2::SomeOtherStruct", - Some((2, 11, "M2.move")), - ); - // const in param (other_mod_struct function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 25, - 39, - 6, - 10, - "M1.move", - "u64", - None, - ); - // other module struct name imported (other_mod_struct_import function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 30, - 35, - 2, - 11, - "M2.move", - "Symbols::M2::SomeOtherStruct", - Some((2, 11, "M2.move")), - ); - // function name (acq function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 34, - 8, - 34, - 8, - "M1.move", - "fun Symbols::M1::acq(addr: address): u64 acquires Symbols::M1::SomeStruct", - None, - ); - // struct name in acquires (acq function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 34, - 41, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // struct name in builtin type param (acq function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 35, - 32, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // param name in builtin (acq function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 35, - 44, - 34, - 12, - "M1.move", - "address", - None, - ); - // const in first param (multi_arg_call function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 40, - 22, - 6, - 10, - "M1.move", - "u64", - None, - ); - // const in second param (multi_arg_call function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 40, - 34, - 6, - 10, - "M1.move", - "u64", - None, - ); - // function name (vec function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 43, - 8, - 43, - 8, - "M1.move", - "fun Symbols::M1::vec(): vector", - None, - ); - // vector constructor type (vec function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 45, - 15, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // vector constructor first element struct type (vec function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 45, - 27, - 2, - 11, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // vector constructor first element struct field (vec function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 45, - 39, - 3, - 8, - "M1.move", - "u64", - None, - ); - // vector constructor second element var (vec function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 3, - 45, - 57, - 44, - 12, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // borrow local (mut function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 56, - 21, - 55, - 12, - "M1.move", - "&mut u64", - None, - ); - // LHS in mutation statement (mut function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 57, - 9, - 56, - 12, - "M1.move", - "&mut u64", - None, - ); - // RHS in mutation statement (mut function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 57, - 13, - 6, - 10, - "M1.move", - "u64", - None, - ); - // function name (ret function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 61, - 8, - 61, - 8, - "M1.move", - "fun Symbols::M1::ret(p1: bool, p2: u64): u64", - None, - ); - // returned value (ret function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 63, - 19, - 6, - 10, - "M1.move", - "u64", - None, - ); - // function name (abort_call function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 68, - 8, - 68, - 8, - "M1.move", - "fun Symbols::M1::abort_call()", - None, - ); - // abort value (abort_call function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 69, - 14, - 6, - 10, - "M1.move", - "u64", - None, - ); - // dereference (deref function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 75, - 9, - 74, - 12, - "M1.move", - "& u64", - None, - ); - // unary operator (unary function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 79, - 9, - 78, - 14, - "M1.move", - "bool", - None, - ); - // temp borrow (temp_borrow function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 83, - 19, - 6, - 10, - "M1.move", - "u64", - None, - ); - // chain access first element (chain_access function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 94, - 8, - 93, - 12, - "M1.move", - "& Symbols::M1::OuterStruct", - Some((87, 11, "M1.move")), - ); - // chain second element (chain_access function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 94, - 14, - 88, - 8, - "M1.move", - "Symbols::M1::OuterStruct", - Some((87, 11, "M1.move")), - ); - // chain access third element (chain_access function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 94, - 26, - 3, - 8, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // chain second element after the block (chain_access_block function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 102, - 10, - 88, - 8, - "M1.move", - "Symbols::M1::OuterStruct", - Some((87, 11, "M1.move")), - ); - // chain access first element when borrowing (chain_access_borrow function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 108, - 17, - 107, - 12, - "M1.move", - "& Symbols::M1::OuterStruct", - Some((87, 11, "M1.move")), - ); - // chain second element when borrowing (chain_access_borrow function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 108, - 23, - 88, - 8, - "M1.move", - "Symbols::M1::OuterStruct", - Some((87, 11, "M1.move")), - ); - // chain access third element when borrowing (chain_access_borrow function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 3, - 108, - 35, - 3, - 8, - "M1.move", - "Symbols::M1::SomeStruct", - Some((2, 11, "M1.move")), - ); - // variable in cast (cast function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 114, - 9, - 113, - 12, - "M1.move", - "u128", - None, - ); - // constant in an annotation (annot function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 118, - 19, - 6, - 10, - "M1.move", - "u64", - None, - ); - // struct type param def (struct_param function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 122, - 21, - 122, - 21, - "M1.move", - "Symbols::M2::SomeOtherStruct", - Some((2, 11, "M2.move")), - ); - // struct type param use (struct_param function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 123, - 8, - 122, - 21, - "M1.move", - "Symbols::M2::SomeOtherStruct", - Some((2, 11, "M2.move")), - ); - // struct type local var def (struct_var function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 127, - 12, - 127, - 12, - "M1.move", - "Symbols::M2::SomeOtherStruct", - Some((2, 11, "M2.move")), - ); - // struct type local var use (struct_var function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 129, - 12, - 127, - 12, - "M1.move", - "Symbols::M2::SomeOtherStruct", - Some((2, 11, "M2.move")), - ); - - let mut fpath = path.clone(); - fpath.push("sources/M3.move"); - let cpath = dunce::canonicalize(&fpath).unwrap(); - - let mod_symbols = symbols.file_use_defs.get(&cpath).unwrap(); - - // generic type in struct definition - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 2, - 23, - 2, - 23, - "M3.move", - "T", - None, - ); - // generic type in struct field definition - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 3, - 20, - 2, - 23, - "M3.move", - "T", - None, - ); - // generic type in generic type definition (type_param_arg function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 6, - 23, - 6, - 23, - "M3.move", - "T", - None, - ); - // parameter (type_param_arg function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 6, - 39, - 6, - 39, - "M3.move", - "T", - None, - ); - // generic type in param type (type_param_arg function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 3, - 6, - 46, - 6, - 23, - "M3.move", - "T", - None, - ); - // generic type in return type (type_param_arg function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 4, - 6, - 50, - 6, - 23, - "M3.move", - "T", - None, - ); - // generic type in struct param type (struct_type_param_arg function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 4, - 10, - 52, - 10, - 30, - "M3.move", - "T", - None, - ); - // generic type in struct return type (struct_type_param_arg function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 6, - 10, - 69, - 10, - 30, - "M3.move", - "T", - None, - ); - // generic type in pack (pack_type_param function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 15, - 20, - 14, - 24, - "M3.move", - "T", - None, - ); - // field type in struct field definition which itself is a struct - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 23, - 20, - 2, - 11, - "M3.move", - "Symbols::M3::ParamStruct", - Some((2, 11, "M3.move")), - ); - // generic type in struct field definition which itself is a struct - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 2, - 23, - 32, - 22, - 30, - "M3.move", - "T", - None, - ); - - let mut fpath = path.clone(); - fpath.push("sources/M4.move"); - let cpath = dunce::canonicalize(&fpath).unwrap(); - - let mod_symbols = symbols.file_use_defs.get(&cpath).unwrap(); - - // param name in RHS (if_cond function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 4, - 18, - 2, - 16, - "M4.move", - "u64", - None, - ); - // param name in RHS (if_cond function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 6, - 22, - 4, - 12, - "M4.move", - "u64", - None, - ); - // var in if's true branch (if_cond function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 7, - 12, - 4, - 12, - "M4.move", - "u64", - None, - ); - // redefined var in if's false branch (if_cond function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 10, - 12, - 9, - 16, - "M4.move", - "u64", - None, - ); - // var name in while loop condition (while_loop function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 20, - 15, - 18, - 12, - "M4.move", - "u64", - None, - ); - // var name in while loop's inner block (while_loop function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 23, - 26, - 18, - 12, - "M4.move", - "u64", - None, - ); - // redefined var name in while loop's inner block (while_loop function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 24, - 23, - 23, - 20, - "M4.move", - "u64", - None, - ); - // var name in while loop's main block (while_loop function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 26, - 12, - 18, - 12, - "M4.move", - "u64", - None, - ); - // redefined var name in while loop's inner block (loop function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 1, - 40, - 23, - 39, - 20, - "M4.move", - "u64", - None, - ); - // var name in loop's main block (loop function) - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 43, - 16, - 34, - 12, - "M4.move", - "u64", - None, - ); - // const in a different module in the same file - assert_use_def( - mod_symbols, - &symbols.file_name_mapping, - 0, - 55, - 10, - 55, - 10, - "M4.move", - "u64", - None, - ); -} diff --git a/third_party/move/move-analyzer/src/utils.rs b/third_party/move/move-analyzer/src/utils.rs deleted file mode 100644 index ed9accd69399d..0000000000000 --- a/third_party/move/move-analyzer/src/utils.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use codespan_reporting::files::{Files, SimpleFiles}; -use lsp_types::Position; -use move_command_line_common::files::FileHash; -use move_ir_types::location::*; -use move_symbol_pool::Symbol; -use std::collections::HashMap; - -/// Converts a location from the byte index format to the line/character (Position) format, where -/// line/character are 0-based. -pub fn get_loc( - fhash: &FileHash, - pos: ByteIndex, - files: &SimpleFiles, - file_id_mapping: &HashMap, -) -> Option { - let id = match file_id_mapping.get(fhash) { - Some(v) => v, - None => return None, - }; - match files.location(*id, pos as usize) { - Ok(v) => Some(Position { - // we need 0-based column location - line: v.line_number as u32 - 1, - character: v.column_number as u32 - 1, - }), - Err(_) => None, - } -} diff --git a/third_party/move/move-analyzer/src/vfs.rs b/third_party/move/move-analyzer/src/vfs.rs deleted file mode 100644 index 6f12e4e477463..0000000000000 --- a/third_party/move/move-analyzer/src/vfs.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) The Diem Core Contributors -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -//! The language server must operate upon Move source buffers as they are being edited. -//! As a result, it is frequently queried about buffers that have not yet (or may never be) saved -//! to the actual file system. -//! -//! To manage these buffers, this module provides a "virtual file system" -- in reality, it is -//! basically just a mapping from file identifier (this could be the file's path were it to be -//! saved) to its textual contents. - -use crate::symbols; -use lsp_server::Notification; -use lsp_types::{ - notification::Notification as _, DidChangeTextDocumentParams, DidCloseTextDocumentParams, - DidOpenTextDocumentParams, DidSaveTextDocumentParams, -}; -use std::path::PathBuf; - -/// A mapping from identifiers (file names, potentially, but not necessarily) to their contents. -#[derive(Debug, Default)] -pub struct VirtualFileSystem { - files: std::collections::HashMap, -} - -impl VirtualFileSystem { - /// Returns a reference to the buffer corresponding to the given identifier, or `None` if it - /// is not present in the system. - pub fn get(&self, identifier: &PathBuf) -> Option<&str> { - self.files.get(identifier).map(|s| s.as_str()) - } - - /// Inserts or overwrites the buffer corresponding to the given identifier. - /// - /// TODO: A far more efficient "virtual file system" would update its buffers with changes sent - /// from the client, instead of completely replacing them each time. The rust-analyzer has a - /// 'vfs' module that is capable of doing just that, but it is not published on crates.io. If - /// we could help get it published, we could use it here. - pub fn update(&mut self, identifier: PathBuf, content: &str) { - self.files.insert(identifier, content.to_string()); - } - - /// Removes the buffer and its identifier from the system. - pub fn remove(&mut self, identifier: &PathBuf) { - self.files.remove(identifier); - } -} - -/// Updates the given virtual file system based on the text document sync notification that was sent. -pub fn on_text_document_sync_notification( - files: &mut VirtualFileSystem, - symbolicator_runner: &symbols::SymbolicatorRunner, - notification: &Notification, -) { - eprintln!("text document notification"); - match notification.method.as_str() { - lsp_types::notification::DidOpenTextDocument::METHOD => { - let parameters = - serde_json::from_value::(notification.params.clone()) - .expect("could not deserialize notification"); - files.update( - parameters.text_document.uri.to_file_path().unwrap(), - ¶meters.text_document.text, - ); - symbolicator_runner.run(parameters.text_document.uri.to_file_path().unwrap()); - }, - lsp_types::notification::DidChangeTextDocument::METHOD => { - let parameters = - serde_json::from_value::(notification.params.clone()) - .expect("could not deserialize notification"); - files.update( - parameters.text_document.uri.to_file_path().unwrap(), - ¶meters.content_changes.last().unwrap().text, - ); - }, - lsp_types::notification::DidSaveTextDocument::METHOD => { - let parameters = - serde_json::from_value::(notification.params.clone()) - .expect("could not deserialize notification"); - files.update( - parameters.text_document.uri.to_file_path().unwrap(), - ¶meters.text.unwrap(), - ); - symbolicator_runner.run(parameters.text_document.uri.to_file_path().unwrap()); - }, - lsp_types::notification::DidCloseTextDocument::METHOD => { - let parameters = - serde_json::from_value::(notification.params.clone()) - .expect("could not deserialize notification"); - files.remove(¶meters.text_document.uri.to_file_path().unwrap()); - }, - _ => eprintln!("invalid notification '{}'", notification.method), - } - eprintln!("text document notification handled"); -} diff --git a/third_party/move/move-analyzer/tests/symbols/Move.toml b/third_party/move/move-analyzer/tests/symbols/Move.toml deleted file mode 100644 index ddd0a6d3582c2..0000000000000 --- a/third_party/move/move-analyzer/tests/symbols/Move.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "Symbols" -version = "0.0.1" - -[dependencies] -MoveStdlib = { local = "../../../move-stdlib/", addr_subst = { "std" = "0x1" } } - -[addresses] -Symbols = "0xCAFE" diff --git a/third_party/move/move-analyzer/tests/symbols/sources/M1.move b/third_party/move/move-analyzer/tests/symbols/sources/M1.move deleted file mode 100644 index 33324b73cd932..0000000000000 --- a/third_party/move/move-analyzer/tests/symbols/sources/M1.move +++ /dev/null @@ -1,136 +0,0 @@ -module Symbols::M1 { - - struct SomeStruct has key, drop, store { - some_field: u64, - } - - const SOME_CONST: u64 = 42; - - - fun unpack(s: SomeStruct): u64 { - let SomeStruct { some_field: value } = s; - value - } - - fun cp(value: u64): u64 { - let ret = value; - ret - } - - fun pack(): SomeStruct { - let ret = SomeStruct { some_field: SOME_CONST }; - ret - } - - fun other_mod_struct(): Symbols::M2::SomeOtherStruct { - Symbols::M2::some_other_struct(SOME_CONST) - } - - use Symbols::M2::{Self, SomeOtherStruct}; - - fun other_mod_struct_import(): SomeOtherStruct { - M2::some_other_struct(7) - } - - fun acq(addr: address): u64 acquires SomeStruct { - let val = borrow_global(addr); - val.some_field - } - - fun multi_arg_call(): u64 { - M2::multi_arg(SOME_CONST, SOME_CONST) - } - - fun vec(): vector { - let s = SomeStruct{ some_field: 7 }; - vector[SomeStruct{ some_field: 42 }, s] - } - - fun unpack_no_assign(s: SomeStruct): u64 { - let value: u64; - SomeStruct { some_field: value } = s; - value - } - - fun mut(): u64 { - let tmp = 7; - let r = &mut tmp; - *r = SOME_CONST; - tmp - } - - fun ret(p1: bool, p2: u64): u64 { - if (p1) { - return SOME_CONST - }; - p2 - } - - fun abort_call() { - abort SOME_CONST - } - - fun deref(): u64 { - let tmp = 7; - let r = &tmp; - *r - } - - fun unary(p: bool):bool { - !p - } - - fun temp_borrow(): u64 { - let tmp = &SOME_CONST; - *tmp - } - - struct OuterStruct has key, drop { - some_struct: SomeStruct, - } - - fun chain_access(): u64 { - let inner = SomeStruct{ some_field: 42 }; - let outer = OuterStruct{ some_struct: inner }; - outer.some_struct.some_field - } - - fun chain_access_block(): u64 { - let inner = SomeStruct{ some_field: 42 }; - let outer = OuterStruct{ some_struct: inner }; - { - outer - }.some_struct.some_field - } - - fun chain_access_borrow(): u64 { - let inner = SomeStruct{ some_field: 42 }; - let outer = OuterStruct{ some_struct: inner }; - let r = &outer.some_struct.some_field; - *r - } - - fun cast(): u64 { - let tmp: u128 = 42; - (tmp as u64) - } - - fun annot(): u64 { - let tmp = (SOME_CONST: u64); - tmp - } - - fun struct_param(p: SomeOtherStruct): SomeOtherStruct { - p - } - - fun struct_var(p: bool): SomeOtherStruct { - let tmp = M2::some_other_struct(7); - if (p) { - tmp - } else { - M2::some_other_struct(42) - } - } - -} diff --git a/third_party/move/move-analyzer/tests/symbols/sources/M2.move b/third_party/move/move-analyzer/tests/symbols/sources/M2.move deleted file mode 100644 index ad95754648c24..0000000000000 --- a/third_party/move/move-analyzer/tests/symbols/sources/M2.move +++ /dev/null @@ -1,15 +0,0 @@ -module Symbols::M2 { - - struct SomeOtherStruct has drop { - some_field: u64, - } - - public fun some_other_struct(v: u64): SomeOtherStruct { - SomeOtherStruct { some_field: v } - } - - public fun multi_arg(p1: u64, p2: u64): u64 { - p1 + p2 - } - -} diff --git a/third_party/move/move-analyzer/tests/symbols/sources/M3.move b/third_party/move/move-analyzer/tests/symbols/sources/M3.move deleted file mode 100644 index db264354600e4..0000000000000 --- a/third_party/move/move-analyzer/tests/symbols/sources/M3.move +++ /dev/null @@ -1,27 +0,0 @@ -module Symbols::M3 { - - struct ParamStruct { - some_field: T, - } - - fun type_param_arg(param: T): T { - param - } - - fun struct_type_param_arg(param: ParamStruct): ParamStruct { - param - } - - fun pack_type_param(param: T): ParamStruct { - ParamStruct { some_field: param } - } - - fun struct_parameterized_arg(param: ParamStruct): ParamStruct { - param - } - - struct AnotherParamStruct { - some_field: ParamStruct, - } - -} diff --git a/third_party/move/move-analyzer/tests/symbols/sources/M4.move b/third_party/move/move-analyzer/tests/symbols/sources/M4.move deleted file mode 100644 index de30eea4afd37..0000000000000 --- a/third_party/move/move-analyzer/tests/symbols/sources/M4.move +++ /dev/null @@ -1,58 +0,0 @@ -module Symbols::M4 { - - fun if_cond(tmp: u64): u64 { - - let tmp = tmp; - - let ret = if (tmp == 7) { - tmp - } else { - let tmp = 42; - tmp - }; - - ret - } - - fun while_loop(): u64 { - - let tmp = 7; - - while (tmp > 0) { - let tmp2 = 1; - { - let tmp = tmp; - tmp2 = tmp - tmp2; - }; - tmp = tmp2; - }; - - tmp - } - - fun loop_loop(): u64 { - - let tmp = 7; - - loop { - let tmp2 = 1; - { - let tmp = tmp; - tmp2 = tmp - tmp2; - }; - tmp = tmp2; - if (tmp == 0) { - break - } - }; - - tmp - } - -} - -module Symbols::M5 { - - const SOME_CONST: u64 = 7; - -} diff --git a/third_party/move/move-analyzer/tests/symbols/sources/M6.move b/third_party/move/move-analyzer/tests/symbols/sources/M6.move deleted file mode 100644 index aa3427fa8c361..0000000000000 --- a/third_party/move/move-analyzer/tests/symbols/sources/M6.move +++ /dev/null @@ -1,42 +0,0 @@ -module Symbols::M6 { - - /// This is a documented struct - /// With a multi-line docstring - struct DocumentedStruct has key, drop, store { - /// A documented field - documented_field: u64, - } - - /// Constant containing the answer to the universe - const DOCUMENTED_CONSTANT: u64 = 42; - - - /// A documented function that unpacks a DocumentedStruct - fun unpack(s: DocumentedStruct): u64 { - let DocumentedStruct { documented_field: value } = s; - value - } - - /** - This is a multiline docstring - - This docstring has empty lines. - - It uses the ** format instead of /// - */ - fun other_doc_struct(): Symbols::M7::OtherDocStruct { - Symbols::M7::create_other_struct(DOCUMENTED_CONSTANT) - } - - /** Asterix based single-line docstring */ - fun acq(addr: address): u64 acquires DocumentedStruct { - let val = borrow_global(addr); - val.documented_field - } - - use Symbols::M7::{Self, OtherDocStruct}; - - fun other_doc_struct_import(): OtherDocStruct { - M7::create_other_struct(7) - } -} diff --git a/third_party/move/move-analyzer/tests/symbols/sources/M7.move b/third_party/move/move-analyzer/tests/symbols/sources/M7.move deleted file mode 100644 index b4165da101290..0000000000000 --- a/third_party/move/move-analyzer/tests/symbols/sources/M7.move +++ /dev/null @@ -1,13 +0,0 @@ -module Symbols::M7 { - - /// Documented struct in another module - struct OtherDocStruct has drop { - /// Documented field in another module - some_field: u64, - } - - /// Documented initializer in another module - public fun create_other_struct(v: u64): OtherDocStruct { - OtherDocStruct { some_field: v } - } -} diff --git a/third_party/move/move-binary-format/Cargo.toml b/third_party/move/move-binary-format/Cargo.toml index 3e8536b21769b..3d238656d40d5 100644 --- a/third_party/move/move-binary-format/Cargo.toml +++ b/third_party/move/move-binary-format/Cargo.toml @@ -10,22 +10,22 @@ publish = ["crates-io"] edition = "2021" [dependencies] -anyhow = "1.0.52" -arbitrary = { version = "1.3.2", optional = true, features = ["derive"] } +anyhow = { workspace = true } +arbitrary = { workspace = true, optional = true, features = ["derive"] } backtrace = { workspace = true } -indexmap = "1.9.3" +indexmap = { workspace = true } move-core-types = { path = "../move-core/types" } -proptest = { version = "1.0.0", optional = true } -proptest-derive = { version = "0.3.0", optional = true } -ref-cast = "1.0.6" -serde = { version = "1.0.124", default-features = false } -variant_count = "1.1.0" +proptest = { workspace = true, optional = true } +proptest-derive = { workspace = true, optional = true } +ref-cast = { workspace = true } +serde = { workspace = true } +variant_count = { workspace = true } [dev-dependencies] -move-core-types = { path = "../move-core/types", features = ["fuzzing" ] } -proptest = "1.0.0" -proptest-derive = "0.3.0" -serde_json = "1.0.64" +move-core-types = { path = "../move-core/types", features = ["fuzzing"] } +proptest = { workspace = true } +proptest-derive = { workspace = true } +serde_json = { workspace = true } [features] default = [] diff --git a/third_party/move/move-binary-format/serializer-tests/Cargo.toml b/third_party/move/move-binary-format/serializer-tests/Cargo.toml index 80573679b1b28..b83bf8a437565 100644 --- a/third_party/move/move-binary-format/serializer-tests/Cargo.toml +++ b/third_party/move/move-binary-format/serializer-tests/Cargo.toml @@ -12,8 +12,8 @@ edition = "2021" [dev-dependencies] move-binary-format = { path = "../", features = ["fuzzing"] } move-core-types = { path = "../../move-core/types" } -proptest = "1.0.0" -proptest-derive = "0.3.0" +proptest = { workspace = true } +proptest-derive = { workspace = true } [features] fuzzing = ["move-binary-format/fuzzing"] diff --git a/third_party/move/move-bytecode-verifier/Cargo.toml b/third_party/move/move-bytecode-verifier/Cargo.toml index 91871519f72fd..9085bb1816373 100644 --- a/third_party/move/move-bytecode-verifier/Cargo.toml +++ b/third_party/move/move-bytecode-verifier/Cargo.toml @@ -10,17 +10,17 @@ publish = false edition = "2021" [dependencies] -fail = "0.4.0" +fail = { workspace = true } move-binary-format = { path = "../move-binary-format" } -petgraph = "0.5.1" -serde = "1.0.149" -typed-arena = "2.0.2" +petgraph = { workspace = true } +serde = { workspace = true } +typed-arena = { workspace = true } move-borrow-graph = { path = "../move-borrow-graph" } move-core-types = { path = "../move-core/types" } [dev-dependencies] -hex-literal = "0.3.4" +hex-literal = { workspace = true } invalid-mutations = { path = "invalid-mutations" } [features] diff --git a/third_party/move/move-bytecode-verifier/bytecode-verifier-tests/Cargo.toml b/third_party/move/move-bytecode-verifier/bytecode-verifier-tests/Cargo.toml index 90a10498922a0..4e5c437cddfdb 100644 --- a/third_party/move/move-bytecode-verifier/bytecode-verifier-tests/Cargo.toml +++ b/third_party/move/move-bytecode-verifier/bytecode-verifier-tests/Cargo.toml @@ -10,14 +10,14 @@ publish = false edition = "2021" [dev-dependencies] -fail = { version = "0.4.0", features = ['failpoints'] } -hex = "0.4.3" +fail = { workspace = true, features = ['failpoints'] } +hex = { workspace = true } invalid-mutations = { path = "../invalid-mutations" } -move-binary-format = { path = "../../move-binary-format", features = ["fuzzing" ] } +move-binary-format = { path = "../../move-binary-format", features = ["fuzzing"] } move-bytecode-verifier = { path = "../" } move-core-types = { path = "../../move-core/types" } -petgraph = "0.5.1" -proptest = "1.0.0" +petgraph = { workspace = true } +proptest = { workspace = true } [features] fuzzing = ["move-binary-format/fuzzing"] diff --git a/third_party/move/move-bytecode-verifier/fuzz/Cargo.toml b/third_party/move/move-bytecode-verifier/fuzz/Cargo.toml index 0232ebf5b6455..c89658cc77f8c 100644 --- a/third_party/move/move-bytecode-verifier/fuzz/Cargo.toml +++ b/third_party/move/move-bytecode-verifier/fuzz/Cargo.toml @@ -10,8 +10,8 @@ edition = "2018" cargo-fuzz = true [dependencies] -arbitrary = "1.3.2" -libfuzzer-sys = "0.4" +arbitrary = { workspace = true } +libfuzzer-sys = { workspace = true } move-binary-format = { path = "../../move-binary-format", features = ["fuzzing"] } move-bytecode-verifier = { path = "../" } move-core-types = { path = "../../move-core/types", features = ["fuzzing"] } diff --git a/third_party/move/move-bytecode-verifier/invalid-mutations/Cargo.toml b/third_party/move/move-bytecode-verifier/invalid-mutations/Cargo.toml index b72c60c3dbd89..77a835ecfbb2d 100644 --- a/third_party/move/move-bytecode-verifier/invalid-mutations/Cargo.toml +++ b/third_party/move/move-bytecode-verifier/invalid-mutations/Cargo.toml @@ -12,7 +12,7 @@ publish = false [dependencies] move-binary-format = { path = "../../move-binary-format" } move-core-types = { path = "../../move-core/types" } -proptest = "1.0.0" +proptest = { workspace = true } [features] default = [] diff --git a/third_party/move/move-bytecode-verifier/transactional-tests/Cargo.toml b/third_party/move/move-bytecode-verifier/transactional-tests/Cargo.toml index e30e2600e0718..2e346e12b13d9 100644 --- a/third_party/move/move-bytecode-verifier/transactional-tests/Cargo.toml +++ b/third_party/move/move-bytecode-verifier/transactional-tests/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "Apache-2.0" [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-transactional-test-runner = { path = "../../testing-infra/transactional-test-runner" } [[test]] diff --git a/third_party/move/move-command-line-common/Cargo.toml b/third_party/move/move-command-line-common/Cargo.toml index 71ca4a9657ccd..4030dbe59abe9 100644 --- a/third_party/move/move-command-line-common/Cargo.toml +++ b/third_party/move/move-command-line-common/Cargo.toml @@ -10,14 +10,14 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -difference = "2.0.0" -dirs-next = "2.0.0" -hex = "0.4.3" -num-bigint = "0.4.0" -once_cell = "1.7.2" -serde = { version = "1.0.124", features = ["derive"] } -sha2 = "0.9.3" -walkdir = "2.3.1" +anyhow = { workspace = true } +difference = { workspace = true } +dirs-next = { workspace = true } +hex = { workspace = true } +num-bigint = { workspace = true } +once_cell = { workspace = true } +serde = { workspace = true, features = ["derive"] } +sha2 = { workspace = true } +walkdir = { workspace = true } move-core-types = { path = "../move-core/types" } diff --git a/third_party/move/move-command-line-common/src/env.rs b/third_party/move/move-command-line-common/src/env.rs index 38ad5f18bc84b..a2c7df2991849 100644 --- a/third_party/move/move-command-line-common/src/env.rs +++ b/third_party/move/move-command-line-common/src/env.rs @@ -28,6 +28,28 @@ pub fn get_bytecode_version_from_env(from_input: Option) -> Option { } } +/// An environment variable which can be set to force use of the move-compiler-v2 +/// in all contexts where the V1 compiler is currently used. +const MOVE_COMPILER_V2_ENV_VAR: &str = "MOVE_COMPILER_V2"; +const MVC_V2_ENV_VAR: &str = "MVC_V2"; + +pub fn get_move_compiler_v2_from_env() -> bool { + read_bool_env_var(MOVE_COMPILER_V2_ENV_VAR) || read_bool_env_var(MVC_V2_ENV_VAR) +} + +/// An environment variable which can be set to cause a panic if the V1 Move compiler is run (past +/// parsing and expansion phases, which are currently used by V2) as part of another toolchain or +/// testing process. This is useful for debugging whether V2 is being invoked properly. +const MOVE_COMPILER_BLOCK_V1_ENV_VAR: &str = "MOVE_COMPILER_BLOCK_V1"; +const MVC_BLOCK_V1_ENV_VAR: &str = "MVC_BLOCK_V1"; + +// Make this debugging option available as a CLI flag +pub const MOVE_COMPILER_BLOCK_V1_FLAG: &str = "block-compiler-v1"; + +pub fn get_move_compiler_block_v1_from_env() -> bool { + read_bool_env_var(MOVE_COMPILER_BLOCK_V1_ENV_VAR) || read_bool_env_var(MVC_BLOCK_V1_ENV_VAR) +} + pub fn read_env_var(v: &str) -> String { std::env::var(v).unwrap_or_else(|_| String::new()) } @@ -37,6 +59,14 @@ pub fn read_bool_env_var(v: &str) -> bool { val.parse::() == Ok(true) || val.parse::() == Ok(1) } +pub fn bool_to_str(b: bool) -> &'static str { + if b { + "true" + } else { + "false" + } +} + pub static MOVE_HOME: Lazy = Lazy::new(|| { std::env::var("MOVE_HOME").unwrap_or_else(|_| { format!( diff --git a/third_party/move/move-command-line-common/src/testing.rs b/third_party/move/move-command-line-common/src/testing.rs index f90e7ef5db94f..68aa6734dc674 100644 --- a/third_party/move/move-command-line-common/src/testing.rs +++ b/third_party/move/move-command-line-common/src/testing.rs @@ -18,9 +18,6 @@ pub const UPDATE_BASELINE: &str = "UPDATE_BASELINE"; pub const UPBL: &str = "UPBL"; pub const UB: &str = "UB"; -/// Env variable to enable compiler v2 in tests -pub const MOVE_COMPILER_V2: &str = "MOVE_COMPILER_V2"; - pub const PRETTY: &str = "PRETTY"; pub const FILTER: &str = "FILTER"; diff --git a/third_party/move/move-compiler-v2/Cargo.toml b/third_party/move/move-compiler-v2/Cargo.toml index dd244423450cc..9b133f283b8d4 100644 --- a/third_party/move/move-compiler-v2/Cargo.toml +++ b/third_party/move/move-compiler-v2/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" [dependencies] abstract-domain-derive = { path = "../move-model/bytecode/abstract_domain_derive" } -anyhow = "1.0.62" +anyhow = { workspace = true } bcs = { workspace = true } move-binary-format = { path = "../move-binary-format" } move-bytecode-source-map = { path = "../move-ir-compiler/move-bytecode-source-map" } @@ -25,26 +25,26 @@ move-model = { path = "../move-model" } move-stackless-bytecode = { path = "../move-model/bytecode" } move-symbol-pool = { path = "../move-symbol-pool" } -clap = { version = "4.3.9", features = ["derive", "env"] } -codespan-reporting = { version = "0.11.1", features = ["serde", "serialization"] } -ethnum = "1.0.4" -flexi_logger = "0.27.4" +clap = { workspace = true, features = ["derive", "env"] } +codespan-reporting = { workspace = true, features = ["serde", "serialization"] } +ethnum = { workspace = true } +flexi_logger = { workspace = true } im = "15.0.0" -itertools = "0.10.0" -log = { version = "0.4.14", features = ["serde"] } -num = "0.4.0" -once_cell = "1.7.2" +itertools = { workspace = true } +log = { workspace = true, features = ["serde"] } +num = { workspace = true } +once_cell = { workspace = true } #paste = "1.0.5" -petgraph = "0.6.4" +petgraph = { workspace = true } [dev-dependencies] -anyhow = "1.0.52" -datatest-stable = "0.1.1" +anyhow = { workspace = true } +datatest-stable = { workspace = true } move-command-line-common = { path = "../move-command-line-common" } move-ir-types = { path = "../move-ir/types" } move-prover-test-utils = { path = "../move-prover/test-utils" } move-stdlib = { path = "../move-stdlib" } -walkdir = "2.3.3" +walkdir = { workspace = true } [lib] doctest = false diff --git a/third_party/move/move-compiler-v2/src/experiments.rs b/third_party/move/move-compiler-v2/src/experiments.rs index c61ccc4a89cda..2735e125212b4 100644 --- a/third_party/move/move-compiler-v2/src/experiments.rs +++ b/third_party/move/move-compiler-v2/src/experiments.rs @@ -171,6 +171,11 @@ pub static EXPERIMENTS: Lazy> = Lazy::new(|| { .to_string(), default: Given(false), }, + Experiment { + name: Experiment::ATTACH_COMPILED_MODULE.to_string(), + description: "Whether to attach the compiled module to the global env.".to_string(), + default: Given(false), + }, ]; experiments .into_iter() @@ -185,6 +190,7 @@ impl Experiment { pub const ACQUIRES_CHECK: &'static str = "acquires-check"; pub const AST_SIMPLIFY: &'static str = "ast-simplify"; pub const AST_SIMPLIFY_FULL: &'static str = "ast-simplify-full"; + pub const ATTACH_COMPILED_MODULE: &'static str = "attach-compiled-module"; pub const CHECKS: &'static str = "checks"; pub const COPY_PROPAGATION: &'static str = "copy-propagation"; pub const DEAD_CODE_ELIMINATION: &'static str = "dead-code-elimination"; diff --git a/third_party/move/move-compiler-v2/src/file_format_generator/mod.rs b/third_party/move/move-compiler-v2/src/file_format_generator/mod.rs index 48cab1e3e9331..2143de5397d3c 100644 --- a/third_party/move/move-compiler-v2/src/file_format_generator/mod.rs +++ b/third_party/move/move-compiler-v2/src/file_format_generator/mod.rs @@ -4,17 +4,21 @@ mod function_generator; mod module_generator; -use crate::{file_format_generator::module_generator::ModuleContext, options::Options}; +use crate::{file_format_generator::module_generator::ModuleContext, options::Options, Experiment}; use module_generator::ModuleGenerator; use move_binary_format::{file_format as FF, internals::ModuleIndex}; use move_command_line_common::{address::NumericalAddress, parser::NumberFormat}; use move_compiler::compiled_unit as CU; -use move_model::model::{GlobalEnv, SCRIPT_MODULE_NAME}; +use move_model::{ + ast::ModuleName, + model::{GlobalEnv, SCRIPT_MODULE_NAME}, +}; use move_stackless_bytecode::function_target_pipeline::FunctionTargetsHolder; use move_symbol_pool::Symbol; +use std::collections::BTreeMap; pub fn generate_file_format( - env: &GlobalEnv, + env: &mut GlobalEnv, targets: &FunctionTargetsHolder, ) -> Vec { let ctx = ModuleContext { env, targets }; @@ -23,6 +27,9 @@ pub fn generate_file_format( .get_extension::() .expect("Options is available"); let compile_test_code = options.compile_test_code; + let mut module_data = BTreeMap::new(); + let mut script_module_data = BTreeMap::new(); + let mut script_index = 0; for module_env in ctx.env.get_modules() { if !module_env.is_target() { continue; @@ -84,6 +91,16 @@ pub fn generate_file_format( type_parameters, parameters, }; + if options.experiment_on(Experiment::ATTACH_COMPILED_MODULE) { + let module_name = + ModuleName::pseudo_script_name(env.symbol_pool(), script_index); + script_index += 1; + let module = move_model::script_into_module( + script.clone(), + &module_name.name().display(env.symbol_pool()).to_string(), + ); + script_module_data.insert(module_env.get_id(), (module, source_map.clone())); + } result.push(CU::CompiledUnitEnum::Script(CU::NamedCompiledScript { package_name: None, name, @@ -94,6 +111,9 @@ pub fn generate_file_format( ctx.internal_error(module_env.get_loc(), "inconsistent script module"); } } else { + if options.experiment_on(Experiment::ATTACH_COMPILED_MODULE) { + module_data.insert(module_env.get_id(), (ff_module.clone(), source_map.clone())); + } result.push(CU::CompiledUnitEnum::Module(CU::NamedCompiledModule { package_name: None, address: NumericalAddress::new( @@ -106,6 +126,14 @@ pub fn generate_file_format( })); } } + if options.experiment_on(Experiment::ATTACH_COMPILED_MODULE) { + for (id, (m, map)) in module_data { + env.attach_compiled_module(id, m, map) + } + for (id, (m, map)) in script_module_data { + env.attach_compiled_module(id, m, map) + } + } result } diff --git a/third_party/move/move-compiler-v2/src/lib.rs b/third_party/move/move-compiler-v2/src/lib.rs index 638e78f9661c7..3e747e1fc96ec 100644 --- a/third_party/move/move-compiler-v2/src/lib.rs +++ b/third_party/move/move-compiler-v2/src/lib.rs @@ -45,19 +45,14 @@ use move_command_line_common::files::FileHash; use move_compiler::{ compiled_unit::{ verify_units, AnnotatedCompiledModule, AnnotatedCompiledScript, AnnotatedCompiledUnit, - CompiledUnit, FunctionInfo, NamedCompiledModule, NamedCompiledScript, + CompiledUnit, FunctionInfo, }, diagnostics::FilesSourceText, shared::{known_attributes::KnownAttribute, unique_map::UniqueMap}, }; use move_disassembler::disassembler::Disassembler; use move_ir_types::location; -use move_model::{ - add_move_lang_diagnostics, - ast::{Address, ModuleName}, - model::GlobalEnv, - PackageInfo, -}; +use move_model::{add_move_lang_diagnostics, model::GlobalEnv, PackageInfo}; use move_stackless_bytecode::function_target_pipeline::{ FunctionTargetPipeline, FunctionTargetsHolder, FunctionVariant, }; @@ -118,7 +113,7 @@ where } check_errors(&env, error_writer, "stackless-bytecode analysis errors")?; - let modules_and_scripts = run_file_format_gen(&env, &targets); + let modules_and_scripts = run_file_format_gen(&mut env, &targets); check_errors(&env, error_writer, "assembling errors")?; debug!( @@ -145,66 +140,10 @@ pub fn run_move_compiler_for_analysis( ) -> anyhow::Result { options.whole_program = true; // will set `treat_everything_as_target` options = options.set_experiment(Experiment::SPEC_REWRITE, true); - let (mut env, units) = run_move_compiler(error_writer, options)?; + options = options.set_experiment(Experiment::ATTACH_COMPILED_MODULE, true); + let (env, _units) = run_move_compiler(error_writer, options)?; // Reset for subsequent analysis env.treat_everything_as_target(false); - // Script pseudo module names are sequentially constructed as `_1 .. _n`. To - // associate the bytecode module by name we need to count the index. This - // assumes script modules come out in the same order as they are were - // added to the environment. - let mut script_index = 0; // script names are named using a sequential index - for unit in units { - let unit = unit.into_compiled_unit(); - match unit { - CompiledUnit::Module(NamedCompiledModule { - package_name: _, - address, - name, - module, - source_map, - }) => { - let name = ModuleName::new( - Address::Numerical(address.into_inner()), - env.symbol_pool().make(name.as_str()), - ); - if let Some(id) = env.find_module(&name).map(|m| m.get_id()) { - env.attach_compiled_module(id, module, source_map) - } else { - env.error( - &env.unknown_loc(), - &format!( - "failed to attach bytecode: cannot find module `{}`", - name.display_full(&env) - ), - ); - } - }, - CompiledUnit::Script(NamedCompiledScript { - package_name: _, - name: _, - script, - source_map, - }) => { - let name = ModuleName::pseudo_script_name(env.symbol_pool(), script_index); - script_index += 1; - let module = move_model::script_into_module( - script, - &name.name().display(env.symbol_pool()).to_string(), - ); - if let Some(id) = env.find_module(&name).map(|m| m.get_id()) { - env.attach_compiled_module(id, module, source_map) - } else { - env.error( - &env.unknown_loc(), - &format!( - "failed to attach bytecode: cannot find script `{}`", - name.display_full(&env) - ), - ); - } - }, - } - } Ok(env) } @@ -297,7 +236,10 @@ pub fn run_bytecode_gen(env: &GlobalEnv) -> FunctionTargetsHolder { targets } -pub fn run_file_format_gen(env: &GlobalEnv, targets: &FunctionTargetsHolder) -> Vec { +pub fn run_file_format_gen( + env: &mut GlobalEnv, + targets: &FunctionTargetsHolder, +) -> Vec { info!("File Format Generation"); file_format_generator::generate_file_format(env, targets) } diff --git a/third_party/move/move-compiler-v2/tests/testsuite.rs b/third_party/move/move-compiler-v2/tests/testsuite.rs index 009d763ed0bfa..6232945d95b75 100644 --- a/third_party/move/move-compiler-v2/tests/testsuite.rs +++ b/third_party/move/move-compiler-v2/tests/testsuite.rs @@ -678,7 +678,7 @@ fn run_test(path: &Path, config: TestConfig) -> datatest_stable::Result<()> { }, ); if *ok.borrow() && config.stop_after == StopAfter::FileFormat { - let units = run_file_format_gen(&env, &targets); + let units = run_file_format_gen(&mut env, &targets); let out = &mut test_output.borrow_mut(); update_diags(ok.borrow_mut(), out, &env); if *ok.borrow() { diff --git a/third_party/move/move-compiler-v2/tools/testdiff/Cargo.toml b/third_party/move/move-compiler-v2/tools/testdiff/Cargo.toml index 40562c405b21d..c986c3c925ae3 100644 --- a/third_party/move/move-compiler-v2/tools/testdiff/Cargo.toml +++ b/third_party/move/move-compiler-v2/tools/testdiff/Cargo.toml @@ -10,8 +10,8 @@ license = "Apache-2.0" publish = false [dependencies] -anyhow = "1.0.62" -clap = { version = "4.3.9", features = ["derive", "env"] } -once_cell = "1.10.0" -regex = "1.10.4" -walkdir = "2.3.3" +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive", "env"] } +once_cell = { workspace = true } +regex = { workspace = true } +walkdir = { workspace = true } diff --git a/third_party/move/move-compiler-v2/transactional-tests/Cargo.toml b/third_party/move/move-compiler-v2/transactional-tests/Cargo.toml index 724f6727c55cd..d8110ee7ae77f 100644 --- a/third_party/move/move-compiler-v2/transactional-tests/Cargo.toml +++ b/third_party/move/move-compiler-v2/transactional-tests/Cargo.toml @@ -8,15 +8,15 @@ license = "Apache-2.0" [dependencies] move-command-line-common = { path = "../../move-command-line-common" } -once_cell = "1.7.2" +once_cell = { workspace = true } [dev-dependencies] -datatest-stable = "0.1.1" -itertools = "0.10.3" +datatest-stable = { workspace = true } +itertools = { workspace = true } move-compiler-v2 = { path = ".." } move-model = { path = "../../move-model" } move-transactional-test-runner = { path = "../../testing-infra/transactional-test-runner" } -walkdir = "2.3.3" +walkdir = { workspace = true } [[test]] name = "tests" diff --git a/third_party/move/move-compiler/Cargo.toml b/third_party/move/move-compiler/Cargo.toml index a8497ebc4b3e8..ba79c0fade252 100644 --- a/third_party/move/move-compiler/Cargo.toml +++ b/third_party/move/move-compiler/Cargo.toml @@ -8,15 +8,15 @@ edition = "2021" license = "Apache-2.0" [dependencies] -anyhow = "1.0.52" -clap = { version = "4.3.9", features = ["derive"] } -codespan-reporting = "0.11.1" -hex = "0.4.3" -once_cell = "1.7.2" -petgraph = "0.5.1" -regex = "1.5.5" -sha3 = "0.9.1" -tempfile = "3.2.0" +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } +codespan-reporting = { workspace = true } +hex = { workspace = true } +once_cell = { workspace = true } +petgraph = { workspace = true } +regex = { workspace = true } +sha3 = { workspace = true } +tempfile = { workspace = true } bcs = { workspace = true } @@ -31,7 +31,7 @@ move-ir-types = { path = "../move-ir/types" } move-symbol-pool = { path = "../move-symbol-pool" } [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-stdlib = { path = "../move-stdlib" } [[test]] diff --git a/third_party/move/move-compiler/src/command_line/mod.rs b/third_party/move/move-compiler/src/command_line/mod.rs index c9935a3fe1b03..c5fe374abe3b3 100644 --- a/third_party/move/move-compiler/src/command_line/mod.rs +++ b/third_party/move/move-compiler/src/command_line/mod.rs @@ -2,6 +2,8 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 +use move_command_line_common::env::read_bool_env_var; + pub mod compiler; pub const DEPENDENCY: &str = "dependency"; @@ -44,6 +46,7 @@ pub const COMPILED_NAMED_ADDRESS_MAPPING: &str = "compiled-module-address-name"; // default value for compiler --debug flag (1 or true to set) // (usually for debugging situations where compiler flags are hard to reach) pub const MOVE_COMPILER_DEBUG_ENV_VAR: &str = "MOVE_COMPILER_DEBUG"; +pub const MVC_DEBUG_ENV_VAR: &str = "MVC_DEBUG"; // Name of compiler CLI debug clap flag (in CLI, looks like --debug): pub const DEBUG_FLAG: &str = "debug"; @@ -51,6 +54,7 @@ pub const DEBUG_FLAG: &str = "debug"; // default value for boolean --dump-bytecode flag (1 or true to set) // (usually for debugging situations where compiler flags are hard to reach) pub const MOVE_COMPILER_DUMP_ENV_VAR: &str = "MOVE_COMPILER_DUMP"; +pub const MVC_DUMP_ENV_VAR: &str = "MVC_DUMP"; pub const MOVE_COMPILER_WARN_OF_DEPRECATION_USE: &str = "MOVE_COMPILER_WARN_OF_DEPRECATION_USE"; pub const MOVE_COMPILER_WARN_OF_DEPRECATION_USE_FLAG: &str = "Wdeprecation"; @@ -61,3 +65,12 @@ pub const WARN_OF_DEPRECATION_USE_IN_APTOS_LIBS_FLAG: &str = "Wdeprecation-aptos pub const WARN_UNUSED_FLAG: &str = "Wunused"; pub const V2_FLAG: &str = "v2"; + +// Flag to dump a stacktrace on a compiler error, for users who like +// to keep RUST_BACKTRACE always enabled. +pub const MOVE_COMPILER_BACKTRACE_ENV_VAR: &str = "MOVE_COMPILER_BACKTRACE"; +pub const MVC_BACKTRACE_ENV_VAR: &str = "MVC_BACKTRACE"; + +pub fn get_move_compiler_backtrace_from_env() -> bool { + read_bool_env_var(MOVE_COMPILER_BACKTRACE_ENV_VAR) || read_bool_env_var(MVC_BACKTRACE_ENV_VAR) +} diff --git a/third_party/move/move-compiler/src/diagnostics/mod.rs b/third_party/move/move-compiler/src/diagnostics/mod.rs index d511563dd6827..865cda6bc6bbb 100644 --- a/third_party/move/move-compiler/src/diagnostics/mod.rs +++ b/third_party/move/move-compiler/src/diagnostics/mod.rs @@ -5,7 +5,7 @@ pub mod codes; use crate::{ - command_line::{COLOR_MODE_ENV_VAR, MOVE_COMPILER_DEBUG_ENV_VAR}, + command_line::{COLOR_MODE_ENV_VAR, MOVE_COMPILER_BACKTRACE_ENV_VAR}, diagnostics::codes::{DiagnosticCode, DiagnosticInfo, Severity}, }; use codespan_reporting::{ @@ -300,9 +300,9 @@ impl Diagnostic { } fn add_backtrace(msg: &str, is_bug: bool) -> String { - static DEBUG_COMPILER: Lazy = - Lazy::new(|| read_bool_env_var(MOVE_COMPILER_DEBUG_ENV_VAR)); - if is_bug || *DEBUG_COMPILER { + static DUMP_BACKTRACE: Lazy = + Lazy::new(|| read_bool_env_var(MOVE_COMPILER_BACKTRACE_ENV_VAR)); + if is_bug || *DUMP_BACKTRACE { let bt = Backtrace::capture(); if BacktraceStatus::Captured == bt.status() { format!("{}\nBacktrace: {:#?}", msg, bt) diff --git a/third_party/move/move-compiler/src/naming/translate.rs b/third_party/move/move-compiler/src/naming/translate.rs index 27176aef6de08..901e284483e3b 100644 --- a/third_party/move/move-compiler/src/naming/translate.rs +++ b/third_party/move/move-compiler/src/naming/translate.rs @@ -353,6 +353,9 @@ pub fn program( prog: E::Program, ) -> N::Program { let mut context = Context::new(compilation_env, pre_compiled_lib, &prog); + if context.env.flags().get_block_v1_compiler() { + panic!("V1 compiler not expected"); + } let E::Program { modules: emodules, scripts: escripts, diff --git a/third_party/move/move-compiler/src/shared/mod.rs b/third_party/move/move-compiler/src/shared/mod.rs index d8981ef9e7de0..1288625ba7bc4 100644 --- a/third_party/move/move-compiler/src/shared/mod.rs +++ b/third_party/move/move-compiler/src/shared/mod.rs @@ -8,7 +8,10 @@ use crate::{ naming::ast::ModuleDefinition, }; use clap::*; -use move_command_line_common::env::read_bool_env_var; +use move_command_line_common::env::{ + bool_to_str, get_move_compiler_block_v1_from_env, read_bool_env_var, + MOVE_COMPILER_BLOCK_V1_FLAG, +}; use move_ir_types::location::*; use move_symbol_pool::Symbol; use once_cell::sync::Lazy; @@ -17,6 +20,7 @@ use std::{ collections::{BTreeMap, BTreeSet}, fmt, hash::Hash, + string::ToString, sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}, }; @@ -286,47 +290,25 @@ pub fn format_comma>(items: I) -> Str //************************************************************************************************** pub fn debug_compiler_env_var() -> bool { - static DEBUG_COMPILER: Lazy = - Lazy::new(|| read_bool_env_var(cli::MOVE_COMPILER_DEBUG_ENV_VAR)); + static DEBUG_COMPILER: Lazy = Lazy::new(|| { + read_bool_env_var(cli::MOVE_COMPILER_DEBUG_ENV_VAR) + || read_bool_env_var(cli::MVC_DEBUG_ENV_VAR) + }); *DEBUG_COMPILER } -pub fn debug_compiler_env_var_str() -> &'static str { - if debug_compiler_env_var() { - "true" - } else { - "false" - } -} - pub fn move_compiler_warn_of_deprecation_use_env_var() -> bool { static WARN_OF_DEPRECATION: Lazy = Lazy::new(|| read_bool_env_var(cli::MOVE_COMPILER_WARN_OF_DEPRECATION_USE)); *WARN_OF_DEPRECATION } -pub fn move_compiler_warn_of_deprecation_use_env_var_str() -> &'static str { - if move_compiler_warn_of_deprecation_use_env_var() { - "true" - } else { - "false" - } -} - pub fn warn_of_deprecation_use_in_aptos_libs_env_var() -> bool { static WARN_OF_DEPRECATION: Lazy = Lazy::new(|| read_bool_env_var(cli::WARN_OF_DEPRECATION_USE_IN_APTOS_LIBS)); *WARN_OF_DEPRECATION } -pub fn warn_of_deprecation_use_in_aptos_libs_env_var_str() -> &'static str { - if warn_of_deprecation_use_in_aptos_libs_env_var() { - "true" - } else { - "false" - } -} - #[derive(Clone, Debug, Eq, PartialEq, Parser)] pub struct Flags { /// Compile in test mode @@ -376,18 +358,19 @@ pub struct Flags { skip_attribute_checks: bool, /// Debug compiler by printing out internal information - #[clap(long = cli::DEBUG_FLAG, default_value=debug_compiler_env_var_str())] + #[clap(long = cli::DEBUG_FLAG, default_value=bool_to_str(debug_compiler_env_var()))] debug: bool, /// Show warnings about use of deprecated functions, modules, constants, etc. /// Note that current value of this constant is "Wdeprecation" - #[clap(long = cli::MOVE_COMPILER_WARN_OF_DEPRECATION_USE_FLAG, default_value=move_compiler_warn_of_deprecation_use_env_var_str())] + #[clap(long = cli::MOVE_COMPILER_WARN_OF_DEPRECATION_USE_FLAG, + default_value=bool_to_str(move_compiler_warn_of_deprecation_use_env_var()))] warn_of_deprecation_use: bool, /// Show warnings about use of deprecated usage in the Aptos libraries, /// which we should generally not bother users with. /// Note that current value of this constant is "Wdeprecation-aptos" - #[clap(long = cli::WARN_OF_DEPRECATION_USE_IN_APTOS_LIBS_FLAG, default_value=warn_of_deprecation_use_in_aptos_libs_env_var_str())] + #[clap(long = cli::WARN_OF_DEPRECATION_USE_IN_APTOS_LIBS_FLAG, default_value=bool_to_str(warn_of_deprecation_use_in_aptos_libs_env_var()))] warn_of_deprecation_use_in_aptos_libs: bool, /// Show warnings about unused functions, fields, constants, etc. @@ -398,6 +381,10 @@ pub struct Flags { /// Support v2 syntax (up to expansion phase) #[clap(long = cli::V2_FLAG)] v2: bool, + + /// Block v1 runs past expansion phase + #[clap(long = MOVE_COMPILER_BLOCK_V1_FLAG, default_value=bool_to_str(get_move_compiler_block_v1_from_env()))] + block_v1_compiler: bool, } impl Flags { @@ -415,23 +402,14 @@ impl Flags { warn_of_deprecation_use_in_aptos_libs: warn_of_deprecation_use_in_aptos_libs_env_var(), warn_unused: false, v2: false, + block_v1_compiler: get_move_compiler_block_v1_from_env(), } } pub fn testing() -> Self { Self { test: true, - verify: false, - shadow: false, - flavor: "".to_string(), - bytecode_version: None, - keep_testing_functions: false, - skip_attribute_checks: false, - debug: debug_compiler_env_var(), - warn_of_deprecation_use: move_compiler_warn_of_deprecation_use_env_var(), - warn_of_deprecation_use_in_aptos_libs: warn_of_deprecation_use_in_aptos_libs_env_var(), - warn_unused: false, - v2: false, + ..Self::empty() } } @@ -439,16 +417,7 @@ impl Flags { Self { test: true, verify: true, - shadow: false, - flavor: "".to_string(), - bytecode_version: None, - keep_testing_functions: false, - skip_attribute_checks: false, - debug: debug_compiler_env_var(), - warn_of_deprecation_use: move_compiler_warn_of_deprecation_use_env_var(), - warn_of_deprecation_use_in_aptos_libs: warn_of_deprecation_use_in_aptos_libs_env_var(), - warn_unused: false, - v2: false, + ..Self::empty() } } @@ -457,15 +426,7 @@ impl Flags { test: false, verify: true, shadow: true, // allows overlapping between sources and deps - flavor: "".to_string(), - bytecode_version: None, - keep_testing_functions: false, - skip_attribute_checks: false, - debug: debug_compiler_env_var(), - warn_of_deprecation_use: move_compiler_warn_of_deprecation_use_env_var(), - warn_of_deprecation_use_in_aptos_libs: warn_of_deprecation_use_in_aptos_libs_env_var(), - warn_unused: false, - v2: false, + ..Self::empty() } } @@ -474,15 +435,9 @@ impl Flags { test: false, verify: true, shadow: true, // allows overlapping between sources and deps - flavor: "".to_string(), - bytecode_version: None, keep_testing_functions: true, - skip_attribute_checks: false, - debug: false, - warn_of_deprecation_use: move_compiler_warn_of_deprecation_use_env_var(), - warn_of_deprecation_use_in_aptos_libs: warn_of_deprecation_use_in_aptos_libs_env_var(), - warn_unused: false, v2: true, + ..Self::empty() } } @@ -568,6 +523,17 @@ impl Flags { } } + pub fn get_block_v1_compiler(&self) -> bool { + self.block_v1_compiler + } + + pub fn set_block_v1_compiler(self, new_value: bool) -> Self { + Self { + block_v1_compiler: new_value, + ..self + } + } + pub fn warn_unused(&self) -> bool { self.warn_unused } diff --git a/third_party/move/move-compiler/transactional-tests/Cargo.toml b/third_party/move/move-compiler/transactional-tests/Cargo.toml index 241db23c7f10b..4a61fbf336685 100644 --- a/third_party/move/move-compiler/transactional-tests/Cargo.toml +++ b/third_party/move/move-compiler/transactional-tests/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "Apache-2.0" [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-transactional-test-runner = { path = "../../testing-infra/transactional-test-runner" } [[test]] diff --git a/third_party/move/move-core/types/Cargo.toml b/third_party/move/move-core/types/Cargo.toml index bcf8908a0d3a4..591721a90796a 100644 --- a/third_party/move/move-core/types/Cargo.toml +++ b/third_party/move/move-core/types/Cargo.toml @@ -10,32 +10,33 @@ publish = ["crates-io"] edition = "2021" [dependencies] -anyhow = "1.0.52" -arbitrary = { version = "1.3.2", features = [ "derive_arbitrary"], optional = true } -bytes = { version = "1.4.0" } -ethnum = "1.0.4" -hashbrown = "0.14.3" -hex = "0.4.3" -num = "0.4.0" -once_cell = "1.7.2" -primitive-types = { version = "0.10.1", features = ["impl-serde"] } -proptest = { version = "1.0.0", default-features = false, optional = true } -proptest-derive = { version = "0.3.0", default-features = false, optional = true } -rand = "0.8.3" -ref-cast = "1.0.6" -serde = { version = "1.0.124", default-features = false } -serde_bytes = "0.11.5" -thiserror = "1.0.45" -uint = "0.9.4" - +anyhow = { workspace = true } +arbitrary = { workspace = true, features = ["derive_arbitrary"], optional = true } bcs = { workspace = true } +bytes = { workspace = true } +ethnum = { workspace = true } +hashbrown = { workspace = true } +hex = { workspace = true } +num = { workspace = true } +once_cell = { workspace = true } +primitive-types = { workspace = true, features = ["impl-serde"] } +proptest = { workspace = true, optional = true } +proptest-derive = { workspace = true, optional = true } +# Cannot use workspace version as aptos-core currently cannot be upgraded +# to newer rand. See https://github.com/aptos-labs/aptos-core/issues/13031 +rand = { version = "0.8.5" } +ref-cast = { workspace = true } +serde = { workspace = true } +serde_bytes = { workspace = true } +thiserror = { workspace = true } +uint = { workspace = true } [dev-dependencies] -arbitrary = { version = "1.3.2", features = [ "derive_arbitrary"] } -proptest = "1.0.0" -proptest-derive = "0.3.0" -regex = "1.5.5" -serde_json = "1.0.64" +arbitrary = { workspace = true, features = ["derive_arbitrary"] } +proptest = { workspace = true } +proptest-derive = { workspace = true } +regex = { workspace = true } +serde_json = { workspace = true } [features] default = [] diff --git a/third_party/move/move-core/types/src/account_address.rs b/third_party/move/move-core/types/src/account_address.rs index a575f2c85d585..3858f80162f19 100644 --- a/third_party/move/move-core/types/src/account_address.rs +++ b/third_party/move/move-core/types/src/account_address.rs @@ -24,6 +24,8 @@ impl AccountAddress { pub const MAX_ADDRESS: Self = Self([0xFF; Self::LENGTH]); /// Hex address: 0x1 pub const ONE: Self = Self::get_hex_address_one(); + /// Hex address: 0xA + pub const TEN: Self = Self::get_hex_address_ten(); /// Hex address: 0x3 pub const THREE: Self = Self::get_hex_address_three(); /// Hex address: 0x2 @@ -47,6 +49,12 @@ impl AccountAddress { Self(addr) } + const fn get_hex_address_ten() -> Self { + let mut addr = [0u8; AccountAddress::LENGTH]; + addr[AccountAddress::LENGTH - 1] = 10u8; + Self(addr) + } + const fn get_hex_address_three() -> Self { let mut addr = [0u8; AccountAddress::LENGTH]; addr[AccountAddress::LENGTH - 1] = 3u8; diff --git a/third_party/move/move-core/types/src/language_storage.rs b/third_party/move/move-core/types/src/language_storage.rs index cbf197d22cf82..494258d77f158 100644 --- a/third_party/move/move-core/types/src/language_storage.rs +++ b/third_party/move/move-core/types/src/language_storage.rs @@ -102,7 +102,9 @@ impl FromStr for TypeTag { } #[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, PartialOrd, Ord)] -#[cfg_attr(any(test, feature = "fuzzing"), derive(arbitrary::Arbitrary))] +#[cfg_attr(feature = "fuzzing", derive(arbitrary::Arbitrary))] +#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))] +#[cfg_attr(any(test, feature = "fuzzing"), proptest(no_params))] pub struct StructTag { pub address: AccountAddress, pub module: Identifier, diff --git a/third_party/move/move-core/types/src/vm_status.rs b/third_party/move/move-core/types/src/vm_status.rs index 750866c125dc4..965883162eb1e 100644 --- a/third_party/move/move-core/types/src/vm_status.rs +++ b/third_party/move/move-core/types/src/vm_status.rs @@ -585,11 +585,12 @@ pub enum StatusCode { GAS_PAYER_ACCOUNT_MISSING = 36, INSUFFICIENT_BALANCE_FOR_REQUIRED_DEPOSIT = 37, GAS_PARAMS_MISSING = 38, + REQUIRED_DEPOSIT_INCONSISTENT_WITH_TXN_MAX_GAS = 39, // Reserved error code for future use - RESERVED_VALIDATION_ERROR_4 = 39, RESERVED_VALIDATION_ERROR_5 = 40, RESERVED_VALIDATION_ERROR_6 = 41, RESERVED_VALIDATION_ERROR_7 = 42, + RESERVED_VALIDATION_ERROR_8 = 43, // When a code module/script is published it is verified. These are the // possible errors that can arise from the verification process. @@ -831,12 +832,13 @@ pub enum StatusCode { ACCESS_STACK_LIMIT_EXCEEDED = 4035, // We tried to create resource with more than currently allowed number of DelayedFields TOO_MANY_DELAYED_FIELDS = 4036, - + // Dynamic function call errors. + RUNTIME_DISPATCH_ERROR = 4037, // Reserved error code for future use. Always keep this buffer of well-defined new codes. - RESERVED_RUNTIME_ERROR_1 = 4037, - RESERVED_RUNTIME_ERROR_2 = 4038, - RESERVED_RUNTIME_ERROR_3 = 4039, - RESERVED_RUNTIME_ERROR_4 = 4040, + RESERVED_RUNTIME_ERROR_1 = 4038, + RESERVED_RUNTIME_ERROR_2 = 4039, + RESERVED_RUNTIME_ERROR_3 = 4040, + RESERVED_RUNTIME_ERROR_4 = 4041, // A reserved status to represent an unknown vm status. // this is std::u64::MAX, but we can't pattern match on that, so put the hardcoded value in diff --git a/third_party/move/move-examples/diem-framework/crates/cli/Cargo.toml b/third_party/move/move-examples/diem-framework/crates/cli/Cargo.toml index 20c90afe14235..54191f06121d6 100644 --- a/third_party/move/move-examples/diem-framework/crates/cli/Cargo.toml +++ b/third_party/move/move-examples/diem-framework/crates/cli/Cargo.toml @@ -8,8 +8,8 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -clap = { version = "4.3.9", features = ["derive"] } +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } move-cli = { path = "../../../../../tools/move-cli" } move-core-types = { path = "../../../../../move-core/types" } @@ -20,4 +20,4 @@ move-vm-test-utils = { path = "../../../../../move-vm/test-utils" } diem-framework-natives = { path = "../natives" } [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } diff --git a/third_party/move/move-examples/diem-framework/crates/crypto-derive/Cargo.toml b/third_party/move/move-examples/diem-framework/crates/crypto-derive/Cargo.toml index f9a6e08ba896f..3018a3631492c 100644 --- a/third_party/move/move-examples/diem-framework/crates/crypto-derive/Cargo.toml +++ b/third_party/move/move-examples/diem-framework/crates/crypto-derive/Cargo.toml @@ -10,9 +10,9 @@ license = "Apache-2.0" proc-macro = true [dependencies] -proc-macro2 = "1.0.24" -quote = "1.0.9" -syn = { version = "1.0.64", features = ["derive"] } +proc-macro2 = { workspace = true } +quote = { workspace = true } +syn = { workspace = true, features = ["derive"] } [dev-dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } diff --git a/third_party/move/move-examples/diem-framework/crates/crypto/Cargo.toml b/third_party/move/move-examples/diem-framework/crates/crypto/Cargo.toml index 2bb8069757705..7c07613b50bdf 100644 --- a/third_party/move/move-examples/diem-framework/crates/crypto/Cargo.toml +++ b/third_party/move/move-examples/diem-framework/crates/crypto/Cargo.toml @@ -7,40 +7,40 @@ edition = "2021" license = "Apache-2.0" [dependencies] -aes-gcm = "0.8.0" -anyhow = "1.0.52" -bytes = "1.4.0" -curve25519-dalek = { version = "0.1.0", package = "curve25519-dalek-fiat", default-features = false, features = ["std"] } +aes-gcm = { workspace = true } +anyhow = { workspace = true } +bytes = { workspace = true } +curve25519-dalek = { workspace = true, package = "curve25519-dalek-fiat", features = ["std"] } diem-crypto-derive = { path = "../crypto-derive" } -digest = "0.9.0" -ed25519-dalek = { version = "0.1.0", package = "ed25519-dalek-fiat", default-features = false, features = ["std", "serde"] } -hex = "0.4.3" -hkdf = "0.10.0" -mirai-annotations = "1.10.1" -once_cell = "1.7.2" -proptest = { version = "1.0.0", optional = true } -proptest-derive = { version = "0.3.0", optional = true } -rand = "0.8.0" -serde = { version = "1.0.124", features = ["derive"] } -serde-name = "0.1.1" -serde_bytes = "0.11.5" -sha2 = "0.9.3" -static_assertions = "1.1.0" -thiserror = "1.0.24" -tiny-keccak = { version = "2.0.2", features = ["sha3"] } -x25519-dalek = { version = "0.1.0", package = "x25519-dalek-fiat", default-features = false, features = ["std"] } +digest = { workspace = true } +ed25519-dalek = { workspace = true, package = "ed25519-dalek-fiat", features = ["std", "serde"] } +hex = { workspace = true } +hkdf = { workspace = true } +mirai-annotations = { workspace = true } +once_cell = { workspace = true } +proptest = { workspace = true, optional = true } +proptest-derive = { workspace = true, optional = true } +rand = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde-name = { workspace = true } +serde_bytes = { workspace = true } +sha2 = { workspace = true } +static_assertions = { workspace = true } +thiserror = { workspace = true } +tiny-keccak = { workspace = true, features = ["sha3"] } +x25519-dalek = { workspace = true, package = "x25519-dalek-fiat", features = ["std"] } -bcs = "0.1.4" +bcs = { workspace = true } [dev-dependencies] -bitvec = "0.19.4" -byteorder = "1.4.3" -criterion = "0.3.4" -proptest = "1.0.0" -proptest-derive = "0.3.0" -ripemd160 = "0.9.1" -serde_json = "1.0.64" -sha3 = "0.9.1" +bitvec = { workspace = true } +byteorder = { workspace = true } +criterion = { workspace = true } +proptest = { workspace = true } +proptest-derive = { workspace = true } +ripemd160 = { workspace = true } +serde_json = { workspace = true } +sha3 = { workspace = true } # TODO: some tests will fail if this is set to 1.0.63 trybuild = "=1.0.53" diff --git a/third_party/move/move-examples/diem-framework/crates/natives/Cargo.toml b/third_party/move/move-examples/diem-framework/crates/natives/Cargo.toml index a9d5bebc3dcc6..bb093436b9f69 100644 --- a/third_party/move/move-examples/diem-framework/crates/natives/Cargo.toml +++ b/third_party/move/move-examples/diem-framework/crates/natives/Cargo.toml @@ -14,4 +14,4 @@ move-vm-types = { path = "../../../../../move-vm/types" } diem-crypto = { path = "../crypto" } -smallvec = "1.6.1" +smallvec = { workspace = true } diff --git a/third_party/move/move-ir-compiler/Cargo.toml b/third_party/move/move-ir-compiler/Cargo.toml index eb8fb43ceb7c0..4a558246d37ec 100644 --- a/third_party/move/move-ir-compiler/Cargo.toml +++ b/third_party/move/move-ir-compiler/Cargo.toml @@ -10,14 +10,14 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -clap = { version = "4.3.9", features = ["derive"] } +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } move-binary-format = { path = "../move-binary-format" } move-bytecode-source-map = { path = "move-bytecode-source-map" } move-bytecode-verifier = { path = "../move-bytecode-verifier" } move-command-line-common = { path = "../move-command-line-common" } move-ir-to-bytecode = { path = "move-ir-to-bytecode" } -serde_json = "1.0.64" +serde_json = { workspace = true } bcs = { workspace = true } diff --git a/third_party/move/move-ir-compiler/move-bytecode-source-map/Cargo.toml b/third_party/move/move-ir-compiler/move-bytecode-source-map/Cargo.toml index b5cf80c14a616..434bccf85ac8d 100644 --- a/third_party/move/move-ir-compiler/move-bytecode-source-map/Cargo.toml +++ b/third_party/move/move-ir-compiler/move-bytecode-source-map/Cargo.toml @@ -7,7 +7,7 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-command-line-common = { path = "../../move-command-line-common" } move-core-types = { path = "../../move-core/types" } @@ -16,7 +16,7 @@ move-symbol-pool = { path = "../../move-symbol-pool" } bcs = { workspace = true } -serde = { version = "1.0.124", default-features = false } +serde = { workspace = true } [features] default = [] diff --git a/third_party/move/move-ir-compiler/move-ir-to-bytecode/Cargo.toml b/third_party/move/move-ir-compiler/move-ir-to-bytecode/Cargo.toml index 4579646c96f87..cf897818ea2ad 100644 --- a/third_party/move/move-ir-compiler/move-ir-to-bytecode/Cargo.toml +++ b/third_party/move/move-ir-compiler/move-ir-to-bytecode/Cargo.toml @@ -10,9 +10,9 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -codespan-reporting = "0.11.1" -log = "0.4.14" +anyhow = { workspace = true } +codespan-reporting = { workspace = true } +log = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-bytecode-source-map = { path = "../move-bytecode-source-map" } move-command-line-common = { path = "../../move-command-line-common" } @@ -20,7 +20,7 @@ move-core-types = { path = "../../move-core/types" } move-ir-to-bytecode-syntax = { path = "syntax" } move-ir-types = { path = "../../move-ir/types" } move-symbol-pool = { path = "../../move-symbol-pool" } -ouroboros = "0.9.2" +ouroboros = { workspace = true } [features] default = [] diff --git a/third_party/move/move-ir-compiler/move-ir-to-bytecode/syntax/Cargo.toml b/third_party/move/move-ir-compiler/move-ir-to-bytecode/syntax/Cargo.toml index babc5c8c0aa31..35e53bfe51bae 100644 --- a/third_party/move/move-ir-compiler/move-ir-to-bytecode/syntax/Cargo.toml +++ b/third_party/move/move-ir-compiler/move-ir-to-bytecode/syntax/Cargo.toml @@ -10,8 +10,8 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -hex = "0.4.3" +anyhow = { workspace = true } +hex = { workspace = true } move-command-line-common = { path = "../../../move-command-line-common" } move-core-types = { path = "../../../move-core/types" } move-ir-types = { path = "../../../move-ir/types" } diff --git a/third_party/move/move-ir-compiler/transactional-tests/Cargo.toml b/third_party/move/move-ir-compiler/transactional-tests/Cargo.toml index 122e04c286d50..84bd5b1309565 100644 --- a/third_party/move/move-ir-compiler/transactional-tests/Cargo.toml +++ b/third_party/move/move-ir-compiler/transactional-tests/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "Apache-2.0" [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-transactional-test-runner = { path = "../../testing-infra/transactional-test-runner" } [[test]] diff --git a/third_party/move/move-ir/types/Cargo.toml b/third_party/move/move-ir/types/Cargo.toml index 04ced1a4bcced..adf98dc221ace 100644 --- a/third_party/move/move-ir/types/Cargo.toml +++ b/third_party/move/move-ir/types/Cargo.toml @@ -11,10 +11,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -hex = "0.4.3" +hex = { workspace = true } move-command-line-common = { path = "../../move-command-line-common" } -once_cell = "1.7.2" -serde = { version = "1.0.124", features = ["derive"] } +once_cell = { workspace = true } +serde = { workspace = true, features = ["derive"] } move-core-types = { path = "../../move-core/types" } move-symbol-pool = { path = "../../move-symbol-pool" } diff --git a/third_party/move/move-model/Cargo.toml b/third_party/move/move-model/Cargo.toml index c948590cfab36..49f76a32dfdf1 100644 --- a/third_party/move/move-model/Cargo.toml +++ b/third_party/move/move-model/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "Apache-2.0" [dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } move-binary-format = { path = "../move-binary-format" } move-bytecode-source-map = { path = "../move-ir-compiler/move-bytecode-source-map" } move-command-line-common = { path = "../move-command-line-common" } @@ -19,19 +19,19 @@ move-ir-types = { path = "../move-ir/types" } move-symbol-pool = { path = "../move-symbol-pool" } # external dependencies -codespan = "0.11.1" -codespan-reporting = "0.11.1" -internment = { version = "0.5.0", features = [ "arc"] } -itertools = "0.10.0" -log = "0.4.14" -num = "0.4.0" -num-traits = "0.2.15" -once_cell = "1.7.2" -regex = "1.5.5" -serde = { version = "1.0.124", features = ["derive"] } +codespan = { workspace = true } +codespan-reporting = { workspace = true } +internment = { workspace = true, features = ["arc"] } +itertools = { workspace = true } +log = { workspace = true } +num = { workspace = true } +num-traits = { workspace = true } +once_cell = { workspace = true } +regex = { workspace = true } +serde = { workspace = true, features = ["derive"] } [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-prover-test-utils = { path = "../move-prover/test-utils" } [[test]] diff --git a/third_party/move/move-model/bytecode-test-utils/Cargo.toml b/third_party/move/move-model/bytecode-test-utils/Cargo.toml index fed87a1d9ca17..eb622da8f865b 100644 --- a/third_party/move/move-model/bytecode-test-utils/Cargo.toml +++ b/third_party/move/move-model/bytecode-test-utils/Cargo.toml @@ -10,8 +10,8 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -codespan-reporting = { version = "0.11.1", features = ["serde", "serialization"] } +anyhow = { workspace = true } +codespan-reporting = { workspace = true, features = ["serde", "serialization"] } move-command-line-common = { path = "../../move-command-line-common" } move-compiler = { path = "../../move-compiler" } move-compiler-v2 = { path = "../../move-compiler-v2" } diff --git a/third_party/move/move-model/bytecode/Cargo.toml b/third_party/move/move-model/bytecode/Cargo.toml index 4b6051aa74ad2..66a9d4e635f37 100644 --- a/third_party/move/move-model/bytecode/Cargo.toml +++ b/third_party/move/move-model/bytecode/Cargo.toml @@ -15,18 +15,18 @@ move-binary-format = { path = "../../move-binary-format" } move-core-types = { path = "../../move-core/types" } move-model = { path = ".." } -codespan-reporting = { version = "0.11.1", features = ["serde", "serialization"] } -ethnum = "1.0.4" +codespan-reporting = { workspace = true, features = ["serde", "serialization"] } +ethnum = { workspace = true } im = "15.0.0" -itertools = "0.10.0" -log = "0.4.14" -num = "0.4.0" -paste = "1.0.5" -petgraph = "0.5.1" +itertools = { workspace = true } +log = { workspace = true } +num = { workspace = true } +paste = { workspace = true } +petgraph = { workspace = true } [dev-dependencies] -anyhow = "1.0.52" -datatest-stable = "0.1.1" +anyhow = { workspace = true } +datatest-stable = { workspace = true } move-stackless-bytecode-test-utils = { path = "../bytecode-test-utils" } [features] diff --git a/third_party/move/move-model/bytecode/abstract_domain_derive/Cargo.toml b/third_party/move/move-model/bytecode/abstract_domain_derive/Cargo.toml index 5ecc1842031b8..33fb294cf577c 100644 --- a/third_party/move/move-model/bytecode/abstract_domain_derive/Cargo.toml +++ b/third_party/move/move-model/bytecode/abstract_domain_derive/Cargo.toml @@ -9,9 +9,9 @@ edition = "2021" proc-macro = true [dependencies] -syn = "2.0" -quote = "1.0" -proc-macro2 = "1.0" +syn = { workspace = true } +quote = { workspace = true } +proc-macro2 = { workspace = true } [dev-dependencies] move-stackless-bytecode = { path = ".." } diff --git a/third_party/move/move-model/bytecode/abstract_domain_derive/src/lib.rs b/third_party/move/move-model/bytecode/abstract_domain_derive/src/lib.rs index b00e9ebbffb0a..eba20df93b1bd 100644 --- a/third_party/move/move-model/bytecode/abstract_domain_derive/src/lib.rs +++ b/third_party/move/move-model/bytecode/abstract_domain_derive/src/lib.rs @@ -96,11 +96,7 @@ pub fn abstract_domain_derive(input: TokenStream) -> TokenStream { .named .iter() .filter_map(|field| { - if field - .attrs - .iter() - .any(|attr| attr.path().is_ident("no_join")) - { + if field.attrs.iter().any(|attr| attr.path.is_ident("no_join")) { None } else { let field_name = diff --git a/third_party/move/move-model/src/metadata.rs b/third_party/move/move-model/src/metadata.rs index 93b24b5bd8da8..b8990fa10ba7b 100644 --- a/third_party/move/move-model/src/metadata.rs +++ b/third_party/move/move-model/src/metadata.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use anyhow::bail; -use move_command_line_common::env::read_bool_env_var; +use move_command_line_common::env::{get_move_compiler_v2_from_env, read_bool_env_var}; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use std::{ @@ -82,7 +82,7 @@ pub enum CompilerVersion { impl Default for CompilerVersion { /// We allow the default to be set via an environment variable. fn default() -> Self { - static MOVE_COMPILER_V2: Lazy = Lazy::new(|| read_bool_env_var("MOVE_COMPILER_V2")); + static MOVE_COMPILER_V2: Lazy = Lazy::new(get_move_compiler_v2_from_env); if *MOVE_COMPILER_V2 { Self::V2_0 } else { diff --git a/third_party/move/move-model/src/model.rs b/third_party/move/move-model/src/model.rs index e4a7f6f7e2162..a7dc59997024a 100644 --- a/third_party/move/move-model/src/model.rs +++ b/third_party/move/move-model/src/model.rs @@ -836,12 +836,11 @@ impl GlobalEnv { } fn add_backtrace(msg: &str, _is_bug: bool) -> String { - // For now, we do not use is_bug, but we could have - // another env var MOVE_COMPILER_DEBUG_BUG_ENV_VAR to - // only backtrace bugs if the env var is set. - static DEBUG_COMPILER: Lazy = - Lazy::new(|| read_bool_env_var(cli::MOVE_COMPILER_DEBUG_ENV_VAR)); - if *DEBUG_COMPILER { + // Note that you need both MOVE_COMPILER_BACKTRACE=1 and RUST_BACKTRACE=1 for this to + // actually generate a backtrace. + static DUMP_BACKTRACE: Lazy = + Lazy::new(|| read_bool_env_var(cli::MOVE_COMPILER_BACKTRACE_ENV_VAR)); + if *DUMP_BACKTRACE { let bt = Backtrace::capture(); if BacktraceStatus::Captured == bt.status() { format!("{}\nBacktrace: {:#?}", msg, bt) diff --git a/third_party/move/move-prover/Cargo.toml b/third_party/move/move-prover/Cargo.toml index d1113fbbb51e4..2609f4abd3c10 100644 --- a/third_party/move/move-prover/Cargo.toml +++ b/third_party/move/move-prover/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "Apache-2.0" [dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } move-abigen = { path = "move-abigen" } move-command-line-common = { path = "../move-command-line-common" } move-compiler = { path = "../move-compiler" } @@ -21,22 +21,22 @@ move-prover-bytecode-pipeline = { path = "bytecode-pipeline" } move-stackless-bytecode = { path = "../move-model/bytecode" } # external dependencies -atty = "0.2.14" -clap = { version = "4.3.9", features = ["derive"] } -codespan-reporting = "0.11.1" -itertools = "0.10.0" -log = { version = "0.4.14", features = ["serde"] } -once_cell = "1.7.2" -serde = { version = "1.0.124", features = ["derive"] } -simplelog = "0.9.0" -toml = "0.5.8" +atty = { workspace = true } +clap = { workspace = true, features = ["derive"] } +codespan-reporting = { workspace = true } +itertools = { workspace = true } +log = { workspace = true, features = ["serde"] } +once_cell = { workspace = true } +serde = { workspace = true, features = ["derive"] } +simplelog = { workspace = true } +toml = { workspace = true } [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-prover-test-utils = { path = "test-utils" } -shell-words = "1.0.0" -tempfile = "3.2.0" -walkdir = "2.3.1" +shell-words = { workspace = true } +tempfile = { workspace = true } +walkdir = { workspace = true } [[test]] name = "testsuite" diff --git a/third_party/move/move-prover/boogie-backend/Cargo.toml b/third_party/move/move-prover/boogie-backend/Cargo.toml index 26ecc76876f38..690d070040639 100644 --- a/third_party/move/move-prover/boogie-backend/Cargo.toml +++ b/third_party/move/move-prover/boogie-backend/Cargo.toml @@ -8,13 +8,13 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -async-trait = "0.1.42" -codespan = "0.11.1" -codespan-reporting = "0.11.1" -futures = "0.3.12" -itertools = "0.10.0" -log = "0.4.14" +anyhow = { workspace = true } +async-trait = { workspace = true } +codespan = { workspace = true } +codespan-reporting = { workspace = true } +futures = { workspace = true } +itertools = { workspace = true } +log = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-command-line-common = { path = "../../move-command-line-common" } move-compiler = { path = "../../move-compiler" } @@ -22,11 +22,11 @@ move-core-types = { path = "../../move-core/types" } move-model = { path = "../../move-model" } move-prover-bytecode-pipeline = { path = "../bytecode-pipeline" } move-stackless-bytecode = { path = "../../move-model/bytecode" } -num = "0.4.0" -once_cell = "1.7.2" -pretty = "0.10.0" -rand = "0.8.3" -regex = "1.5.5" -serde = { version = "1.0.124", features = ["derive"] } -tera = "1.16.0" -tokio = { version = "1.18.2", features = ["full"] } +num = { workspace = true } +once_cell = { workspace = true } +pretty = { workspace = true } +rand = { workspace = true } +regex = { workspace = true } +serde = { workspace = true, features = ["derive"] } +tera = { workspace = true } +tokio = { workspace = true, features = ["full"] } diff --git a/third_party/move/move-prover/bytecode-pipeline/Cargo.toml b/third_party/move/move-prover/bytecode-pipeline/Cargo.toml index 2d90a8858bbbf..4a0fc40b37588 100644 --- a/third_party/move/move-prover/bytecode-pipeline/Cargo.toml +++ b/third_party/move/move-prover/bytecode-pipeline/Cargo.toml @@ -8,7 +8,7 @@ license = "Apache-2.0" [dependencies] abstract-domain-derive = { path = "../../move-model/bytecode/abstract_domain_derive" } -anyhow = "1.0.52" +anyhow = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-core-types = { path = "../../move-core/types" } move-model = { path = "../../move-model" } @@ -17,17 +17,17 @@ move-model = { path = "../../move-model" } move-stackless-bytecode = { path = "../../move-model/bytecode" } # external dependencies -codespan-reporting = "0.11.1" -itertools = "0.10.0" -log = { version = "0.4.14", features = ["serde"] } -serde = { version = "1.0.124", features = ["derive"] } +codespan-reporting = { workspace = true } +itertools = { workspace = true } +log = { workspace = true, features = ["serde"] } +serde = { workspace = true, features = ["derive"] } [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-stackless-bytecode-test-utils = { path = "../../move-model/bytecode-test-utils" } -shell-words = "1.0.0" -tempfile = "3.2.0" -walkdir = "2.3.1" +shell-words = { workspace = true } +tempfile = { workspace = true } +walkdir = { workspace = true } [[test]] name = "testsuite" diff --git a/third_party/move/move-prover/lab/Cargo.toml b/third_party/move/move-prover/lab/Cargo.toml index db173188a62a5..58d250941ebd0 100644 --- a/third_party/move/move-prover/lab/Cargo.toml +++ b/third_party/move/move-prover/lab/Cargo.toml @@ -15,16 +15,16 @@ move-prover-boogie-backend = { path = "../boogie-backend" } move-prover-bytecode-pipeline = { path = "../bytecode-pipeline" } # FB external dependencies -z3tracer = "0.8.0" +z3tracer = { workspace = true } # external dependencies -anyhow = "1.0.52" -chrono = "0.4.19" -clap = { version = "4.3.9", features = ["derive"] } -codespan-reporting = "0.11.1" -itertools = "0.10.0" -log = { version = "0.4.14", features = ["serde"] } -plotters = { version = "0.3.5", default_features = false, features = [ +anyhow = { workspace = true } +chrono = { workspace = true } +clap = { workspace = true, features = ["derive"] } +codespan-reporting = { workspace = true } +itertools = { workspace = true } +log = { workspace = true, features = ["serde"] } +plotters = { workspace = true, features = [ "evcxr", "line_series", "histogram", diff --git a/third_party/move/move-prover/move-abigen/Cargo.toml b/third_party/move/move-prover/move-abigen/Cargo.toml index 0c745b41b8e03..d33e3f5de01e9 100644 --- a/third_party/move/move-prover/move-abigen/Cargo.toml +++ b/third_party/move/move-prover/move-abigen/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "Apache-2.0" [dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-bytecode-verifier = { path = "../../move-bytecode-verifier" } move-command-line-common = { path = "../../move-command-line-common" } @@ -16,18 +16,18 @@ move-core-types = { path = "../../move-core/types" } move-model = { path = "../../move-model" } bcs = { workspace = true } -heck = "0.3.2" +heck = { workspace = true } # external dependencies -log = "0.4.14" -serde = { version = "1.0.124", features = ["derive"] } +log = { workspace = true } +serde = { workspace = true, features = ["derive"] } [dev-dependencies] -codespan-reporting = "0.11.1" -datatest-stable = "0.1.1" +codespan-reporting = { workspace = true } +datatest-stable = { workspace = true } move-prover = { path = ".." } move-prover-test-utils = { path = "../test-utils" } -tempfile = "3.2.0" +tempfile = { workspace = true } [[test]] name = "testsuite" diff --git a/third_party/move/move-prover/move-abigen/src/abigen.rs b/third_party/move/move-prover/move-abigen/src/abigen.rs index 5247778b2131a..e7d538d982bbe 100644 --- a/third_party/move/move-prover/move-abigen/src/abigen.rs +++ b/third_party/move/move-prover/move-abigen/src/abigen.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use anyhow::{anyhow, bail}; -use heck::SnakeCase; +use heck::ToSnakeCase; #[allow(unused_imports)] use log::{debug, info, warn}; use move_binary_format::{file_format::Ability, CompiledModule}; diff --git a/third_party/move/move-prover/move-docgen/Cargo.toml b/third_party/move/move-prover/move-docgen/Cargo.toml index 52cc0d7866ff7..2b349b757ad5e 100644 --- a/third_party/move/move-prover/move-docgen/Cargo.toml +++ b/third_party/move/move-prover/move-docgen/Cargo.toml @@ -7,26 +7,26 @@ edition = "2021" license = "Apache-2.0" [dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } # diem dependencies move-compiler = { path = "../../move-compiler" } move-core-types = { path = "../../move-core/types" } move-model = { path = "../../move-model" } # external dependencies -codespan = "0.11.1" -codespan-reporting = "0.11.1" -itertools = "0.10.0" -log = "0.4.14" -once_cell = "1.7.2" -regex = "1.5.5" -serde = { version = "1.0.124", features = ["derive"] } +codespan = { workspace = true } +codespan-reporting = { workspace = true } +itertools = { workspace = true } +log = { workspace = true } +once_cell = { workspace = true } +regex = { workspace = true } +serde = { workspace = true, features = ["derive"] } [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-prover = { path = ".." } move-prover-test-utils = { path = "../test-utils" } -tempfile = "3.2.0" +tempfile = { workspace = true } [[test]] name = "testsuite" diff --git a/third_party/move/move-prover/move-errmapgen/Cargo.toml b/third_party/move/move-prover/move-errmapgen/Cargo.toml index 8f33c7eb7e8ce..6b726107fbf97 100644 --- a/third_party/move/move-prover/move-errmapgen/Cargo.toml +++ b/third_party/move/move-prover/move-errmapgen/Cargo.toml @@ -7,16 +7,16 @@ edition = "2021" license = "Apache-2.0" [dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } # Move dependencies move-command-line-common = { path = "../../move-command-line-common" } move-core-types = { path = "../../move-core/types" } move-model = { path = "../../move-model" } # external dependencies -serde = { version = "1.0.124", features = ["derive"] } +serde = { workspace = true, features = ["derive"] } [dev-dependencies] -codespan-reporting = "0.11.1" -datatest-stable = "0.1.1" +codespan-reporting = { workspace = true } +datatest-stable = { workspace = true } move-prover = { path = ".." } diff --git a/third_party/move/move-prover/src/cli.rs b/third_party/move/move-prover/src/cli.rs index e1accbf68063c..f21cc3f082482 100644 --- a/third_party/move/move-prover/src/cli.rs +++ b/third_party/move/move-prover/src/cli.rs @@ -11,11 +11,14 @@ use clap::{builder::PossibleValuesParser, Arg, ArgAction, ArgAction::SetTrue, Co use codespan_reporting::diagnostic::Severity; use log::LevelFilter; use move_abigen::AbigenOptions; +use move_command_line_common::env::{bool_to_str, get_move_compiler_v2_from_env}; use move_compiler::{command_line::SKIP_ATTRIBUTE_CHECKS, shared::NumericalAddress}; use move_docgen::DocgenOptions; use move_errmapgen::ErrmapOptions; use move_model::{ - metadata::LanguageVersion, model::VerificationScope, options::ModelBuilderOptions, + metadata::{CompilerVersion, LanguageVersion}, + model::VerificationScope, + options::ModelBuilderOptions, }; use move_prover_boogie_backend::options::{BoogieOptions, CustomNativeOptions, VectorTheory}; use move_prover_bytecode_pipeline::options::{AutoTraceLevel, ProverOptions}; @@ -108,7 +111,10 @@ impl Default for Options { errmapgen: ErrmapOptions::default(), experimental_pipeline: false, skip_attribute_checks: false, - compiler_v2: false, + compiler_v2: match CompilerVersion::default() { + CompilerVersion::V1 => false, + CompilerVersion::V2_0 => true, + }, language_version: None, } } @@ -173,7 +179,7 @@ impl Options { .arg( Arg::new("compiler-v2") .long("compiler-v2") - .env("MOVE_COMPILER_V2") + .default_value(bool_to_str(get_move_compiler_v2_from_env())) .action(SetTrue) .help("whether to use Move compiler v2 to compile to bytecode") ) diff --git a/third_party/move/move-prover/src/lib.rs b/third_party/move/move-prover/src/lib.rs index 6094ad9f8ff2a..f5d5c00a7943b 100644 --- a/third_party/move/move-prover/src/lib.rs +++ b/third_party/move/move-prover/src/lib.rs @@ -138,8 +138,6 @@ pub fn run_move_prover_with_model_v2( options: Options, start_time: Instant, ) -> anyhow::Result<()> { - debug!("global env before prover run:\n{}", env.dump_env_all()); - let build_duration = start_time.elapsed(); check_errors( env, diff --git a/third_party/move/move-prover/test-utils/Cargo.toml b/third_party/move/move-prover/test-utils/Cargo.toml index 826d7c71061c3..576de1ab67db2 100644 --- a/third_party/move/move-prover/test-utils/Cargo.toml +++ b/third_party/move/move-prover/test-utils/Cargo.toml @@ -7,7 +7,7 @@ publish = false license = "Apache-2.0" [dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } move-command-line-common = { path = "../../move-command-line-common" } -prettydiff = { version = "0.6.2", default-features = false } -regex = "1.5.5" +prettydiff = { workspace = true } +regex = { workspace = true } diff --git a/third_party/move/move-stdlib/Cargo.toml b/third_party/move/move-stdlib/Cargo.toml index 273203ee295a0..6d643779e4db5 100644 --- a/third_party/move/move-stdlib/Cargo.toml +++ b/third_party/move/move-stdlib/Cargo.toml @@ -11,9 +11,9 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.52" -hex = "0.4.3" -log = "0.4.14" +anyhow = { workspace = true } +hex = { workspace = true } +log = { workspace = true } move-binary-format = { path = "../move-binary-format" } move-command-line-common = { path = "../move-command-line-common" } move-compiler = { path = "../move-compiler" } @@ -23,18 +23,18 @@ move-errmapgen = { path = "../move-prover/move-errmapgen" } move-prover = { path = "../move-prover" } move-vm-runtime = { path = "../move-vm/runtime" } move-vm-types = { path = "../move-vm/types" } -sha2 = "0.9.3" -sha3 = "0.9.1" -smallvec = "1.6.1" -walkdir = "2.3.1" +sha2 = { workspace = true } +sha3 = { workspace = true } +smallvec = { workspace = true } +walkdir = { workspace = true } [dev-dependencies] -dir-diff = "0.3.2" -file_diff = "1.0.0" +dir-diff = { workspace = true } +file_diff = { workspace = true } move-cli = { path = "../tools/move-cli" } move-package = { path = "../tools/move-package" } move-unit-test = { path = "../tools/move-unit-test" } -tempfile = "3.2.0" +tempfile = { workspace = true } [features] testing = [] diff --git a/third_party/move/move-stdlib/src/lib.rs b/third_party/move/move-stdlib/src/lib.rs index e4c3b4e133b3b..a956971b9641f 100644 --- a/third_party/move/move-stdlib/src/lib.rs +++ b/third_party/move/move-stdlib/src/lib.rs @@ -72,6 +72,10 @@ pub fn move_stdlib_named_addresses() -> BTreeMap { .collect() } +pub fn move_stdlib_named_addresses_strings() -> Vec { + vec!["std=0x1".to_string()] +} + pub fn build_doc( output_path: &str, doc_path: &str, diff --git a/third_party/move/move-symbol-pool/Cargo.toml b/third_party/move/move-symbol-pool/Cargo.toml index 92278fb6db014..9096856fb24ff 100644 --- a/third_party/move/move-symbol-pool/Cargo.toml +++ b/third_party/move/move-symbol-pool/Cargo.toml @@ -10,11 +10,11 @@ publish = false edition = "2021" [dependencies] -once_cell = "1.7.2" -serde = { version = "1.0.124", features = ["derive"] } +once_cell = { workspace = true } +serde = { workspace = true, features = ["derive"] } [dev-dependencies] -serde_json = { version = "1.0.64" } +serde_json = { workspace = true } [features] default = [] diff --git a/third_party/move/move-vm/integration-tests/Cargo.toml b/third_party/move/move-vm/integration-tests/Cargo.toml index 337acff7dc586..86d4016f23e9d 100644 --- a/third_party/move/move-vm/integration-tests/Cargo.toml +++ b/third_party/move/move-vm/integration-tests/Cargo.toml @@ -11,13 +11,14 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.52" -bytes = "1.4.0" -memory-stats = "1.0.0" +anyhow = { workspace = true } +bytes = { workspace = true } +memory-stats = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-bytecode-verifier = { path = "../../move-bytecode-verifier" } move-compiler = { path = "../../move-compiler" } -tempfile = "3.2.0" +smallvec = { workspace = true } +tempfile = { workspace = true } move-core-types = { path = "../../move-core/types" } move-stdlib = { path = "../../move-stdlib" } diff --git a/third_party/move/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs index 811c270e8f954..173348478080d 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs @@ -10,7 +10,7 @@ use move_core_types::{ value::{serialize_values, MoveValue}, vm_status::StatusType, }; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::{BlankStorage, InMemoryStorage}; use move_vm_types::gas::UnmeteredGasMeter; @@ -24,6 +24,7 @@ fn call_non_existent_module() { let mut sess = vm.new_session(&storage); let module_id = ModuleId::new(TEST_ADDR, Identifier::new("M").unwrap()); let fun_name = Identifier::new("foo").unwrap(); + let traversal_storage = TraversalStorage::new(); let err = sess .execute_function_bypass_visibility( @@ -32,6 +33,7 @@ fn call_non_existent_module() { vec![], serialize_values(&vec![MoveValue::Signer(TEST_ADDR)]), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); @@ -59,6 +61,8 @@ fn call_non_existent_function() { let fun_name = Identifier::new("foo").unwrap(); + let storage = TraversalStorage::new(); + let err = sess .execute_function_bypass_visibility( &module_id, @@ -66,6 +70,7 @@ fn call_non_existent_function() { vec![], serialize_values(&vec![MoveValue::Signer(TEST_ADDR)]), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&storage), ) .unwrap_err(); diff --git a/third_party/move/move-vm/integration-tests/src/tests/bad_storage_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/bad_storage_tests.rs index b37a672f9317e..c31c649fbb377 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/bad_storage_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/bad_storage_tests.rs @@ -15,7 +15,7 @@ use move_core_types::{ value::{serialize_values, MoveTypeLayout, MoveValue}, vm_status::{StatusCode, StatusType}, }; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::{DeltaStorage, InMemoryStorage}; use move_vm_types::gas::UnmeteredGasMeter; @@ -96,11 +96,13 @@ fn test_malformed_resource() { let mut script_blob = vec![]; s1.serialize(&mut script_blob).unwrap(); let mut sess = vm.new_session(&storage); + let traversal_storage = TraversalStorage::new(); sess.execute_script( script_blob, vec![], vec![MoveValue::Signer(TEST_ADDR).simple_serialize().unwrap()], &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .map(|_| ()) .unwrap(); @@ -119,6 +121,7 @@ fn test_malformed_resource() { vec![], vec![MoveValue::Signer(TEST_ADDR).simple_serialize().unwrap()], &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .map(|_| ()) .unwrap(); @@ -146,6 +149,7 @@ fn test_malformed_resource() { vec![], vec![MoveValue::Signer(TEST_ADDR).simple_serialize().unwrap()], &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .map(|_| ()) .unwrap_err(); @@ -172,6 +176,7 @@ fn test_malformed_module() { let module_id = ModuleId::new(TEST_ADDR, Identifier::new("M").unwrap()); let fun_name = Identifier::new("foo").unwrap(); + let traversal_storage = TraversalStorage::new(); // Publish M and call M::foo. No errors should be thrown. { @@ -185,6 +190,7 @@ fn test_malformed_module() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); } @@ -211,6 +217,7 @@ fn test_malformed_module() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); assert_eq!(err.status_type(), StatusType::InvariantViolation); @@ -232,6 +239,7 @@ fn test_unverifiable_module() { let module_id = ModuleId::new(TEST_ADDR, Identifier::new("M").unwrap()); let fun_name = Identifier::new("foo").unwrap(); + let traversal_storage = TraversalStorage::new(); // Publish M and call M::foo to make sure it works. { @@ -250,6 +258,7 @@ fn test_unverifiable_module() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); } @@ -275,6 +284,7 @@ fn test_unverifiable_module() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); @@ -308,6 +318,7 @@ fn test_missing_module_dependency() { let module_id = ModuleId::new(TEST_ADDR, Identifier::new("N").unwrap()); let fun_name = Identifier::new("bar").unwrap(); + let traversal_storage = TraversalStorage::new(); // Publish M and N and call N::bar. Everything should work. { @@ -325,6 +336,7 @@ fn test_missing_module_dependency() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); } @@ -345,6 +357,7 @@ fn test_missing_module_dependency() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); @@ -378,6 +391,7 @@ fn test_malformed_module_dependency() { let module_id = ModuleId::new(TEST_ADDR, Identifier::new("N").unwrap()); let fun_name = Identifier::new("bar").unwrap(); + let traversal_storage = TraversalStorage::new(); // Publish M and N and call N::bar. Everything should work. { @@ -395,6 +409,7 @@ fn test_malformed_module_dependency() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); } @@ -421,6 +436,7 @@ fn test_malformed_module_dependency() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); @@ -452,6 +468,7 @@ fn test_unverifiable_module_dependency() { let module_id = ModuleId::new(TEST_ADDR, Identifier::new("N").unwrap()); let fun_name = Identifier::new("bar").unwrap(); + let traversal_storage = TraversalStorage::new(); // Publish M and N and call N::bar. Everything should work. { @@ -472,6 +489,7 @@ fn test_unverifiable_module_dependency() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); } @@ -498,6 +516,7 @@ fn test_unverifiable_module_dependency() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); @@ -549,6 +568,7 @@ const LIST_OF_ERROR_CODES: &[StatusCode] = &[ fn test_storage_returns_bogus_error_when_loading_module() { let module_id = ModuleId::new(TEST_ADDR, Identifier::new("N").unwrap()); let fun_name = Identifier::new("bar").unwrap(); + let traversal_storage = TraversalStorage::new(); for error_code in LIST_OF_ERROR_CODES { let storage = BogusStorage { @@ -564,6 +584,7 @@ fn test_storage_returns_bogus_error_when_loading_module() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); @@ -616,6 +637,7 @@ fn test_storage_returns_bogus_error_when_loading_resource() { let m_id = m.self_id(); let foo_name = Identifier::new("foo").unwrap(); let bar_name = Identifier::new("bar").unwrap(); + let traversal_storage = TraversalStorage::new(); for error_code in LIST_OF_ERROR_CODES { let storage = BogusStorage { @@ -636,6 +658,7 @@ fn test_storage_returns_bogus_error_when_loading_resource() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); @@ -646,6 +669,7 @@ fn test_storage_returns_bogus_error_when_loading_resource() { vec![], serialize_values(&vec![MoveValue::Signer(TEST_ADDR)]), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); diff --git a/third_party/move/move-vm/integration-tests/src/tests/binary_format_version.rs b/third_party/move/move-vm/integration-tests/src/tests/binary_format_version.rs index d541881c4881e..35338dca36c41 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/binary_format_version.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/binary_format_version.rs @@ -7,7 +7,7 @@ use move_binary_format::{ file_format_common::{IDENTIFIER_SIZE_MAX, VERSION_MAX}, }; use move_core_types::{account_address::AccountAddress, vm_status::StatusCode}; -use move_vm_runtime::{config::VMConfig, move_vm::MoveVM}; +use move_vm_runtime::{config::VMConfig, module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; @@ -94,6 +94,7 @@ fn test_run_script_with_custom_max_binary_format_version() { .unwrap(); s.serialize_for_version(Some(VERSION_MAX.checked_sub(1).unwrap()), &mut b_old) .unwrap(); + let traversal_storage = TraversalStorage::new(); // Should accept both modules with the default settings { @@ -106,11 +107,23 @@ fn test_run_script_with_custom_max_binary_format_version() { let mut sess = vm.new_session(&storage); let args: Vec> = vec![]; - sess.execute_script(b_new.clone(), vec![], args.clone(), &mut UnmeteredGasMeter) - .unwrap(); + sess.execute_script( + b_new.clone(), + vec![], + args.clone(), + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + ) + .unwrap(); - sess.execute_script(b_old.clone(), vec![], args, &mut UnmeteredGasMeter) - .unwrap(); + sess.execute_script( + b_old.clone(), + vec![], + args, + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + ) + .unwrap(); } // Should reject the module with newer version with max binary format version being set to VERSION_MAX - 1 @@ -134,13 +147,25 @@ fn test_run_script_with_custom_max_binary_format_version() { let args: Vec> = vec![]; assert_eq!( - sess.execute_script(b_new.clone(), vec![], args.clone(), &mut UnmeteredGasMeter) - .unwrap_err() - .major_status(), + sess.execute_script( + b_new.clone(), + vec![], + args.clone(), + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage) + ) + .unwrap_err() + .major_status(), StatusCode::CODE_DESERIALIZATION_ERROR ); - sess.execute_script(b_old.clone(), vec![], args, &mut UnmeteredGasMeter) - .unwrap(); + sess.execute_script( + b_old.clone(), + vec![], + args, + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + ) + .unwrap(); } } diff --git a/third_party/move/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs index 725fd9d540acb..398a29d81daa5 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs @@ -13,7 +13,7 @@ use move_core_types::{ value::{serialize_values, MoveValue}, vm_status::StatusCode, }; -use move_vm_runtime::{move_vm::MoveVM, session::SerializedReturnValues}; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM, session::SerializedReturnValues}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; use std::convert::TryInto; @@ -96,6 +96,7 @@ fn run( let mut session = vm.new_session(&storage); let fun_name = Identifier::new(fun_name).unwrap(); + let traversal_storage = TraversalStorage::new(); session .execute_function_bypass_visibility( @@ -104,6 +105,7 @@ fn run( vec![], serialize_values(&vec![arg_val0]), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .and_then(|ret_values| { let change_set = session.finish()?; diff --git a/third_party/move/move-vm/integration-tests/src/tests/function_arg_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/function_arg_tests.rs index ef6778fdca26e..ccd55169ff6c7 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/function_arg_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/function_arg_tests.rs @@ -12,7 +12,7 @@ use move_core_types::{ value::{MoveStruct, MoveValue}, vm_status::StatusCode, }; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; @@ -63,6 +63,7 @@ fn run( let mut sess = vm.new_session(&storage); let fun_name = Identifier::new("foo").unwrap(); + let traversal_storage = TraversalStorage::new(); let args: Vec<_> = args .into_iter() @@ -75,6 +76,7 @@ fn run( ty_args, args, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), )?; Ok(()) diff --git a/third_party/move/move-vm/integration-tests/src/tests/instantiation_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/instantiation_tests.rs index e1ef7c5a7febb..761b63f52bf22 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/instantiation_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/instantiation_tests.rs @@ -15,7 +15,7 @@ use move_core_types::{ language_storage::{StructTag, TypeTag}, vm_status::StatusCode, }; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::{gas_schedule::GasStatus, InMemoryStorage}; #[test] @@ -106,6 +106,7 @@ fn instantiation_err() { let mut session = vm.new_session(&storage); let mut mod_bytes = vec![]; cm.serialize(&mut mod_bytes).unwrap(); + let traversal_storage = TraversalStorage::new(); session .publish_module(mod_bytes, addr, &mut GasStatus::new_unmetered()) @@ -128,6 +129,7 @@ fn instantiation_err() { vec![ty_arg], Vec::>::new(), &mut GasStatus::new_unmetered(), + &mut TraversalContext::new(&traversal_storage), ); assert!(err.is_err(), "Instantiation must fail at runtime"); assert_eq!( diff --git a/third_party/move/move-vm/integration-tests/src/tests/invariant_violation_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/invariant_violation_tests.rs index b91f72ac47171..cb48d3a6dc015 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/invariant_violation_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/invariant_violation_tests.rs @@ -6,7 +6,7 @@ use move_binary_format::file_format::{ SignatureToken::*, }; use move_core_types::vm_status::StatusCode; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::{gas_schedule::GasStatus, InMemoryStorage}; #[test] @@ -76,6 +76,7 @@ fn merge_borrow_states_infinite_loop() { let mut session = vm.new_session(&storage); let mut script_bytes = vec![]; cs.serialize(&mut script_bytes).unwrap(); + let traversal_storage = TraversalStorage::new(); let err = session .execute_script( @@ -83,6 +84,7 @@ fn merge_borrow_states_infinite_loop() { vec![], Vec::>::new(), &mut GasStatus::new_unmetered(), + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); diff --git a/third_party/move/move-vm/integration-tests/src/tests/leak_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/leak_tests.rs index 6a23b80555b3a..3d6673d6b37fc 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/leak_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/leak_tests.rs @@ -4,7 +4,7 @@ use move_binary_format::file_format::{ Bytecode::*, CodeUnit, CompiledScript, Signature, SignatureIndex, SignatureToken::*, }; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::{gas_schedule::GasStatus, InMemoryStorage}; #[ignore] // TODO: figure whether to reactive this test @@ -51,6 +51,7 @@ fn leak_with_abort() { let mut session = vm.new_session(&storage); let mut script_bytes = vec![]; cs.serialize(&mut script_bytes).unwrap(); + let traversal_storage = TraversalStorage::new(); for _ in 0..100_000 { let _ = session.execute_script( @@ -58,6 +59,7 @@ fn leak_with_abort() { vec![], Vec::>::new(), &mut GasStatus::new_unmetered(), + &mut TraversalContext::new(&traversal_storage), ); } diff --git a/third_party/move/move-vm/integration-tests/src/tests/loader_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/loader_tests.rs index a75eaf719f6bd..52b5ca2251317 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/loader_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/loader_tests.rs @@ -16,7 +16,7 @@ use move_core_types::{ identifier::{IdentStr, Identifier}, language_storage::ModuleId, }; -use move_vm_runtime::{config::VMConfig, move_vm::MoveVM}; +use move_vm_runtime::{config::VMConfig, module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; use std::{path::PathBuf, sync::Arc, thread}; @@ -128,6 +128,7 @@ impl Adapter { let data_store = self.store.clone(); children.push(thread::spawn(move || { let mut session = vm.new_session(&data_store); + let traversal_storage = TraversalStorage::new(); session .execute_function_bypass_visibility( &module_id, @@ -135,6 +136,7 @@ impl Adapter { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_or_else(|_| { panic!("Failure executing {:?}::{:?}", module_id, name) @@ -149,6 +151,7 @@ impl Adapter { fn call_function(&self, module: &ModuleId, name: &IdentStr) { let mut session = self.vm.new_session(&self.store); + let traversal_storage = TraversalStorage::new(); session .execute_function_bypass_visibility( module, @@ -156,6 +159,7 @@ impl Adapter { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_or_else(|_| panic!("Failure executing {:?}::{:?}", module, name)); } diff --git a/third_party/move/move-vm/integration-tests/src/tests/mod.rs b/third_party/move/move-vm/integration-tests/src/tests/mod.rs index 2a5111d77160d..23ca581ad7e71 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/mod.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/mod.rs @@ -16,4 +16,5 @@ mod native_tests; mod nested_loop_tests; mod regression_tests; mod return_value_tests; +mod runtime_reentrancy_check_tests; mod vm_arguments_tests; diff --git a/third_party/move/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs index 18182f4898ee0..bb1e55fa85fc0 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs @@ -9,7 +9,7 @@ use move_core_types::{ language_storage::ModuleId, value::{serialize_values, MoveValue}, }; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; @@ -51,6 +51,7 @@ fn mutated_accounts() { let get = Identifier::new("get").unwrap(); let account1 = AccountAddress::random(); + let traversal_storage = TraversalStorage::new(); sess.execute_function_bypass_visibility( &module_id, @@ -58,6 +59,7 @@ fn mutated_accounts() { vec![], serialize_values(&vec![MoveValue::Signer(account1)]), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); @@ -72,6 +74,7 @@ fn mutated_accounts() { vec![], serialize_values(&vec![MoveValue::Address(account1)]), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); @@ -83,6 +86,7 @@ fn mutated_accounts() { vec![], serialize_values(&vec![MoveValue::Address(account1)]), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); assert_eq!(sess.num_mutated_accounts(&TEST_ADDR), 2); @@ -97,6 +101,7 @@ fn mutated_accounts() { vec![], serialize_values(&vec![MoveValue::Address(account1)]), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap(); diff --git a/third_party/move/move-vm/integration-tests/src/tests/native_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/native_tests.rs index c95fc0f6f2c21..e42618e5a4e17 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/native_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/native_tests.rs @@ -7,7 +7,9 @@ use move_bytecode_verifier::VerifierConfig; use move_core_types::{ account_address::AccountAddress, gas_algebra::InternalGas, identifier::Identifier, }; -use move_vm_runtime::{config::VMConfig, move_vm::MoveVM, native_functions::NativeFunction}; +use move_vm_runtime::{ + config::VMConfig, module_traversal::*, move_vm::MoveVM, native_functions::NativeFunction, +}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::{gas::UnmeteredGasMeter, natives::function::NativeResult}; use std::sync::Arc; @@ -50,6 +52,7 @@ fn test_publish_module_with_nested_loops() { let m = as_module(units.pop().unwrap()); let mut m_blob = vec![]; m.serialize(&mut m_blob).unwrap(); + let traversal_storage = TraversalStorage::new(); // Should succeed with max_loop_depth = 2 { @@ -81,6 +84,7 @@ fn test_publish_module_with_nested_loops() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); @@ -93,6 +97,7 @@ fn test_publish_module_with_nested_loops() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); diff --git a/third_party/move/move-vm/integration-tests/src/tests/nested_loop_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/nested_loop_tests.rs index 0d79ddd868d9c..8b8e1c86ae692 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/nested_loop_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/nested_loop_tests.rs @@ -4,7 +4,7 @@ use crate::compiler::{as_module, as_script, compile_units}; use move_bytecode_verifier::VerifierConfig; use move_core_types::account_address::AccountAddress; -use move_vm_runtime::{config::VMConfig, move_vm::MoveVM}; +use move_vm_runtime::{config::VMConfig, module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; @@ -106,6 +106,7 @@ fn test_run_script_with_nested_loops() { let s = as_script(units.pop().unwrap()); let mut s_blob: Vec = vec![]; s.serialize(&mut s_blob).unwrap(); + let traversal_storage = TraversalStorage::new(); // Should succeed with max_loop_depth = 2 { @@ -127,8 +128,14 @@ fn test_run_script_with_nested_loops() { let mut sess = vm.new_session(&storage); let args: Vec> = vec![]; - sess.execute_script(s_blob.clone(), vec![], args, &mut UnmeteredGasMeter) - .unwrap(); + sess.execute_script( + s_blob.clone(), + vec![], + args, + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + ) + .unwrap(); } // Should fail with max_loop_depth = 1 @@ -151,7 +158,13 @@ fn test_run_script_with_nested_loops() { let mut sess = vm.new_session(&storage); let args: Vec> = vec![]; - sess.execute_script(s_blob, vec![], args, &mut UnmeteredGasMeter) - .unwrap_err(); + sess.execute_script( + s_blob, + vec![], + args, + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + ) + .unwrap_err(); } } diff --git a/third_party/move/move-vm/integration-tests/src/tests/regression_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/regression_tests.rs index 3befb1eba0a67..b990b9283b94b 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/regression_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/regression_tests.rs @@ -10,7 +10,7 @@ use move_core_types::{ language_storage::{StructTag, TypeTag}, vm_status::StatusCode, }; -use move_vm_runtime::{config::VMConfig, move_vm::MoveVM}; +use move_vm_runtime::{config::VMConfig, module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; use std::time::Instant; @@ -132,12 +132,14 @@ fn script_large_ty() { ); let mut session = move_vm.new_session(&storage); + let traversal_storage = TraversalStorage::new(); let res = session .execute_script( script.as_ref(), vec![input_type], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .unwrap_err(); diff --git a/third_party/move/move-vm/integration-tests/src/tests/return_value_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/return_value_tests.rs index a8702a766ad0d..b23e3d72faaa4 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/return_value_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/return_value_tests.rs @@ -10,7 +10,7 @@ use move_core_types::{ language_storage::{ModuleId, TypeTag}, value::{MoveTypeLayout, MoveValue}, }; -use move_vm_runtime::{move_vm::MoveVM, session::SerializedReturnValues}; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM, session::SerializedReturnValues}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; @@ -59,6 +59,7 @@ fn run( .into_iter() .map(|val| val.simple_serialize().unwrap()) .collect(); + let traversal_storage = TraversalStorage::new(); let SerializedReturnValues { return_values, @@ -69,6 +70,7 @@ fn run( ty_args, args, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), )?; Ok(return_values diff --git a/third_party/move/move-vm/integration-tests/src/tests/runtime_reentrancy_check_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/runtime_reentrancy_check_tests.rs new file mode 100644 index 0000000000000..463a724766c48 --- /dev/null +++ b/third_party/move/move-vm/integration-tests/src/tests/runtime_reentrancy_check_tests.rs @@ -0,0 +1,211 @@ +// Copyright (c) The Diem Core Contributors +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +use crate::compiler::{as_module, compile_units}; +use move_binary_format::errors::PartialVMResult; +use move_core_types::{ + account_address::AccountAddress, gas_algebra::GasQuantity, identifier::Identifier, + language_storage::ModuleId, vm_status::StatusCode, +}; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM, native_functions::NativeFunction}; +use move_vm_test_utils::InMemoryStorage; +use move_vm_types::{gas::UnmeteredGasMeter, natives::function::NativeResult}; +use smallvec::SmallVec; +use std::sync::Arc; +const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGTH]); + +fn make_load_c() -> NativeFunction { + Arc::new(move |_, _, _| -> PartialVMResult { + Ok(NativeResult::LoadModule { + module_name: ModuleId::new(TEST_ADDR, Identifier::new("C").unwrap()), + }) + }) +} + +fn make_dispatch_native() -> NativeFunction { + Arc::new(move |_, _, _| -> PartialVMResult { + Ok(NativeResult::CallFunction { + cost: GasQuantity::zero(), + module_name: ModuleId::new(TEST_ADDR, Identifier::new("A").unwrap()), + func_name: Identifier::new("foo").unwrap(), + ty_args: vec![], + args: SmallVec::new(), + }) + }) +} + +fn make_dispatch_c_native() -> NativeFunction { + Arc::new(move |_, _, _| -> PartialVMResult { + Ok(NativeResult::CallFunction { + cost: GasQuantity::zero(), + module_name: ModuleId::new(TEST_ADDR, Identifier::new("C").unwrap()), + func_name: Identifier::new("foo").unwrap(), + ty_args: vec![], + args: SmallVec::new(), + }) + }) +} + +fn make_dispatch_d_native() -> NativeFunction { + Arc::new(move |_, _, _| -> PartialVMResult { + Ok(NativeResult::CallFunction { + cost: GasQuantity::zero(), + module_name: ModuleId::new(TEST_ADDR, Identifier::new("D").unwrap()), + func_name: Identifier::new("foo3").unwrap(), + ty_args: vec![], + args: SmallVec::new(), + }) + }) +} + +fn compile_and_publish(storage: &mut InMemoryStorage, code: String) { + let mut units = compile_units(&code).unwrap(); + let m = as_module(units.pop().unwrap()); + let mut blob = vec![]; + m.serialize(&mut blob).unwrap(); + storage.publish_or_overwrite_module(m.self_id(), blob); +} + +#[test] +fn runtime_reentrancy_check() { + let mut storage = InMemoryStorage::new(); + + let code_1 = format!( + r#" + module 0x{0}::B {{ + public fun foo1() {{ Self::dispatch(0); return }} + public fun foo2() {{ Self::load_c(); Self::dispatch_c(0); return }} + public fun foo3() {{ Self::dispatch_d(0); return }} + + native fun dispatch(_f: u64); + native fun dispatch_c(_f: u64); + native fun dispatch_d(_f: u64); + native fun load_c(); + }} +"#, + TEST_ADDR.to_hex(), + ); + + compile_and_publish(&mut storage, code_1); + + let code_2 = format!( + r#" + module 0x{0}::A {{ + use 0x{0}::B; + public fun foo1() {{ B::foo1(); return }} + public fun foo2() {{ B::foo2(); return }} + public fun foo3() {{ B::foo3(); return }} + + public fun foo() {{ return }} + }} + module 0x{0}::B {{ + public fun foo1() {{ Self::dispatch(0); return }} + public fun foo2() {{ Self::load_c(); Self::dispatch_c(0); return }} + public fun foo3() {{ Self::dispatch_d(0); return }} + + native fun dispatch(_f: u64); + native fun dispatch_c(_f: u64); + native fun dispatch_d(_f: u64); + native fun load_c(); + }} +"#, + TEST_ADDR.to_hex(), + ); + + compile_and_publish(&mut storage, code_2); + + let code_3 = format!( + r#" + module 0x{0}::C {{ + public fun foo() {{ return }} + }} +"#, + TEST_ADDR.to_hex(), + ); + + compile_and_publish(&mut storage, code_3); + + let natives = vec![ + ( + TEST_ADDR, + Identifier::new("B").unwrap(), + Identifier::new("dispatch").unwrap(), + make_dispatch_native(), + ), + ( + TEST_ADDR, + Identifier::new("B").unwrap(), + Identifier::new("dispatch_c").unwrap(), + make_dispatch_c_native(), + ), + ( + TEST_ADDR, + Identifier::new("B").unwrap(), + Identifier::new("dispatch_d").unwrap(), + make_dispatch_d_native(), + ), + ( + TEST_ADDR, + Identifier::new("B").unwrap(), + Identifier::new("load_c").unwrap(), + make_load_c(), + ), + ]; + + let fun_name = Identifier::new("foo1").unwrap(); + let args: Vec> = vec![]; + let module_id = ModuleId::new(TEST_ADDR, Identifier::new("A").unwrap()); + + let vm = MoveVM::new(natives).unwrap(); + let mut sess = vm.new_session(&storage); + let traversal_storage = TraversalStorage::new(); + + // Call stack look like following: + // A::foo1 -> B::foo1 -> B::dispatch -> A::foo3, Re-entrancy happens at foo3. + assert_eq!( + sess.execute_function_bypass_visibility( + &module_id, + &fun_name, + vec![], + args.clone(), + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage) + ) + .unwrap_err() + .major_status(), + StatusCode::RUNTIME_DISPATCH_ERROR + ); + + // Call stack look like following: + // A::foo2 -> B::foo2 -> B::dispatch_c -> C::foo3, No reentrancy, executed successfully. + // + // Note that C needs to be loaded into module cache at runtime. + let fun_name = Identifier::new("foo2").unwrap(); + sess.execute_function_bypass_visibility( + &module_id, + &fun_name, + vec![], + args.clone(), + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), + ) + .unwrap(); + + // Call stack look like following: + // A::foo3 -> B::foo3 -> B::dispatch_d -> D::foo3, D doesn't exists, thus FUNCTION_RESOLUTION_FAILURE. + let fun_name = Identifier::new("foo3").unwrap(); + assert_eq!( + sess.execute_function_bypass_visibility( + &module_id, + &fun_name, + vec![], + args, + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage) + ) + .unwrap_err() + .major_status(), + StatusCode::FUNCTION_RESOLUTION_FAILURE + ); +} diff --git a/third_party/move/move-vm/integration-tests/src/tests/vm_arguments_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/vm_arguments_tests.rs index c1c1e280e2f50..5f3f1088c158c 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/vm_arguments_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/vm_arguments_tests.rs @@ -21,7 +21,7 @@ use move_core_types::{ value::{serialize_values, MoveValue}, vm_status::{StatusCode, StatusType}, }; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; @@ -250,12 +250,15 @@ fn call_script_with_args_ty_args_signers( let move_vm = MoveVM::new(vec![]).unwrap(); let remote_view = InMemoryStorage::new(); let mut session = move_vm.new_session(&remote_view); + let traversal_storage = TraversalStorage::new(); + session .execute_script( script, ty_args, combine_signers_and_args(signers, non_signer_args), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .map(|_| ()) } @@ -280,12 +283,14 @@ fn call_script_function_with_args_ty_args_signers( remote_view.publish_or_overwrite_module(module_id.clone(), module_blob); let mut session = move_vm.new_session(&remote_view); + let traversal_storage = TraversalStorage::new(); session.execute_function_bypass_visibility( &module_id, function_name.as_ident_str(), ty_args, combine_signers_and_args(signers, non_signer_args), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), )?; Ok(()) } @@ -774,6 +779,7 @@ fn call_missing_item() { let move_vm = MoveVM::new(vec![]).unwrap(); let mut remote_view = InMemoryStorage::new(); let mut session = move_vm.new_session(&remote_view); + let traversal_storage = TraversalStorage::new(); let error = session .execute_function_bypass_visibility( &module_id, @@ -781,6 +787,7 @@ fn call_missing_item() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .err() .unwrap(); @@ -796,6 +803,7 @@ fn call_missing_item() { // missing function remote_view.publish_or_overwrite_module(module_id.clone(), module_blob); let mut session = move_vm.new_session(&remote_view); + let traversal_storage = TraversalStorage::new(); let error = session .execute_function_bypass_visibility( &module_id, @@ -803,6 +811,7 @@ fn call_missing_item() { vec![], Vec::>::new(), &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), ) .err() .unwrap(); diff --git a/third_party/move/move-vm/paranoid-tests/Cargo.toml b/third_party/move/move-vm/paranoid-tests/Cargo.toml index 5442a6597e966..bf4e6bb08686f 100644 --- a/third_party/move/move-vm/paranoid-tests/Cargo.toml +++ b/third_party/move/move-vm/paranoid-tests/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" license = "Apache-2.0" [dev-dependencies] -datatest-stable = "0.1.1" -fail = { version = "0.4.0", features = ['failpoints'] } +datatest-stable = { workspace = true } +fail = { workspace = true, features = ['failpoints'] } move-transactional-test-runner = { path = "../../testing-infra/transactional-test-runner", features = ['failpoints'] } [[test]] diff --git a/third_party/move/move-vm/runtime/Cargo.toml b/third_party/move/move-vm/runtime/Cargo.toml index 1ab85d4c0872d..c3442e9691282 100644 --- a/third_party/move/move-vm/runtime/Cargo.toml +++ b/third_party/move/move-vm/runtime/Cargo.toml @@ -11,31 +11,31 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -better_any = "0.1.1" -bytes = "1.4.0" -fail = "0.4.0" -hashbrown = "0.14.3" -lazy_static = "1.4.0" -lru = "0.7.5" +better_any = { workspace = true } +bytes = { workspace = true } +fail = { workspace = true } +hashbrown = { workspace = true } +lazy_static = { workspace = true } +lru = { workspace = true } move-binary-format = { path = "../../move-binary-format" } -once_cell = "1.7.2" -parking_lot = "0.11.1" -serde = "1.0.149" -sha3 = "0.9.1" -tracing = "0.1.26" -triomphe = "0.1.9" -typed-arena = "2.0.2" +once_cell = { workspace = true } +parking_lot = { workspace = true } +serde = { workspace = true } +sha3 = { workspace = true } +tracing = { workspace = true } +triomphe = { workspace = true } +typed-arena = { workspace = true } move-bytecode-verifier = { path = "../../move-bytecode-verifier" } move-core-types = { path = "../../move-core/types" } move-vm-types = { path = "../types" } [dev-dependencies] -anyhow = "1.0.52" -hex = "0.4.3" +anyhow = { workspace = true } +hex = { workspace = true } move-compiler = { path = "../../move-compiler" } move-ir-compiler = { path = "../../move-ir-compiler" } -proptest = "1.0.0" +proptest = { workspace = true } [features] default = [] diff --git a/third_party/move/move-vm/runtime/src/interpreter.rs b/third_party/move/move-vm/runtime/src/interpreter.rs index c35dbaade8de6..87cc06e17f25f 100644 --- a/third_party/move/move-vm/runtime/src/interpreter.rs +++ b/third_party/move/move-vm/runtime/src/interpreter.rs @@ -6,6 +6,7 @@ use crate::{ access_control::AccessControlState, data_cache::TransactionDataCache, loader::{Function, Loader, ModuleStorageAdapter, Resolver}, + module_traversal::TraversalContext, native_extensions::NativeContextExtensions, native_functions::NativeContext, trace, @@ -21,7 +22,7 @@ use move_binary_format::{ use move_core_types::{ account_address::AccountAddress, gas_algebra::{NumArgs, NumBytes, NumTypeNodes}, - language_storage::TypeTag, + language_storage::{ModuleId, TypeTag}, vm_status::{StatusCode, StatusType}, }; use move_vm_types::{ @@ -40,7 +41,7 @@ use move_vm_types::{ }; use std::{ cmp::min, - collections::{BTreeMap, VecDeque}, + collections::{BTreeMap, HashSet, VecDeque}, fmt::Write, sync::Arc, }; @@ -65,6 +66,8 @@ pub(crate) struct Interpreter { paranoid_type_checks: bool, /// The access control state. access_control: AccessControlState, + /// Set of modules that exists on call stack. + active_modules: HashSet, } struct TypeWithLoader<'a, 'b> { @@ -88,6 +91,7 @@ impl Interpreter { data_store: &mut TransactionDataCache, module_store: &ModuleStorageAdapter, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, extensions: &mut NativeContextExtensions, loader: &Loader, ) -> VMResult> { @@ -96,12 +100,14 @@ impl Interpreter { call_stack: CallStack::new(), paranoid_type_checks: loader.vm_config().paranoid_type_checks, access_control: AccessControlState::default(), + active_modules: HashSet::new(), } .execute_main( loader, data_store, module_store, gas_meter, + traversal_context, extensions, function, ty_args, @@ -121,6 +127,7 @@ impl Interpreter { data_store: &mut TransactionDataCache, module_store: &ModuleStorageAdapter, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, extensions: &mut NativeContextExtensions, function: Arc, ty_args: Vec, @@ -139,9 +146,14 @@ impl Interpreter { .map_err(|e| self.set_location(e))?; } + if let Some(module_id) = function.module_id() { + self.active_modules.insert(module_id.clone()); + } + let mut current_frame = self .make_new_frame(gas_meter, loader, function, ty_args, locals) .map_err(|err| self.set_location(err))?; + // Access control for the new frame. self.access_control .enter_function(¤t_frame, current_frame.function.as_ref()) @@ -170,6 +182,11 @@ impl Interpreter { .map_err(|e| self.set_location(e))?; if let Some(frame) = self.call_stack.pop() { + if frame.function.module_id() != current_frame.function.module_id() { + if let Some(module_id) = current_frame.function.module_id() { + self.active_modules.remove(module_id); + } + } // Note: the caller will find the callee's return values at the top of the shared operand stack current_frame = frame; current_frame.pc += 1; // advance past the Call instruction in the caller @@ -212,37 +229,25 @@ impl Interpreter { if func.is_native() { self.call_native( + &mut current_frame, &resolver, data_store, + module_store, gas_meter, + traversal_context, extensions, func, vec![], )?; - current_frame.pc += 1; // advance past the Call instruction in the caller continue; } - let frame = self - .make_call_frame(gas_meter, loader, func, vec![]) + self.set_new_call_frame(&mut current_frame, gas_meter, loader, func, vec![]) .map_err(|err| { self.attach_state_if_invariant_violation( self.set_location(err), ¤t_frame, ) })?; - - // Access control for the new frame. - self.access_control - .enter_function(&frame, frame.function.as_ref()) - .map_err(|e| self.set_location(e))?; - - self.call_stack.push(current_frame).map_err(|frame| { - let err = PartialVMError::new(StatusCode::CALL_STACK_OVERFLOW); - let err = set_err_info!(frame, err); - self.attach_state_if_invariant_violation(err, &frame) - })?; - // Note: the caller will find the callee's return values at the top of the shared operand stack - current_frame = frame; }, ExitCode::CallGeneric(idx) => { let ty_args = resolver @@ -278,36 +283,69 @@ impl Interpreter { if func.is_native() { self.call_native( - &resolver, data_store, gas_meter, extensions, func, ty_args, + &mut current_frame, + &resolver, + data_store, + module_store, + gas_meter, + traversal_context, + extensions, + func, + ty_args, )?; - current_frame.pc += 1; // advance past the Call instruction in the caller continue; } - let frame = self - .make_call_frame(gas_meter, loader, func, ty_args) + self.set_new_call_frame(&mut current_frame, gas_meter, loader, func, ty_args) .map_err(|err| { self.attach_state_if_invariant_violation( self.set_location(err), ¤t_frame, ) })?; - - // Access control for the new frame. - self.access_control - .enter_function(&frame, frame.function.as_ref()) - .map_err(|e| self.set_location(e))?; - - self.call_stack.push(current_frame).map_err(|frame| { - let err = PartialVMError::new(StatusCode::CALL_STACK_OVERFLOW); - let err = set_err_info!(frame, err); - self.attach_state_if_invariant_violation(err, &frame) - })?; - current_frame = frame; }, } } } + fn set_new_call_frame( + &mut self, + current_frame: &mut Frame, + gas_meter: &mut impl GasMeter, + loader: &Loader, + func: Arc, + ty_args: Vec, + ) -> PartialVMResult<()> { + match (func.module_id(), current_frame.function.module_id()) { + (Some(module_id), Some(current_module_id)) if module_id != current_module_id => { + if self.active_modules.contains(module_id) { + return Err(PartialVMError::new(StatusCode::RUNTIME_DISPATCH_ERROR) + .with_message(format!( + "Re-entrancy detected: {} already exists on top of the stack", + module_id + ))); + } + self.active_modules.insert(module_id.clone()); + }, + (Some(module_id), None) => { + self.active_modules.insert(module_id.clone()); + }, + _ => (), + } + + let mut frame = self.make_call_frame(gas_meter, loader, func, ty_args)?; + + // Access control for the new frame. + self.access_control + .enter_function(&frame, frame.function.as_ref())?; + + std::mem::swap(current_frame, &mut frame); + self.call_stack + .push(frame) + .map_err(|_| PartialVMError::new(StatusCode::CALL_STACK_OVERFLOW))?; + + Ok(()) + } + /// Returns a `Frame` if the call is to a Move function. Calls to native functions are /// "inlined" and this returns `None`. /// @@ -392,18 +430,24 @@ impl Interpreter { /// Call a native functions. fn call_native( &mut self, + current_frame: &mut Frame, resolver: &Resolver, data_store: &mut TransactionDataCache, + module_store: &ModuleStorageAdapter, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, extensions: &mut NativeContextExtensions, function: Arc, ty_args: Vec, ) -> VMResult<()> { // Note: refactor if native functions push a frame on the stack self.call_native_impl( + current_frame, resolver, data_store, + module_store, gas_meter, + traversal_context, extensions, function.clone(), ty_args, @@ -428,27 +472,32 @@ impl Interpreter { fn call_native_impl( &mut self, + current_frame: &mut Frame, resolver: &Resolver, data_store: &mut TransactionDataCache, + module_store: &ModuleStorageAdapter, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, extensions: &mut NativeContextExtensions, function: Arc, ty_args: Vec, ) -> PartialVMResult<()> { + let ty_builder = resolver.loader().ty_builder(); let return_type_count = function.return_type_count(); let mut args = VecDeque::new(); let expected_args = function.arg_count(); for _ in 0..expected_args { args.push_front(self.operand_stack.pop()?); } + let mut args_ty = VecDeque::new(); if self.paranoid_type_checks { - let ty_builder = resolver.loader().ty_builder(); for i in 0..expected_args { let expected_ty = ty_builder .subst(&function.parameter_types()[expected_args - i - 1], &ty_args)?; let ty = self.operand_stack.pop_ty()?; ty.check_eq(&expected_ty)?; + args_ty.push_front(ty); } } @@ -458,6 +507,7 @@ impl Interpreter { resolver, extensions, gas_meter.balance_internal(), + traversal_context, ); let native_function = function.get_native()?; @@ -473,14 +523,43 @@ impl Interpreter { // Note(Gas): The order by which gas is charged / error gets returned MUST NOT be modified // here or otherwise it becomes an incompatible change!!! - let return_values = match result { - NativeResult::Success { cost, ret_vals } => { - gas_meter.charge_native_function(cost, Some(ret_vals.iter()))?; - ret_vals + match result { + NativeResult::Success { + cost, + ret_vals: return_values, + } => { + gas_meter.charge_native_function(cost, Some(return_values.iter()))?; + // Paranoid check to protect us against incorrect native function implementations. A native function that + // returns a different number of values than its declared types will trigger this check + if return_values.len() != return_type_count { + return Err( + PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR) + .with_message( + "Arity mismatch: return value count does not match return type count" + .to_string(), + ), + ); + } + // Put return values on the top of the operand stack, where the caller will find them. + // This is one of only two times the operand stack is shared across call stack frames; the other is in handling + // the Return instruction for normal calls + for value in return_values { + self.operand_stack.push(value)?; + } + + if self.paranoid_type_checks { + for ty in function.return_types() { + self.operand_stack + .push_ty(ty_builder.subst(ty, &ty_args)?)?; + } + } + + current_frame.pc += 1; // advance past the Call instruction in the caller + Ok(()) }, NativeResult::Abort { cost, abort_code } => { gas_meter.charge_native_function(cost, Option::>::None)?; - return Err(PartialVMError::new(StatusCode::ABORTED).with_sub_status(abort_code)); + Err(PartialVMError::new(StatusCode::ABORTED).with_sub_status(abort_code)) }, NativeResult::OutOfGas { partial_cost } => { let err = match gas_meter.charge_native_function( @@ -493,35 +572,109 @@ impl Interpreter { ), }; - return Err(err); + Err(err) }, - }; + NativeResult::CallFunction { + cost, + module_name, + func_name, + ty_args, + args, + } => { + gas_meter.charge_native_function(cost, Option::>::None)?; - // Paranoid check to protect us against incorrect native function implementations. A native function that - // returns a different number of values than its declared types will trigger this check - if return_values.len() != return_type_count { - return Err( - PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR).with_message( - "Arity mismatch: return value count does not match return type count" - .to_string(), - ), - ); - } - // Put return values on the top of the operand stack, where the caller will find them. - // This is one of only two times the operand stack is shared across call stack frames; the other is in handling - // the Return instruction for normal calls - for value in return_values { - self.operand_stack.push(value)?; - } + // Load the module that contains this function regardless of the traversal context. + // + // This is just a precautionary step to make sure that caching status of the VM will not alter execution + // result in case framework code forgot to use LoadFunction result to load the modules into cache + // and charge properly. + resolver + .loader() + .load_module(&module_name, data_store, module_store) + .map_err(|_| { + PartialVMError::new(StatusCode::FUNCTION_RESOLUTION_FAILURE) + .with_message(format!("Module {} doesn't exist", module_name)) + })?; - if self.paranoid_type_checks { - let ty_builder = resolver.loader().ty_builder(); - for ty in function.return_types() { - self.operand_stack - .push_ty(ty_builder.subst(ty, &ty_args)?)?; - } + let target_func = resolver.function_from_name(&module_name, &func_name)?; + + if target_func.is_friend_or_private() + || target_func.module_id() == function.module_id() + { + return Err(PartialVMError::new(StatusCode::RUNTIME_DISPATCH_ERROR) + .with_message( + "Invoking private or friend function during dispatch".to_string(), + )); + } + + // Checking type of the dispatch target function + // + // MoveVM will check that the native function that performs the dispatch will have the same + // type signature as the dispatch target function except the native function will have an extra argument + // in the end to determine which function to jump to. The native function shouldn't switch ordering of arguments. + // + // Runtime will use such convention to reconstruct the type stack required to perform paranoid mode checks. + if function.type_parameters != target_func.type_parameters + || function.return_types != target_func.return_types + || function.parameter_types[0..function.parameter_types.len() - 1] + != target_func.parameter_types + { + return Err(PartialVMError::new(StatusCode::RUNTIME_DISPATCH_ERROR) + .with_message( + "Invoking private or friend function during dispatch".to_string(), + )); + } + + for value in args { + self.operand_stack.push(value)?; + } + + // Maintaining the type stack for the paranoid mode using calling convention mentioned above. + if self.paranoid_type_checks { + args_ty.pop_back(); + for ty in args_ty { + self.operand_stack.push_ty(ty)?; + } + } + + self.set_new_call_frame( + current_frame, + gas_meter, + resolver.loader(), + target_func, + ty_args, + ) + }, + NativeResult::LoadModule { module_name } => { + let arena_id = traversal_context + .referenced_module_ids + .alloc(module_name.clone()); + resolver + .loader() + .check_dependencies_and_charge_gas( + module_store, + data_store, + gas_meter, + &mut traversal_context.visited, + traversal_context.referenced_modules, + [(arena_id.address(), arena_id.name())], + ) + .map_err(|err| { + PartialVMError::new(err.major_status()) + .with_message(format!("Module {} failed to be charged", module_name)) + })?; + resolver + .loader() + .load_module(&module_name, data_store, module_store) + .map_err(|_| { + PartialVMError::new(StatusCode::FUNCTION_RESOLUTION_FAILURE) + .with_message(format!("Module {} doesn't exist", module_name)) + })?; + + current_frame.pc += 1; // advance past the Call instruction in the caller + Ok(()) + }, } - Ok(()) } /// Make sure only private/friend function can only be invoked by modules under the same address. diff --git a/third_party/move/move-vm/runtime/src/loader/function.rs b/third_party/move/move-vm/runtime/src/loader/function.rs index 859f2d26f54b3..ad46bb720b048 100644 --- a/third_party/move/move-vm/runtime/src/loader/function.rs +++ b/third_party/move/move-vm/runtime/src/loader/function.rs @@ -32,21 +32,21 @@ pub(crate) enum Scope { // A runtime function // #[derive(Debug)] // https://github.com/rust-lang/rust/issues/70263 -pub(crate) struct Function { +pub struct Function { #[allow(unused)] pub(crate) file_format_version: u32, pub(crate) index: FunctionDefinitionIndex, pub(crate) code: Vec, - pub(crate) type_parameters: Vec, + pub type_parameters: Vec, // TODO: Make `native` and `def_is_native` become an enum. pub(crate) native: Option, pub(crate) def_is_native: bool, - pub(crate) def_is_friend_or_private: bool, + pub def_is_friend_or_private: bool, pub(crate) scope: Scope, pub(crate) name: Identifier, - pub(crate) return_types: Vec, + pub return_types: Vec, pub(crate) local_types: Vec, - pub(crate) parameter_types: Vec, + pub parameter_types: Vec, pub(crate) access_specifier: AccessSpecifier, } diff --git a/third_party/move/move-vm/runtime/src/loader/mod.rs b/third_party/move/move-vm/runtime/src/loader/mod.rs index 9cfb35df30803..64b579f285d98 100644 --- a/third_party/move/move-vm/runtime/src/loader/mod.rs +++ b/third_party/move/move-vm/runtime/src/loader/mod.rs @@ -1292,6 +1292,15 @@ impl<'a> Resolver<'a> { self.module_store.function_at(&func_inst.handle) } + pub(crate) fn function_from_name( + &self, + module_id: &ModuleId, + func_name: &IdentStr, + ) -> PartialVMResult> { + self.module_store + .resolve_function_by_name(func_name, module_id) + } + pub(crate) fn instantiate_generic_function( &self, gas_meter: Option<&mut impl GasMeter>, diff --git a/third_party/move/move-vm/runtime/src/native_functions.rs b/third_party/move/move-vm/runtime/src/native_functions.rs index 85be02a2a96bc..107120a6bc4e5 100644 --- a/third_party/move/move-vm/runtime/src/native_functions.rs +++ b/third_party/move/move-vm/runtime/src/native_functions.rs @@ -3,7 +3,10 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - data_cache::TransactionDataCache, interpreter::Interpreter, loader::Resolver, + data_cache::TransactionDataCache, + interpreter::Interpreter, + loader::{Function, Resolver}, + module_traversal::TraversalContext, native_extensions::NativeContextExtensions, }; use move_binary_format::errors::{ @@ -13,7 +16,7 @@ use move_core_types::{ account_address::AccountAddress, gas_algebra::{InternalGas, NumBytes}, identifier::Identifier, - language_storage::TypeTag, + language_storage::{ModuleId, TypeTag}, value::MoveTypeLayout, vm_status::StatusCode, }; @@ -99,6 +102,7 @@ pub struct NativeContext<'a, 'b, 'c> { resolver: &'a Resolver<'a>, extensions: &'a mut NativeContextExtensions<'b>, gas_balance: InternalGas, + traversal_context: &'a TraversalContext<'a>, } impl<'a, 'b, 'c> NativeContext<'a, 'b, 'c> { @@ -108,6 +112,7 @@ impl<'a, 'b, 'c> NativeContext<'a, 'b, 'c> { resolver: &'a Resolver<'a>, extensions: &'a mut NativeContextExtensions<'b>, gas_balance: InternalGas, + traversal_context: &'a TraversalContext<'a>, ) -> Self { Self { interpreter, @@ -115,6 +120,7 @@ impl<'a, 'b, 'c> NativeContext<'a, 'b, 'c> { resolver, extensions, gas_balance, + traversal_context, } } } @@ -182,4 +188,31 @@ impl<'a, 'b, 'c> NativeContext<'a, 'b, 'c> { pub fn gas_balance(&self) -> InternalGas { self.gas_balance } + + pub fn traversal_context(&self) -> &TraversalContext { + self.traversal_context + } + + pub fn load_function( + &mut self, + module: &ModuleId, + function_name: &Identifier, + ) -> PartialVMResult> { + // Load the module that contains this function regardless of the traversal context. + // + // This is just a precautionary step to make sure that caching status of the VM will not alter execution + // result in case framework code forgot to use LoadFunction result to load the modules into cache + // and charge properly. + self.resolver + .loader() + .load_module(module, self.data_store, self.resolver.module_store()) + .map_err(|_| { + PartialVMError::new(StatusCode::FUNCTION_RESOLUTION_FAILURE) + .with_message(format!("Module {} doesn't exist", module)) + })?; + + self.resolver + .module_store() + .resolve_function_by_name(function_name, module) + } } diff --git a/third_party/move/move-vm/runtime/src/runtime.rs b/third_party/move/move-vm/runtime/src/runtime.rs index d6cf16160018c..619699e6f42d9 100644 --- a/third_party/move/move-vm/runtime/src/runtime.rs +++ b/third_party/move/move-vm/runtime/src/runtime.rs @@ -7,6 +7,7 @@ use crate::{ data_cache::TransactionDataCache, interpreter::Interpreter, loader::{Function, LoadedFunction, Loader, ModuleCache, ModuleStorage, ModuleStorageAdapter}, + module_traversal::TraversalContext, native_extensions::NativeContextExtensions, native_functions::{NativeFunction, NativeFunctions}, session::{LoadedFunctionInstantiation, SerializedReturnValues}, @@ -362,6 +363,7 @@ impl VMRuntime { data_store: &mut TransactionDataCache, module_store: &ModuleStorageAdapter, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, extensions: &mut NativeContextExtensions, ) -> VMResult { let ty_builder = self.loader().ty_builder(); @@ -394,6 +396,7 @@ impl VMRuntime { data_store, module_store, gas_meter, + traversal_context, extensions, &self.loader, )?; @@ -435,6 +438,7 @@ impl VMRuntime { data_store: &mut TransactionDataCache, module_store: &ModuleStorageAdapter, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, extensions: &mut NativeContextExtensions, bypass_declared_entry_check: bool, ) -> VMResult { @@ -450,6 +454,7 @@ impl VMRuntime { data_store, module_store, gas_meter, + traversal_context, extensions, bypass_declared_entry_check, ) @@ -463,6 +468,7 @@ impl VMRuntime { data_store: &mut TransactionDataCache, module_store: &ModuleStorageAdapter, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, extensions: &mut NativeContextExtensions, bypass_declared_entry_check: bool, ) -> VMResult { @@ -512,6 +518,7 @@ impl VMRuntime { data_store, module_store, gas_meter, + traversal_context, extensions, ) } @@ -525,6 +532,7 @@ impl VMRuntime { data_store: &mut TransactionDataCache, module_store: &ModuleStorageAdapter, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, extensions: &mut NativeContextExtensions, ) -> VMResult<()> { // load the script, perform verification @@ -548,6 +556,7 @@ impl VMRuntime { data_store, module_store, gas_meter, + traversal_context, extensions, )?; Ok(()) diff --git a/third_party/move/move-vm/runtime/src/session.rs b/third_party/move/move-vm/runtime/src/session.rs index 547f1658d20b5..398db12c24355 100644 --- a/third_party/move/move-vm/runtime/src/session.rs +++ b/third_party/move/move-vm/runtime/src/session.rs @@ -82,6 +82,7 @@ impl<'r, 'l> Session<'r, 'l> { ty_args: Vec, args: Vec>, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, ) -> VMResult<()> { let bypass_declared_entry_check = false; self.move_vm.runtime.execute_function( @@ -92,6 +93,7 @@ impl<'r, 'l> Session<'r, 'l> { &mut self.data_cache, &self.module_store, gas_meter, + traversal_context, &mut self.native_extensions, bypass_declared_entry_check, )?; @@ -106,6 +108,7 @@ impl<'r, 'l> Session<'r, 'l> { ty_args: Vec, args: Vec>, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, ) -> VMResult { let bypass_declared_entry_check = true; self.move_vm.runtime.execute_function( @@ -116,6 +119,7 @@ impl<'r, 'l> Session<'r, 'l> { &mut self.data_cache, &self.module_store, gas_meter, + traversal_context, &mut self.native_extensions, bypass_declared_entry_check, ) @@ -127,6 +131,7 @@ impl<'r, 'l> Session<'r, 'l> { instantiation: LoadedFunctionInstantiation, args: Vec>, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, ) -> VMResult { self.move_vm.runtime.execute_function_instantiation( func, @@ -135,6 +140,7 @@ impl<'r, 'l> Session<'r, 'l> { &mut self.data_cache, &self.module_store, gas_meter, + traversal_context, &mut self.native_extensions, true, ) @@ -162,6 +168,7 @@ impl<'r, 'l> Session<'r, 'l> { ty_args: Vec, args: Vec>, gas_meter: &mut impl GasMeter, + traversal_context: &mut TraversalContext, ) -> VMResult<()> { self.move_vm.runtime.execute_script( script, @@ -170,6 +177,7 @@ impl<'r, 'l> Session<'r, 'l> { &mut self.data_cache, &self.module_store, gas_meter, + traversal_context, &mut self.native_extensions, ) } diff --git a/third_party/move/move-vm/test-utils/Cargo.toml b/third_party/move/move-vm/test-utils/Cargo.toml index 44bc0a26b8fe9..c92f07072b50d 100644 --- a/third_party/move/move-vm/test-utils/Cargo.toml +++ b/third_party/move/move-vm/test-utils/Cargo.toml @@ -11,9 +11,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bytes = "1.4.0" -once_cell = "1.7.2" -serde = { version = "1.0.124", features = ["derive", "rc"] } +bytes = { workspace = true } +once_cell = { workspace = true } +serde = { workspace = true, features = ["derive", "rc"] } move-binary-format = { path = "../../move-binary-format" } move-core-types = { path = "../../move-core/types" } @@ -21,5 +21,5 @@ move-table-extension = { path = "../../extensions/move-table-extension", optiona move-vm-types = { path = "../types" } [features] -default = [ ] +default = [] table-extension = ["move-table-extension"] diff --git a/third_party/move/move-vm/transactional-tests/Cargo.toml b/third_party/move/move-vm/transactional-tests/Cargo.toml index d29d297039294..6d30685ac1ed5 100644 --- a/third_party/move/move-vm/transactional-tests/Cargo.toml +++ b/third_party/move/move-vm/transactional-tests/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" license = "Apache-2.0" [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } move-transactional-test-runner = { path = "../../testing-infra/transactional-test-runner" } [[test]] diff --git a/third_party/move/move-vm/types/Cargo.toml b/third_party/move/move-vm/types/Cargo.toml index fc3c9ecab7fc3..4952f0cdf0b7b 100644 --- a/third_party/move/move-vm/types/Cargo.toml +++ b/third_party/move/move-vm/types/Cargo.toml @@ -10,13 +10,13 @@ publish = false edition = "2021" [dependencies] -derivative = "2.2.0" -itertools = "0.10.0" -proptest = { version = "1.0.0", optional = true } -serde = { version = "1.0.124", features = ["derive", "rc"] } -smallbitvec = "2.5.1" -smallvec = "1.6.1" -triomphe = "0.1.9" +derivative = { workspace = true } +itertools = { workspace = true } +proptest = { workspace = true, optional = true } +serde = { workspace = true, features = ["derive", "rc"] } +smallbitvec = { workspace = true } +smallvec = { workspace = true } +triomphe = { workspace = true } bcs = { workspace = true } @@ -24,10 +24,10 @@ move-binary-format = { path = "../../move-binary-format" } move-core-types = { path = "../../move-core/types" } [dev-dependencies] -claims = "0.7" +claims = { workspace = true } move-binary-format = { path = "../../move-binary-format", features = ["fuzzing"] } -proptest = "1.0.0" -rand = "0.8.5" +proptest = { workspace = true } +rand = { workspace = true } [features] default = [] diff --git a/third_party/move/move-vm/types/src/natives/function.rs b/third_party/move/move-vm/types/src/natives/function.rs index 3afef8beba2a1..24ef4c7cccfac 100644 --- a/third_party/move/move-vm/types/src/natives/function.rs +++ b/third_party/move/move-vm/types/src/natives/function.rs @@ -17,9 +17,10 @@ //! This module contains the declarations and utilities to implement a native //! function. -use crate::values::Value; +use crate::{loaded_data::runtime_types::Type, values::Value}; pub use move_binary_format::errors::{PartialVMError, PartialVMResult}; pub use move_core_types::{gas_algebra::InternalGas, vm_status::StatusCode}; +use move_core_types::{identifier::Identifier, language_storage::ModuleId}; use smallvec::{smallvec, SmallVec}; /// Result of a native function execution requires charges for execution cost. @@ -43,6 +44,24 @@ pub enum NativeResult { OutOfGas { partial_cost: InternalGas, }, + /// Instruct the VM to perform a control flow transfer. + /// + /// Note the calling convention here requires the following: + /// The native function that performs the dispatch should have the same type signature as the dispatch target function except + /// the native function will have an extra argument in the end to determine which function to jump to. + /// + /// Failing to follow this convention will result in errors in paranoid mode. + CallFunction { + cost: InternalGas, + module_name: ModuleId, + func_name: Identifier, + ty_args: Vec, + args: SmallVec<[Value; 1]>, + }, + /// Instruct the VM to load up a module into the loader and charge dependency for such operation. + LoadModule { + module_name: ModuleId, + }, } impl NativeResult { diff --git a/third_party/move/testing-infra/module-generation/Cargo.toml b/third_party/move/testing-infra/module-generation/Cargo.toml index 624a979373521..ca6088cdec1ca 100644 --- a/third_party/move/testing-infra/module-generation/Cargo.toml +++ b/third_party/move/testing-infra/module-generation/Cargo.toml @@ -11,7 +11,9 @@ edition = "2021" [dependencies] move-binary-format = { path = "../../move-binary-format" } -rand = "0.8.3" +# Cannot use workspace version as aptos-core currently cannot be upgraded +# to newer rand. See https://github.com/aptos-labs/aptos-core/issues/13031 +rand = { version = "0.8.5" } move-bytecode-verifier = { path = "../../move-bytecode-verifier" } move-core-types = { path = "../../move-core/types" } diff --git a/third_party/move/testing-infra/test-generation/Cargo.toml b/third_party/move/testing-infra/test-generation/Cargo.toml index 97c614e108c71..86f443cfc0b81 100644 --- a/third_party/move/testing-infra/test-generation/Cargo.toml +++ b/third_party/move/testing-infra/test-generation/Cargo.toml @@ -10,17 +10,19 @@ publish = false edition = "2021" [dependencies] -clap = { version = "4.3.9", features = ["derive"] } -crossbeam-channel = "0.5.0" -getrandom = "0.2.2" -hex = "0.4.3" -itertools = "0.10.0" +clap = { workspace = true, features = ["derive"] } +crossbeam-channel = { workspace = true } +getrandom = { workspace = true } +hex = { workspace = true } +itertools = { workspace = true } module-generation = { path = "../module-generation" } -num_cpus = "1.13.0" -once_cell = "1.7.2" -rand = "0.8.3" -tracing = "0.1.26" -tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } +num_cpus = { workspace = true } +once_cell = { workspace = true } +# Cannot use workspace version as aptos-core currently cannot be upgraded +# to newer rand. See https://github.com/aptos-labs/aptos-core/issues/13031 +rand = { version = "0.8.5" } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter"] } move-binary-format = { path = "../../move-binary-format" } move-bytecode-verifier = { path = "../../move-bytecode-verifier" } diff --git a/third_party/move/testing-infra/test-generation/src/lib.rs b/third_party/move/testing-infra/test-generation/src/lib.rs index 27ac3271be984..1f175f7a38399 100644 --- a/third_party/move/testing-infra/test-generation/src/lib.rs +++ b/third_party/move/testing-infra/test-generation/src/lib.rs @@ -39,7 +39,7 @@ use move_core_types::{ value::MoveValue, vm_status::{StatusCode, VMStatus}, }; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{module_traversal::*, move_vm::MoveVM}; use move_vm_test_utils::{DeltaStorage, InMemoryStorage}; use move_vm_types::gas::UnmeteredGasMeter; use once_cell::sync::Lazy; @@ -156,6 +156,7 @@ fn execute_function_in_module( .unwrap(); let delta_storage = DeltaStorage::new(storage, &changeset); let mut sess = vm.new_session(&delta_storage); + let traversal_storage = TraversalStorage::new(); sess.execute_function_bypass_visibility( &module_id, @@ -163,6 +164,7 @@ fn execute_function_in_module( ty_args, args, &mut UnmeteredGasMeter, + &mut TraversalContext::new(&traversal_storage), )?; Ok(()) diff --git a/third_party/move/testing-infra/transactional-test-runner/Cargo.toml b/third_party/move/testing-infra/transactional-test-runner/Cargo.toml index 21461e1c8cbd7..3cb8f9bfd5796 100644 --- a/third_party/move/testing-infra/transactional-test-runner/Cargo.toml +++ b/third_party/move/testing-infra/transactional-test-runner/Cargo.toml @@ -10,8 +10,8 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -clap = { version = "4.3.9", features = ["derive"] } +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } move-binary-format = { path = "../../move-binary-format", features = ["testing"] } move-bytecode-source-map = { path = "../../move-ir-compiler/move-bytecode-source-map" } move-cli = { path = "../../tools/move-cli" } @@ -24,10 +24,10 @@ move-ir-compiler = { path = "../../move-ir-compiler" } move-ir-types = { path = "../../move-ir/types" } move-model = { path = "../../move-model" } move-resource-viewer = { path = "../../tools/move-resource-viewer" } -once_cell = "1.7.2" -regex = "1.1.9" -tempfile = "3.2.0" -termcolor = "1.1.3" +once_cell = { workspace = true } +regex = { workspace = true } +tempfile = { workspace = true } +termcolor = { workspace = true } move-stdlib = { path = "../../move-stdlib", features = ["testing"] } move-symbol-pool = { path = "../../move-symbol-pool" } @@ -36,8 +36,8 @@ move-vm-test-utils = { path = "../../move-vm/test-utils" } move-vm-types = { path = "../../move-vm/types" } [dev-dependencies] -datatest-stable = "0.1.1" -difference = "2.0.0" +datatest-stable = { workspace = true } +difference = { workspace = true } [[test]] name = "tests" diff --git a/third_party/move/testing-infra/transactional-test-runner/src/framework.rs b/third_party/move/testing-infra/transactional-test-runner/src/framework.rs index b3d043105dc92..13e084d9ea830 100644 --- a/third_party/move/testing-infra/transactional-test-runner/src/framework.rs +++ b/third_party/move/testing-infra/transactional-test-runner/src/framework.rs @@ -9,7 +9,7 @@ use crate::{ taskify, InitCommand, PrintBytecodeCommand, PrintBytecodeInputChoice, PublishCommand, RunCommand, SyntaxChoice, TaskCommand, TaskInput, ViewCommand, }, - vm_test_harness::TestRunConfig, + vm_test_harness::{PrecompiledFilesModules, TestRunConfig}, }; use anyhow::{anyhow, Result}; use clap::Parser; @@ -30,7 +30,7 @@ use move_command_line_common::{ values::{ParsableValue, ParsedValue}, }; use move_compiler::{ - compiled_unit::AnnotatedCompiledUnit, + compiled_unit::{AnnotatedCompiledModule, AnnotatedCompiledUnit}, diagnostics::{Diagnostics, FilesSourceText}, shared::NumericalAddress, FullyCompiledProgram, @@ -61,7 +61,8 @@ pub struct ProcessedModule { } pub struct CompiledState<'a> { - pre_compiled_deps: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v1: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v2: Option<&'a PrecompiledFilesModules>, pre_compiled_ids: BTreeSet<(AccountAddress, String)>, compiled_module_named_address_mapping: BTreeMap, pub named_address_mapping: BTreeMap, @@ -116,6 +117,49 @@ fn merge_output(left: Option, right: Option) -> Option { } } +pub trait PreCompiledModules { + fn get_pre_compiled_modules(&self) -> Vec<&AnnotatedCompiledModule>; +} + +fn annotated_module_from_unit(unit: &AnnotatedCompiledUnit) -> Option<&AnnotatedCompiledModule> { + if let AnnotatedCompiledUnit::Module(tmod) = unit { + Some(tmod) + } else { + None + } +} + +impl PreCompiledModules for FullyCompiledProgram { + fn get_pre_compiled_modules(&self) -> Vec<&AnnotatedCompiledModule> { + self.compiled + .iter() + .filter_map(annotated_module_from_unit) + .collect() + } +} + +impl PreCompiledModules for PrecompiledFilesModules { + fn get_pre_compiled_modules(&self) -> Vec<&AnnotatedCompiledModule> { + self.units() + .iter() + .filter_map(annotated_module_from_unit) + .collect() + } +} + +pub fn either_or_no_modules<'a>( + pre_compiled_deps_v1: Option<&'a impl PreCompiledModules>, + pre_compiled_deps_v2: Option<&'a impl PreCompiledModules>, +) -> Vec<&'a AnnotatedCompiledModule> { + if let Some(v1_deps) = pre_compiled_deps_v1 { + v1_deps.get_pre_compiled_modules() + } else if let Some(v2_deps) = pre_compiled_deps_v2 { + v2_deps.get_pre_compiled_modules() + } else { + vec![] + } +} + pub trait MoveTestAdapter<'a>: Sized { type ExtraPublishArgs: Parser; type ExtraValueArgs: ParsableValue; @@ -133,7 +177,8 @@ pub trait MoveTestAdapter<'a>: Sized { default_syntax: SyntaxChoice, comparison_mode: bool, run_config: TestRunConfig, - option: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v1: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v2: Option<&'a PrecompiledFilesModules>, init_data: Option>, ) -> (Self, Option); fn publish_module( @@ -197,39 +242,31 @@ pub trait MoveTestAdapter<'a>: Sized { let data_path = data.path().to_str().unwrap(); let run_config = self.run_config(); let state = self.compiled_state(); - let (named_addr_opt, module, warnings_opt) = match (syntax, run_config) { - // Run the V2 compiler if requested - ( - SyntaxChoice::Source, - TestRunConfig::CompilerV2 { - language_version, - v2_experiments, - }, - ) => { - let ((module, _), warning_opt) = compile_source_unit_v2( - state.pre_compiled_deps, - state.named_address_mapping.clone(), - &state.source_files().cloned().collect::>(), - data_path.to_owned(), - self.known_attributes(), - language_version, - v2_experiments, - )?; - if let Some(module) = module { - (None, module, warning_opt) - } else { - anyhow::bail!("expected a module but found a script") - } - }, - // In all other cases, run V1 - (SyntaxChoice::Source, _) => { - let (unit, warnings_opt) = compile_source_unit( - state.pre_compiled_deps, - state.named_address_mapping.clone(), - &state.source_files().cloned().collect::>(), - data_path.to_owned(), - self.known_attributes(), - )?; + let (named_addr_opt, module, warnings_opt) = match syntax { + SyntaxChoice::Source => { + let (unit, warnings_opt) = match run_config { + // Run the V2 compiler if requested + TestRunConfig::CompilerV2 { + language_version, + v2_experiments, + } => compile_source_unit_v2( + state.pre_compiled_deps_v2, + state.named_address_mapping.clone(), + &state.source_files().cloned().collect::>(), + data_path.to_owned(), + self.known_attributes(), + language_version, + v2_experiments, + )?, + // In all other cases, run V1 + _ => compile_source_unit( + state.pre_compiled_deps_v1, + state.named_address_mapping.clone(), + &state.source_files().cloned().collect::>(), + data_path.to_owned(), + self.known_attributes(), + )?, + }; let (named_addr_opt, module) = match unit { AnnotatedCompiledUnit::Module(annot_module) => { let (named_addr_opt, _id) = annot_module.module_id(); @@ -246,7 +283,7 @@ pub trait MoveTestAdapter<'a>: Sized { }; (named_addr_opt, module, warnings_opt) }, - (SyntaxChoice::IR, _) => { + SyntaxChoice::IR => { let module = compile_ir_module(state.dep_modules(), data_path)?; (None, module, None) }, @@ -271,39 +308,31 @@ pub trait MoveTestAdapter<'a>: Sized { let data_path = data.path().to_str().unwrap(); let run_config = self.run_config(); let state = self.compiled_state(); - let (script, warning_opt) = match (syntax, run_config) { - // Run the V2 compiler if requested. - ( - SyntaxChoice::Source, - TestRunConfig::CompilerV2 { - language_version, - v2_experiments, - }, - ) => { - let ((_, script), warning_opt) = compile_source_unit_v2( - state.pre_compiled_deps, - state.named_address_mapping.clone(), - &state.source_files().cloned().collect::>(), - data_path.to_owned(), - self.known_attributes(), - language_version, - v2_experiments, - )?; - if let Some(script) = script { - (script, warning_opt) - } else { - anyhow::bail!("expected a script but found a module") - } - }, - // In all other Source cases, run the V1 compiler - (SyntaxChoice::Source, _) => { - let (unit, warning_opt) = compile_source_unit( - state.pre_compiled_deps, - state.named_address_mapping.clone(), - &state.source_files().cloned().collect::>(), - data_path.to_owned(), - self.known_attributes(), - )?; + let (script, warning_opt) = match syntax { + SyntaxChoice::Source => { + let (unit, warning_opt) = match run_config { + // Run the V2 compiler if requested. + TestRunConfig::CompilerV2 { + language_version, + v2_experiments, + } => compile_source_unit_v2( + state.pre_compiled_deps_v2, + state.named_address_mapping.clone(), + &state.source_files().cloned().collect::>(), + data_path.to_owned(), + self.known_attributes(), + language_version, + v2_experiments, + )?, + // In all other Source cases, run the V1 compiler + _ => compile_source_unit( + state.pre_compiled_deps_v1, + state.named_address_mapping.clone(), + &state.source_files().cloned().collect::>(), + data_path.to_owned(), + self.known_attributes(), + )?, + }; match unit { AnnotatedCompiledUnit::Script(annot_script) => (annot_script.named_script.script, warning_opt), AnnotatedCompiledUnit::Module(_) => panic!( @@ -312,7 +341,7 @@ pub trait MoveTestAdapter<'a>: Sized { ), } }, - (SyntaxChoice::IR, _) => (compile_ir_script(state.dep_modules(), data_path)?, None), + SyntaxChoice::IR => (compile_ir_script(state.dep_modules(), data_path)?, None), }; Ok((script, warning_opt)) } @@ -467,7 +496,7 @@ pub trait MoveTestAdapter<'a>: Sized { Ok(merge_output(output, rendered_return_value)) }, TaskCommand::View(ViewCommand { address, resource }) => { - let state: &CompiledState = self.compiled_state(); + let state: &CompiledState<'a> = self.compiled_state(); let StructTag { address: module_addr, module, @@ -558,41 +587,35 @@ fn display_return_values(return_values: SerializedReturnValues) -> Option CompiledState<'a> { pub fn new( named_address_mapping: BTreeMap, - pre_compiled_deps: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v1: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v2: Option<&'a PrecompiledFilesModules>, default_named_address_mapping: Option, ) -> Self { - let pre_compiled_ids = match pre_compiled_deps { - None => BTreeSet::new(), - Some(pre_compiled) => pre_compiled - .cfgir - .modules - .key_cloned_iter() - .map(|(ident, _)| { - ( - ident.value.address.into_addr_bytes().into_inner(), - ident.value.module.to_string(), - ) - }) - .collect(), - }; + let pre_compiled_ids = either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) + .into_iter() + .map(|annot_module| { + let ident = annot_module.module_ident(); + ( + ident.value.address.into_addr_bytes().into_inner(), + ident.value.module.to_string(), + ) + }) + .collect(); let mut state = Self { - pre_compiled_deps, + pre_compiled_deps_v1, + pre_compiled_deps_v2, pre_compiled_ids, modules: BTreeMap::new(), compiled_module_named_address_mapping: BTreeMap::new(), named_address_mapping, default_named_address_mapping, }; - if let Some(pcd) = pre_compiled_deps { - for unit in &pcd.compiled { - if let AnnotatedCompiledUnit::Module(annot_module) = unit { - let (named_addr_opt, _id) = annot_module.module_id(); - state.add_precompiled( - named_addr_opt.map(|n| n.value), - annot_module.named_module.module.clone(), - ); - } - } + for annot_module in either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) { + let (named_addr_opt, _id) = annot_module.module_id(); + state.add_precompiled( + named_addr_opt.map(|n| n.value), + annot_module.named_module.module.clone(), + ); } state } @@ -675,29 +698,26 @@ impl<'a> CompiledState<'a> { "Error publishing module: '{}'. \ Re-publishing modules in pre-compiled lib is not yet supported", id - ) + ); } } fn compile_source_unit_v2( - pre_compiled_deps: Option<&FullyCompiledProgram>, + pre_compiled_deps: Option<&PrecompiledFilesModules>, named_address_mapping: BTreeMap, deps: &[String], path: String, known_attributes: &BTreeSet, language_version: LanguageVersion, experiments: Vec<(String, bool)>, -) -> Result<( - (Option, Option), - Option, -)> { +) -> Result<(AnnotatedCompiledUnit, Option)> { let deps = if let Some(p) = pre_compiled_deps { - // The v2 compiler does not (and perhaps never) supports precompiled programs, so - // compile from the sources again, computing the directories where they are found. + // The v2 compiler does not really support precompiled programs, so we must include all the + // dependent sources with their directories here. let mut dirs: BTreeSet<_> = p - .files + .filenames() .iter() - .filter_map(|(_, (file_name, _))| { + .filter_map(|file_name| { Path::new(file_name.as_str()) .parent() .map(|p| p.to_string_lossy().to_string()) @@ -712,7 +732,7 @@ fn compile_source_unit_v2( let mut options = move_compiler_v2::Options { sources: vec![path], - dependencies: deps, + dependencies: deps.to_vec(), named_address_mapping: named_address_mapping .into_iter() .map(|(alias, addr)| format!("{}={}", alias, addr)) @@ -732,10 +752,7 @@ fn compile_source_unit_v2( let unit = if units.len() != 1 { anyhow::bail!("expected either one script or one module") } else { - match units.pop().unwrap() { - AnnotatedCompiledUnit::Module(m) => (Some(m.named_module.module), None), - AnnotatedCompiledUnit::Script(s) => (None, Some(s.named_script.script)), - } + units.pop().unwrap() }; if error_str.is_empty() { Ok((unit, None)) @@ -837,7 +854,8 @@ fn compile_ir_script<'a>( pub fn run_test_impl<'a, Adapter>( config: TestRunConfig, path: &Path, - fully_compiled_program_opt: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v1: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v2: Option<&'a PrecompiledFilesModules>, exp_suffix: &Option, ) -> Result<(), Box> where @@ -911,7 +929,8 @@ where default_syntax, comparison_mode, run_config.clone(), - fully_compiled_program_opt, + pre_compiled_deps_v1, + pre_compiled_deps_v2, init_opt, ); if let Some(result) = result_opt { diff --git a/third_party/move/testing-infra/transactional-test-runner/src/vm_test_harness.rs b/third_party/move/testing-infra/transactional-test-runner/src/vm_test_harness.rs index 3c3b76955ce6e..813c656609b96 100644 --- a/third_party/move/testing-infra/transactional-test-runner/src/vm_test_harness.rs +++ b/third_party/move/testing-infra/transactional-test-runner/src/vm_test_harness.rs @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - framework::{run_test_impl, CompiledState, MoveTestAdapter}, + framework::{either_or_no_modules, run_test_impl, CompiledState, MoveTestAdapter}, tasks::{EmptyCommand, InitCommand, SyntaxChoice, TaskInput}, }; use anyhow::{anyhow, Result}; @@ -17,7 +17,9 @@ use move_binary_format::{ CompiledModule, }; use move_command_line_common::{ - address::ParsedAddress, env::read_bool_env_var, files::verify_and_create_named_address_mapping, + address::ParsedAddress, + env::{get_move_compiler_block_v1_from_env, get_move_compiler_v2_from_env, read_bool_env_var}, + files::verify_and_create_named_address_mapping, }; use move_compiler::{ compiled_unit::AnnotatedCompiledUnit, @@ -37,6 +39,7 @@ use move_stdlib::move_stdlib_named_addresses; use move_symbol_pool::Symbol; use move_vm_runtime::{ config::VMConfig, + module_traversal::*, move_vm::MoveVM, session::{SerializedReturnValues, Session}, }; @@ -44,6 +47,7 @@ use move_vm_test_utils::{gas_schedule::GasStatus, InMemoryStorage}; use once_cell::sync::Lazy; use std::{ collections::{BTreeMap, BTreeSet}, + iter::Iterator, path::Path, }; @@ -138,7 +142,8 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { default_syntax: SyntaxChoice, comparison_mode: bool, run_config: TestRunConfig, - pre_compiled_deps: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v1: Option<&'a FullyCompiledProgram>, + pre_compiled_deps_v2: Option<&'a PrecompiledFilesModules>, task_opt: Option>, ) -> (Self, Option) { let additional_mapping = match task_opt.map(|t| t.command) { @@ -159,7 +164,12 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { named_address_mapping.insert(name, addr); } let mut adapter = Self { - compiled_state: CompiledState::new(named_address_mapping, pre_compiled_deps, None), + compiled_state: CompiledState::new( + named_address_mapping, + pre_compiled_deps_v1, + pre_compiled_deps_v2, + None, + ), default_syntax, comparison_mode, run_config, @@ -170,7 +180,10 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { .perform_session_action( None, |session, gas_status| { - for module in &*MOVE_STDLIB_COMPILED { + for module in either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) + .into_iter() + .map(|tmod| &tmod.named_module.module) + { let mut module_bytes = vec![]; module .serialize_for_version( @@ -194,14 +207,16 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { let prev = addr_to_name_mapping.insert(addr, Symbol::from(name)); assert!(prev.is_none()); } - for module in MOVE_STDLIB_COMPILED - .iter() - .filter(|module| !adapter.compiled_state.is_precompiled_dep(&module.self_id())) - .collect::>() - { + let missing_modules: Vec<_> = + either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) + .into_iter() + .map(|tmod| &tmod.named_module.module) + .filter(|module| !adapter.compiled_state.is_precompiled_dep(&module.self_id())) + .collect(); + for module in missing_modules { adapter .compiled_state - .add_and_generate_interface_file(module.clone()); + .add_and_generate_interface_file(module.clone()) } (adapter, None) } @@ -277,9 +292,18 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { .chain(args) .collect(); let verbose = extra_args.verbose; + let traversal_storage = TraversalStorage::new(); self.perform_session_action( gas_budget, - |session, gas_status| session.execute_script(script_bytes, type_args, args, gas_status), + |session, gas_status| { + session.execute_script( + script_bytes, + type_args, + args, + gas_status, + &mut TraversalContext::new(&traversal_storage), + ) + }, VMConfig::from(extra_args), ) .map_err(|vm_error| { @@ -320,12 +344,19 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { .chain(args) .collect(); let verbose = extra_args.verbose; + let traversal_storage = TraversalStorage::new(); + let serialized_return_values = self .perform_session_action( gas_budget, |session, gas_status| { session.execute_function_bypass_visibility( - module, function, type_args, args, gas_status, + module, + function, + type_args, + args, + gas_status, + &mut TraversalContext::new(&traversal_storage), ) }, VMConfig::from(extra_args), @@ -394,7 +425,10 @@ impl<'a> SimpleVMTestAdapter<'a> { } } -static PRECOMPILED_MOVE_STDLIB: Lazy = Lazy::new(|| { +static PRECOMPILED_MOVE_STDLIB: Lazy> = Lazy::new(|| { + if get_move_compiler_block_v1_from_env() { + return None; + } let program_res = move_compiler::construct_pre_compiled_lib( vec![PackagePaths { name: None, @@ -407,7 +441,7 @@ static PRECOMPILED_MOVE_STDLIB: Lazy = Lazy::new(|| { ) .unwrap(); match program_res { - Ok(stdlib) => stdlib, + Ok(stdlib) => Some(stdlib), Err((files, errors)) => { eprintln!("!!!Standard library failed to compile!!!"); move_compiler::diagnostics::report_diagnostics(&files, errors) @@ -415,35 +449,35 @@ static PRECOMPILED_MOVE_STDLIB: Lazy = Lazy::new(|| { } }); -static MOVE_STDLIB_COMPILED: Lazy> = Lazy::new(|| { - let (files, units_res) = move_compiler::Compiler::from_files( - move_stdlib::move_stdlib_files(), - vec![], - move_stdlib::move_stdlib_named_addresses(), - Flags::empty().set_skip_attribute_checks(true), // no point in checking here. - KnownAttribute::get_all_attribute_names(), - ) - .build() - .unwrap(); - match units_res { - Err(diags) => { - eprintln!("!!!Standard library failed to compile!!!"); - move_compiler::diagnostics::report_diagnostics(&files, diags) - }, - Ok((_, warnings)) if !warnings.is_empty() => { - eprintln!("!!!Standard library failed to compile!!!"); - move_compiler::diagnostics::report_diagnostics(&files, warnings) - }, - Ok((units, _warnings)) => units - .into_iter() - .filter_map(|m| match m { - AnnotatedCompiledUnit::Module(annot_module) => { - Some(annot_module.named_module.module) - }, - AnnotatedCompiledUnit::Script(_) => None, - }) - .collect(), +pub struct PrecompiledFilesModules(Vec, Vec); + +impl PrecompiledFilesModules { + pub fn new(files: Vec, modules: Vec) -> Self { + PrecompiledFilesModules(files, modules) } + + pub fn filenames(&self) -> &Vec { + &self.0 + } + + pub fn units(&self) -> &Vec { + &self.1 + } +} + +static PRECOMPILED_MOVE_STDLIB_V2: Lazy = Lazy::new(|| { + let options = move_compiler_v2::Options { + sources: move_stdlib::move_stdlib_files(), + dependencies: vec![], + named_address_mapping: move_stdlib::move_stdlib_named_addresses_strings(), + known_attributes: KnownAttribute::get_all_attribute_names().clone(), + language_version: None, + ..move_compiler_v2::Options::default() + }; + + let (_global_env, modules) = move_compiler_v2::run_move_compiler_to_stderr(options) + .expect("stdlib compilation succeeds"); + PrecompiledFilesModules::new(move_stdlib::move_stdlib_files(), modules) }); #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] @@ -463,11 +497,39 @@ pub fn run_test(path: &Path) -> Result<(), Box> { run_test_with_config(TestRunConfig::CompilerV1, path) } +fn precompiled_v1_stdlib_if_needed( + config: &TestRunConfig, +) -> Option<&'static FullyCompiledProgram> { + match config { + TestRunConfig::CompilerV1 { .. } => PRECOMPILED_MOVE_STDLIB.as_ref(), + TestRunConfig::ComparisonV1V2 { .. } => PRECOMPILED_MOVE_STDLIB.as_ref(), + TestRunConfig::CompilerV2 { .. } => None, + } +} + +fn precompiled_v2_stdlib_if_needed( + config: &TestRunConfig, +) -> Option<&'static PrecompiledFilesModules> { + match config { + TestRunConfig::CompilerV1 { .. } => None, + TestRunConfig::ComparisonV1V2 { .. } => Some(&*PRECOMPILED_MOVE_STDLIB_V2), + TestRunConfig::CompilerV2 { .. } => Some(&*PRECOMPILED_MOVE_STDLIB_V2), + } +} + pub fn run_test_with_config( - config: TestRunConfig, + mut config: TestRunConfig, path: &Path, ) -> Result<(), Box> { - run_test_impl::(config, path, Some(&*PRECOMPILED_MOVE_STDLIB), &None) + if get_move_compiler_v2_from_env() && !matches!(config, TestRunConfig::CompilerV2 { .. }) { + config = TestRunConfig::CompilerV2 { + language_version: LanguageVersion::default(), + v2_experiments: vec![], + } + } + let v1_lib = precompiled_v1_stdlib_if_needed(&config); + let v2_lib = precompiled_v2_stdlib_if_needed(&config); + run_test_impl::(config, path, v1_lib, v2_lib, &None) } pub fn run_test_with_config_and_exp_suffix( @@ -475,7 +537,18 @@ pub fn run_test_with_config_and_exp_suffix( path: &Path, exp_suffix: &Option, ) -> Result<(), Box> { - run_test_impl::(config, path, Some(&*PRECOMPILED_MOVE_STDLIB), exp_suffix) + let config = + if get_move_compiler_v2_from_env() && !matches!(config, TestRunConfig::CompilerV2 { .. }) { + TestRunConfig::CompilerV2 { + language_version: LanguageVersion::default(), + v2_experiments: vec![], + } + } else { + config + }; + let v1_lib = precompiled_v1_stdlib_if_needed(&config); + let v2_lib = precompiled_v2_stdlib_if_needed(&config); + run_test_impl::(config, path, v1_lib, v2_lib, exp_suffix) } impl From for VMConfig { diff --git a/third_party/move/tools/move-bytecode-utils/Cargo.toml b/third_party/move/tools/move-bytecode-utils/Cargo.toml index a17adf719ddf2..aa14f2a099841 100644 --- a/third_party/move/tools/move-bytecode-utils/Cargo.toml +++ b/third_party/move/tools/move-bytecode-utils/Cargo.toml @@ -10,8 +10,8 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" +anyhow = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-core-types = { path = "../../move-core/types" } -petgraph = "0.5.1" +petgraph = { workspace = true } serde-reflection = { workspace = true } diff --git a/third_party/move/tools/move-bytecode-viewer/Cargo.toml b/third_party/move/tools/move-bytecode-viewer/Cargo.toml index 396134a5767ab..e3a51224a71a7 100644 --- a/third_party/move/tools/move-bytecode-viewer/Cargo.toml +++ b/third_party/move/tools/move-bytecode-viewer/Cargo.toml @@ -8,13 +8,13 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -clap = { version = "4.3.9", features = ["derive"] } -crossterm = "0.26.1" +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } +crossterm = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-bytecode-source-map = { path = "../../move-ir-compiler/move-bytecode-source-map" } -regex = "1.5.5" -tui = "0.19.0" +regex = { workspace = true } +tui = { workspace = true } move-disassembler = { path = "../move-disassembler" } diff --git a/third_party/move/tools/move-cli/Cargo.toml b/third_party/move/tools/move-cli/Cargo.toml index 9f601651bafc8..09d13080281d5 100644 --- a/third_party/move/tools/move-cli/Cargo.toml +++ b/third_party/move/tools/move-cli/Cargo.toml @@ -10,20 +10,20 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -bytes = "1.4.0" -clap = { version = "4.3.9", features = ["derive"] } -codespan-reporting = "0.11.1" -colored = "2.0.0" -difference = "2.0.0" -once_cell = "1.7.2" -reqwest = { version = "0.11.1", features = ["blocking", "json"] } -serde = { version = "1.0.124", default-features = false } -serde_json = "1.0" -serde_yaml = "0.8.17" -tempfile = "3.2.0" -toml_edit = { version = "0.14.3", features = ["easy"] } -walkdir = "2.3.1" +anyhow = { workspace = true } +bytes = { workspace = true } +clap = { workspace = true, features = ["derive"] } +codespan-reporting = { workspace = true } +colored = { workspace = true } +difference = { workspace = true } +once_cell = { workspace = true } +reqwest = { workspace = true, features = ["blocking", "json"] } +serde = { workspace = true } +serde_json = { workspace = true } +serde_yaml = { workspace = true } +tempfile = { workspace = true } +toml_edit = { workspace = true, features = ["easy"] } +walkdir = { workspace = true } bcs = { workspace = true } move-binary-format = { path = "../../move-binary-format" } @@ -51,8 +51,8 @@ move-vm-runtime = { path = "../../move-vm/runtime", features = ["debugging"] } move-vm-test-utils = { path = "../../move-vm/test-utils" } [dev-dependencies] -datatest-stable = "0.1.1" -httpmock = "0.6.6" +datatest-stable = { workspace = true } +httpmock = { workspace = true } [[bin]] name = "move" diff --git a/third_party/move/tools/move-cli/src/base/test.rs b/third_party/move/tools/move-cli/src/base/test.rs index 40a3c4dcd41c2..5e3b04baa5b37 100644 --- a/third_party/move/tools/move-cli/src/base/test.rs +++ b/third_party/move/tools/move-cli/src/base/test.rs @@ -215,7 +215,7 @@ pub fn run_move_unit_tests( // Move package system, to first grab the compilation env, construct the test plan from it, and // then save it, before resuming the rest of the compilation and returning the results and // control back to the Move package system. - let (_, model_opt) = build_plan.compile_with_driver( + let (_compiled_package, model_opt) = build_plan.compile_with_driver( writer, &build_config.compiler_config, |compiler| { diff --git a/third_party/move/tools/move-cli/src/sandbox/commands/run.rs b/third_party/move/tools/move-cli/src/sandbox/commands/run.rs index 9f59ea58c045f..9d56adb15a1d3 100644 --- a/third_party/move/tools/move-cli/src/sandbox/commands/run.rs +++ b/third_party/move/tools/move-cli/src/sandbox/commands/run.rs @@ -21,7 +21,10 @@ use move_core_types::{ value::MoveValue, }; use move_package::compilation::compiled_package::CompiledPackage; -use move_vm_runtime::move_vm::MoveVM; +use move_vm_runtime::{ + module_traversal::{TraversalContext, TraversalStorage}, + move_vm::MoveVM, +}; use move_vm_test_utils::gas_schedule::CostTable; use std::{fs, path::Path}; @@ -92,6 +95,8 @@ move run` must be applied to a module inside `storage/`", }) .chain(vm_args) .collect(); + + let storage = TraversalStorage::new(); let res = match script_name_opt { Some(script_name) => { // script fun. parse module, extract script ID to pass to VM @@ -103,6 +108,7 @@ move run` must be applied to a module inside `storage/`", vm_type_args.clone(), vm_args, &mut gas_status, + &mut TraversalContext::new(&storage), ) }, None => session.execute_script( @@ -110,6 +116,7 @@ move run` must be applied to a module inside `storage/`", vm_type_args.clone(), vm_args, &mut gas_status, + &mut TraversalContext::new(&storage), ), }; diff --git a/third_party/move/tools/move-cli/src/sandbox/commands/test.rs b/third_party/move/tools/move-cli/src/sandbox/commands/test.rs index 761230eeda789..808d363ecede4 100644 --- a/third_party/move/tools/move-cli/src/sandbox/commands/test.rs +++ b/third_party/move/tools/move-cli/src/sandbox/commands/test.rs @@ -4,11 +4,10 @@ use crate::{sandbox::utils::module, DEFAULT_BUILD_DIR, DEFAULT_STORAGE_DIR}; use move_command_line_common::{ - env::{read_bool_env_var, NO_COLOR_MODE_ENV_VAR}, + env::{get_move_compiler_v2_from_env, read_bool_env_var, NO_COLOR_MODE_ENV_VAR}, files::{find_filenames, path_to_string}, testing::{ add_update_baseline_fix, format_diff, read_env_update_baseline, EXP_EXT, EXP_EXT_V2, - MOVE_COMPILER_V2, }, }; use move_compiler::command_line::COLOR_MODE_ENV_VAR; @@ -341,7 +340,7 @@ pub fn run_one( // compare output and exp_file let update_baseline = read_env_update_baseline(); - let exp_ext = if read_bool_env_var(MOVE_COMPILER_V2) { + let exp_ext = if get_move_compiler_v2_from_env() { EXP_EXT_V2 } else { EXP_EXT diff --git a/third_party/move/tools/move-coverage/Cargo.toml b/third_party/move/tools/move-coverage/Cargo.toml index 4b058f6f1ecae..276754c9b3ca3 100644 --- a/third_party/move/tools/move-coverage/Cargo.toml +++ b/third_party/move/tools/move-coverage/Cargo.toml @@ -10,12 +10,12 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -clap = { version = "4.3.9", features = ["derive"] } -codespan = { version = "0.11.1", features = ["serialization"] } -colored = "2.0.0" -petgraph = "0.5.1" -serde = { version = "1.0.124", default-features = false } +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } +codespan = { workspace = true, features = ["serialization"] } +colored = { workspace = true } +petgraph = { workspace = true } +serde = { workspace = true } bcs = { workspace = true } move-binary-format = { path = "../../move-binary-format" } diff --git a/third_party/move/tools/move-disassembler/Cargo.toml b/third_party/move/tools/move-disassembler/Cargo.toml index f65b47e1e0caf..33babe7a7f674 100644 --- a/third_party/move/tools/move-disassembler/Cargo.toml +++ b/third_party/move/tools/move-disassembler/Cargo.toml @@ -8,8 +8,8 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -colored = "2.0.0" +anyhow = { workspace = true } +colored = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-bytecode-source-map = { path = "../../move-ir-compiler/move-bytecode-source-map" } @@ -19,7 +19,7 @@ move-core-types = { path = "../../move-core/types" } move-coverage = { path = "../move-coverage" } move-ir-types = { path = "../../move-ir/types" } -clap = { version = "4.3.9", features = ["derive"] } +clap = { workspace = true, features = ["derive"] } [features] default = [] diff --git a/third_party/move/tools/move-explain/Cargo.toml b/third_party/move/tools/move-explain/Cargo.toml index 91396df15ab1f..a6d982f3caa0e 100644 --- a/third_party/move/tools/move-explain/Cargo.toml +++ b/third_party/move/tools/move-explain/Cargo.toml @@ -10,7 +10,7 @@ publish = false edition = "2021" [dependencies] -clap = { version = "4.3.9", features = ["derive"] } +clap = { workspace = true, features = ["derive"] } move-command-line-common = { path = "../../move-command-line-common" } move-core-types = { path = "../../move-core/types" } diff --git a/third_party/move/tools/move-package/Cargo.toml b/third_party/move/tools/move-package/Cargo.toml index df001bade7f7e..ee1609ac73a64 100644 --- a/third_party/move/tools/move-package/Cargo.toml +++ b/third_party/move/tools/move-package/Cargo.toml @@ -8,23 +8,23 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -clap = { version = "4.3.9", features = ["derive"] } -colored = "2.0.0" -itertools = "0.10.0" -named-lock = "0.2.0" -once_cell = "1.7.2" -petgraph = "0.5.1" -regex = "1.1.9" -serde = { version = "1.0", features = ["derive"] } -serde_yaml = "0.8.17" -sha2 = "0.9.3" -tempfile = "3.2.0" -toml = "0.5.8" -walkdir = "2.3.1" +anyhow = { workspace = true } +clap = { workspace = true, features = ["derive"] } +colored = { workspace = true } +itertools = { workspace = true } +named-lock = { workspace = true } +once_cell = { workspace = true } +petgraph = { workspace = true } +regex = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_yaml = { workspace = true } +sha2 = { workspace = true } +tempfile = { workspace = true } +toml = { workspace = true } +walkdir = { workspace = true } evm-exec-utils = { path = "../../evm/exec-utils", optional = true } -hex = { version = "0.4.3", optional = true } +hex = { workspace = true, optional = true } move-abigen = { path = "../../move-prover/move-abigen" } move-binary-format = { path = "../../move-binary-format" } @@ -39,12 +39,12 @@ move-model = { path = "../../move-model" } move-symbol-pool = { path = "../../move-symbol-pool" } move-to-yul = { path = "../../evm/move-to-yul", optional = true } -termcolor = { version = "1.1.2" } +termcolor = { workspace = true } -whoami = { version = "1.5.0" } +whoami = { workspace = true } [dev-dependencies] -datatest-stable = "0.1.1" +datatest-stable = { workspace = true } [[test]] name = "test_runner" diff --git a/third_party/move/tools/move-package/src/compilation/compiled_package.rs b/third_party/move/tools/move-package/src/compilation/compiled_package.rs index 1796aa5fe7dac..987a152d6ba09 100644 --- a/third_party/move/tools/move-package/src/compilation/compiled_package.rs +++ b/third_party/move/tools/move-package/src/compilation/compiled_package.rs @@ -31,6 +31,7 @@ use move_compiler::{ shared::{Flags, NamedAddressMap, NumericalAddress, PackagePaths}, Compiler, }; +use move_compiler_v2::Experiment; use move_docgen::{Docgen, DocgenOptions}; use move_model::{ model::GlobalEnv, options::ModelBuilderOptions, @@ -637,7 +638,7 @@ impl CompiledPackage { let effective_language_version = config.language_version.unwrap_or_default(); effective_compiler_version.check_language_support(effective_language_version)?; - let (file_map, all_compiled_units, _optional_global_env) = match config + let (file_map, all_compiled_units, optional_global_env) = match config .compiler_version .unwrap_or_default() { @@ -671,8 +672,7 @@ impl CompiledPackage { } } } - - let options = move_compiler_v2::Options { + let mut options = move_compiler_v2::Options { sources: paths.iter().flat_map(|x| to_str_vec(&x.paths)).collect(), dependencies: bytecode_deps .iter() @@ -688,6 +688,7 @@ impl CompiledPackage { compile_test_code: flags.keep_testing_functions(), ..Default::default() }; + options = options.set_experiment(Experiment::ATTACH_COMPILED_MODULE, true); compiler_driver_v2(options)? }, }; @@ -747,13 +748,22 @@ impl CompiledPackage { if skip_attribute_checks { flags = flags.set_skip_attribute_checks(true) } - let model = run_model_builder_with_options_and_compilation_flags( - vec![sources_package_paths], - deps_package_paths.into_iter().map(|(p, _)| p).collect_vec(), - ModelBuilderOptions::default(), - flags, - &known_attributes, - )?; + + let model = match ( + resolution_graph.build_options.generate_docs, + resolution_graph.build_options.generate_abis, + optional_global_env, + ) { + (false, false, Some(env)) => env, // Use V2 generated model if not for docgen or abigen + _ => run_model_builder_with_options_and_compilation_flags( + // Otherwise, use V1 generated model + vec![sources_package_paths], + deps_package_paths.into_iter().map(|(p, _)| p).collect_vec(), + ModelBuilderOptions::default(), + flags, + &known_attributes, + )?, + }; if resolution_graph.build_options.generate_docs { compiled_docs = Some(Self::build_docs( diff --git a/third_party/move/tools/move-package/tests/test_sources/parsing/duplicate_address_names/Move.exp b/third_party/move/tools/move-package/tests/test_sources/parsing/duplicate_address_names/Move.exp index 946069e409f6b..02b7cfdc99007 100644 --- a/third_party/move/tools/move-package/tests/test_sources/parsing/duplicate_address_names/Move.exp +++ b/third_party/move/tools/move-package/tests/test_sources/parsing/duplicate_address_names/Move.exp @@ -1 +1,6 @@ -Unable to parse Move package manifest: duplicate key: `a` for key `addresses` at line 5 column 1 +Unable to parse Move package manifest: TOML parse error at line 7, column 1 + | +7 | a = "0x2" + | ^ +duplicate key `a` in table `addresses` + diff --git a/third_party/move/tools/move-package/tests/test_sources/parsing/duplicate_top_level_field/Move.exp b/third_party/move/tools/move-package/tests/test_sources/parsing/duplicate_top_level_field/Move.exp index c74ce542f744b..32f4476f0b14d 100644 --- a/third_party/move/tools/move-package/tests/test_sources/parsing/duplicate_top_level_field/Move.exp +++ b/third_party/move/tools/move-package/tests/test_sources/parsing/duplicate_top_level_field/Move.exp @@ -1 +1,7 @@ -Unable to parse Move package manifest: redefinition of table `package` for key `package` at line 5 column 1 +Unable to parse Move package manifest: TOML parse error at line 5, column 1 + | +5 | [package] + | ^ +invalid table header +duplicate key `package` in document root + diff --git a/third_party/move/tools/move-package/tests/test_sources/parsing/non_string_address_name/Move.exp b/third_party/move/tools/move-package/tests/test_sources/parsing/non_string_address_name/Move.exp index d84d0e1a68e7d..d254bd2a857eb 100644 --- a/third_party/move/tools/move-package/tests/test_sources/parsing/non_string_address_name/Move.exp +++ b/third_party/move/tools/move-package/tests/test_sources/parsing/non_string_address_name/Move.exp @@ -1,2 +1 @@ -Error parsing '[addresses]' section of manifest: Invalid address name b = "0x1" - encountered. Expected a string but found a table +Error parsing '[addresses]' section of manifest: Invalid address name { b = "0x1" } encountered. Expected a string but found a table diff --git a/third_party/move/tools/move-package/tests/test_sources/parsing/too_many_entries_renaming_instantiation/Move.exp b/third_party/move/tools/move-package/tests/test_sources/parsing/too_many_entries_renaming_instantiation/Move.exp index b6a6cc50d24a8..a704eef4a45ad 100644 --- a/third_party/move/tools/move-package/tests/test_sources/parsing/too_many_entries_renaming_instantiation/Move.exp +++ b/third_party/move/tools/move-package/tests/test_sources/parsing/too_many_entries_renaming_instantiation/Move.exp @@ -1,3 +1 @@ -Error parsing '[dependencies]' section of manifest: Malformed dependency substitution B = "0x1" -R = "0x2" -. Expected a string, but encountered a table +Error parsing '[dependencies]' section of manifest: Malformed dependency substitution { B = "0x1", R = "0x2" }. Expected a string, but encountered a table diff --git a/third_party/move/tools/move-package/tests/test_sources/parsing/version_not_a_string/Move.exp b/third_party/move/tools/move-package/tests/test_sources/parsing/version_not_a_string/Move.exp index 6a7795f55a5c2..2eb5314e36a94 100644 --- a/third_party/move/tools/move-package/tests/test_sources/parsing/version_not_a_string/Move.exp +++ b/third_party/move/tools/move-package/tests/test_sources/parsing/version_not_a_string/Move.exp @@ -1 +1,6 @@ -Unable to parse Move package manifest: expected newline, found a period at line 3 column 14 +Unable to parse Move package manifest: TOML parse error at line 3, column 14 + | +3 | version = 0.1.2 + | ^ +expected newline, `#` + diff --git a/third_party/move/tools/move-package/tests/test_sources/resolution/conflicting_dependencies/Move.exp b/third_party/move/tools/move-package/tests/test_sources/resolution/conflicting_dependencies/Move.exp index c194bad023fc6..404f45333f80c 100644 --- a/third_party/move/tools/move-package/tests/test_sources/resolution/conflicting_dependencies/Move.exp +++ b/third_party/move/tools/move-package/tests/test_sources/resolution/conflicting_dependencies/Move.exp @@ -1 +1,6 @@ -Unable to parse Move package manifest: duplicate key: `OtherDep` for key `dependencies` at line 5 column 1 +Unable to parse Move package manifest: TOML parse error at line 7, column 1 + | +7 | OtherDep = { local = "./deps_only/different_dep" } + | ^ +duplicate key `OtherDep` in table `dependencies` + diff --git a/third_party/move/tools/move-resource-viewer/Cargo.toml b/third_party/move/tools/move-resource-viewer/Cargo.toml index 725d947d8b97c..962de569ff390 100644 --- a/third_party/move/tools/move-resource-viewer/Cargo.toml +++ b/third_party/move/tools/move-resource-viewer/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" move-binary-format = { path = "../../move-binary-format" } move-bytecode-utils = { path = "../move-bytecode-utils" } move-core-types = { path = "../../move-core/types" } -serde = { version = "1.0.124", features = ["derive", "rc"] } +serde = { workspace = true, features = ["derive", "rc"] } -anyhow = "1.0.52" -hex = "0.4.3" +anyhow = { workspace = true } +hex = { workspace = true } diff --git a/third_party/move/tools/move-unit-test/Cargo.toml b/third_party/move/tools/move-unit-test/Cargo.toml index cdebeb6e842fc..3bd0fbfd08a6c 100644 --- a/third_party/move/tools/move-unit-test/Cargo.toml +++ b/third_party/move/tools/move-unit-test/Cargo.toml @@ -10,18 +10,18 @@ publish = false edition = "2021" [dependencies] -anyhow = "1.0.52" -better_any = "0.1.1" -clap = { version = "4.3.9", features = ["derive"] } -codespan-reporting = "0.11.1" -colored = "2.0.0" +anyhow = { workspace = true } +better_any = { workspace = true } +clap = { workspace = true, features = ["derive"] } +codespan-reporting = { workspace = true } +colored = { workspace = true } evm-exec-utils = { path = "../../evm/exec-utils", optional = true } -itertools = "0.10.1" +itertools = { workspace = true } move-binary-format = { path = "../../move-binary-format" } move-bytecode-utils = { path = "../move-bytecode-utils" } -once_cell = "1.7.2" -rayon = "1.5.0" -regex = "1.5.5" +once_cell = { workspace = true } +rayon = { workspace = true } +regex = { workspace = true } move-command-line-common = { path = "../../move-command-line-common" } move-compiler = { path = "../../move-compiler" } @@ -37,12 +37,12 @@ move-vm-test-utils = { path = "../../move-vm/test-utils" } # EVM-specific dependencies move-to-yul = { path = "../../evm/move-to-yul", optional = true } -evm = { version = "0.41.1", optional = true } -primitive-types = { version = "0.10.1", optional = true } +evm = { workspace = true, optional = true } +primitive-types = { workspace = true, optional = true } [dev-dependencies] -datatest-stable = "0.1.1" -difference = "2.0.0" +datatest-stable = { workspace = true } +difference = { workspace = true } [[bin]] name = "move-unit-test" @@ -55,6 +55,6 @@ harness = false [features] evm-backend = ["move-to-yul", "evm-exec-utils", "evm", "primitive-types"] table-extension = [ - "move-vm-test-utils/table-extension" + "move-vm-test-utils/table-extension" ] debugging = ["move-vm-runtime/debugging"] diff --git a/third_party/move/tools/move-unit-test/src/test_runner.rs b/third_party/move/tools/move-unit-test/src/test_runner.rs index 989835f388b60..4a2c34c21556e 100644 --- a/third_party/move/tools/move-unit-test/src/test_runner.rs +++ b/third_party/move/tools/move-unit-test/src/test_runner.rs @@ -22,7 +22,10 @@ use move_core_types::{ }; use move_resource_viewer::MoveValueAnnotator; use move_vm_runtime::{ - move_vm::MoveVM, native_extensions::NativeContextExtensions, + config::VMConfig, + module_traversal::{TraversalContext, TraversalStorage}, + move_vm::MoveVM, + native_extensions::NativeContextExtensions, native_functions::NativeFunctionTable, }; use move_vm_test_utils::{ @@ -252,6 +255,7 @@ impl<'a, 'b, W: Write> TestOutput<'a, 'b, W> { } impl SharedTestingConfig { + #[allow(clippy::field_reassign_with_default)] fn execute_via_move_vm( &self, test_plan: &ModuleTestPlan, @@ -263,7 +267,10 @@ impl SharedTestingConfig { VMResult>>, TestRunInfo, ) { - let move_vm = MoveVM::new(self.native_function_table.clone()).unwrap(); + let mut config = VMConfig::default(); + config.paranoid_type_checks = true; + + let move_vm = MoveVM::new_with_config(self.native_function_table.clone(), config).unwrap(); let extensions = extensions::new_extensions(); let mut session = move_vm.new_session_with_extensions(&self.starting_storage_state, extensions); @@ -271,12 +278,14 @@ impl SharedTestingConfig { // TODO: collect VM logs if the verbose flag (i.e, `self.verbose`) is set let now = Instant::now(); + let storage = TraversalStorage::new(); let serialized_return_values_result = session.execute_function_bypass_visibility( &test_plan.module_id, IdentStr::new(function_name).unwrap(), vec![], // no ty args, at least for now serialize_values(test_info.arguments.iter()), &mut gas_meter, + &mut TraversalContext::new(&storage), ); let mut return_result = serialized_return_values_result.map(|res| { res.return_values diff --git a/types/Cargo.toml b/types/Cargo.toml index af3ffd1a33cb8..b6f03e82452ea 100644 --- a/types/Cargo.toml +++ b/types/Cargo.toml @@ -70,6 +70,7 @@ passkey-client = { workspace = true } proptest = { workspace = true } proptest-derive = { workspace = true } regex = { workspace = true } +reqwest = { workspace = true } serde_json = { workspace = true } tokio = { workspace = true } url = { workspace = true } diff --git a/types/proptest-regressions/state_store/state_key.txt b/types/proptest-regressions/state_store/state_key.txt deleted file mode 100644 index 187b7428bcac5..0000000000000 --- a/types/proptest-regressions/state_store/state_key.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 877179e1169bbeee3194cdc5a43ae0662ad9220606ff994acac121b19b3e5009 # shrinks to key = TableItem { handle: 0000000000000000000000000000000000000000000000000000000000000000, key: } diff --git a/types/src/access_path.rs b/types/src/access_path.rs index 916f7f6d0dee9..92abe7e7ecad9 100644 --- a/types/src/access_path.rs +++ b/types/src/access_path.rs @@ -40,25 +40,42 @@ use crate::{ account_address::AccountAddress, - state_store::state_key::{StateKey, StateKeyInner}, + state_store::state_key::{inner::StateKeyInner, StateKey}, }; use anyhow::{Error, Result}; use aptos_crypto::hash::HashValue; use move_core_types::language_storage::{ModuleId, StructTag}; #[cfg(any(test, feature = "fuzzing"))] +use proptest::prelude::*; +#[cfg(any(test, feature = "fuzzing"))] use proptest_derive::Arbitrary; use serde::{Deserialize, Serialize}; use std::{convert::TryFrom, fmt, fmt::Formatter}; #[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)] -#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))] pub struct AccessPath { pub address: AccountAddress, #[serde(with = "serde_bytes")] pub path: Vec, } -#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)] +#[cfg(any(test, feature = "fuzzing"))] +impl Arbitrary for AccessPath { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (any::(), any::()) + .prop_map(|(address, path)| AccessPath { + address, + path: bcs::to_bytes(&path).unwrap(), + }) + .boxed() + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, Ord, PartialOrd)] +#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))] pub enum Path { Code(ModuleId), Resource(StructTag), @@ -208,8 +225,8 @@ impl TryFrom for AccessPath { type Error = Error; fn try_from(state_key: StateKey) -> Result { - match state_key.into_inner() { - StateKeyInner::AccessPath(access_path) => Ok(access_path), + match state_key.inner() { + StateKeyInner::AccessPath(access_path) => Ok(access_path.clone()), _ => anyhow::bail!("Unsupported state key type"), } } diff --git a/types/src/account_config/resources/coin_info.rs b/types/src/account_config/resources/coin_info.rs index 3ee5e1002f34b..6a9e4bcdc2618 100644 --- a/types/src/account_config/resources/coin_info.rs +++ b/types/src/account_config/resources/coin_info.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - access_path::AccessPath, state_store::{state_key::StateKey, table::TableHandle}, utility_coin::APTOS_COIN_TYPE, write_set::{WriteOp, WriteSet, WriteSetMut}, @@ -32,8 +31,7 @@ impl Aggregator { /// Helper function to return the state key where the actual value is stored. pub fn state_key(&self) -> StateKey { - let key_bytes = self.key.to_vec(); - StateKey::table_item(TableHandle(self.handle), key_bytes) + StateKey::table_item(&TableHandle(self.handle), self.key.as_ref()) } } @@ -110,10 +108,7 @@ impl CoinInfoResource { /// Returns a writeset corresponding to the creation of CoinInfo in Move. /// This can be passed to data store for testing total supply. - pub fn to_writeset(&self) -> anyhow::Result { - let ap = - AccessPath::resource_access_path(AccountAddress::ONE, CoinInfoResource::struct_tag())?; - + pub fn to_writeset(&self, supply: u128) -> anyhow::Result { let value_state_key = self .supply .as_ref() @@ -126,12 +121,12 @@ impl CoinInfoResource { // We store CoinInfo and aggregatable value separately. let write_set = vec![ ( - StateKey::access_path(ap), + StateKey::resource_typed::(&AccountAddress::ONE)?, WriteOp::legacy_modification(bcs::to_bytes(&self).unwrap().into()), ), ( value_state_key, - WriteOp::legacy_modification(bcs::to_bytes(&0_u128).unwrap().into()), + WriteOp::legacy_modification(bcs::to_bytes(&supply).unwrap().into()), ), ]; Ok(WriteSetMut::new(write_set).freeze().unwrap()) diff --git a/types/src/account_config/resources/fungible_store.rs b/types/src/account_config/resources/fungible_store.rs new file mode 100644 index 0000000000000..d57cf7ed09f8a --- /dev/null +++ b/types/src/account_config/resources/fungible_store.rs @@ -0,0 +1,57 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::{ + account_address::AccountAddress, + ident_str, + identifier::IdentStr, + move_resource::{MoveResource, MoveStructType}, +}; +#[cfg(any(test, feature = "fuzzing"))] +use proptest_derive::Arbitrary; +use serde::{Deserialize, Serialize}; + +pub fn primary_store(address: &AccountAddress) -> AccountAddress { + let mut bytes = address.to_vec(); + bytes.append(&mut AccountAddress::TEN.to_vec()); + bytes.push(0xFC); + AccountAddress::from_bytes(aptos_crypto::hash::HashValue::sha3_256_of(&bytes).to_vec()).unwrap() +} + +/// The balance resource held under an account. +#[derive(Debug, Serialize, Deserialize)] +#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))] +pub struct FungibleStoreResource { + metadata: AccountAddress, + balance: u64, + frozen: bool, +} + +impl FungibleStoreResource { + pub fn new(metadata: AccountAddress, balance: u64, frozen: bool) -> Self { + Self { + metadata, + balance, + frozen, + } + } + + pub fn metadata(&self) -> AccountAddress { + self.metadata + } + + pub fn balance(&self) -> u64 { + self.balance + } + + pub fn frozen(&self) -> bool { + self.frozen + } +} + +impl MoveStructType for FungibleStoreResource { + const MODULE_NAME: &'static IdentStr = ident_str!("fungible_asset"); + const STRUCT_NAME: &'static IdentStr = ident_str!("FungibleStore"); +} + +impl MoveResource for FungibleStoreResource {} diff --git a/types/src/account_config/resources/mod.rs b/types/src/account_config/resources/mod.rs index 97a02e94cb337..8859dfc40005d 100644 --- a/types/src/account_config/resources/mod.rs +++ b/types/src/account_config/resources/mod.rs @@ -7,6 +7,7 @@ pub mod challenge; pub mod coin_info; pub mod coin_store; pub mod core_account; +pub mod fungible_store; pub mod object; pub use chain_id::*; diff --git a/types/src/error.rs b/types/src/error.rs new file mode 100644 index 0000000000000..6e130826b06b0 --- /dev/null +++ b/types/src/error.rs @@ -0,0 +1,87 @@ +// Copyright © Aptos Foundation +// Parts of the project are originally copyright © Meta Platforms, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//! Error codes that follow the Move error convention of the Aptos Framework. + +/// Caller specified an invalid argument (http: 400) +pub const INVALID_ARGUMENT: u64 = 0x1; + +/// An input or result of a computation is out of range (http: 400) +pub const OUT_OF_RANGE: u64 = 0x2; + +/// The system is not in a state where the operation can be performed (http: 400) +pub const INVALID_STATE: u64 = 0x3; + +/// Request not authenticated due to missing, invalid, or expired auth token (http: 401) +pub const UNAUTHENTICATED: u64 = 0x4; + +/// client does not have sufficient permission (http: 403) +pub const PERMISSION_DENIED: u64 = 0x5; + +/// A specified resource is not found (http: 404) +pub const NOT_FOUND: u64 = 0x6; + +/// Concurrency conflict, such as read-modify-write conflict (http: 409) +pub const ABORTED: u64 = 0x7; + +/// The resource that a client tried to create already exists (http: 409) +pub const ALREADY_EXISTS: u64 = 0x8; + +/// Out of gas or other forms of quota (http: 429) +pub const RESOURCE_EXHAUSTED: u64 = 0x9; + +/// Request cancelled by the client (http: 499) +pub const CANCELLED: u64 = 0xA; + +/// Internal error (http: 500) +pub const INTERNAL: u64 = 0xB; + +/// Feature not implemented (http: 501) +pub const NOT_IMPLEMENTED: u64 = 0xC; + +/// The service is currently unavailable. Indicates that a retry could solve the issue (http: 503) +pub const UNAVAILABLE: u64 = 0xD; + +/// Construct a canonical error code from a category and a reason. +pub fn canonical(category: u64, reason: u64) -> u64 { + (category << 16) + reason +} + +/// Functions to construct a canonical error code of the given category. +pub fn invalid_argument(r: u64) -> u64 { + canonical(INVALID_ARGUMENT, r) +} +pub fn out_of_range(r: u64) -> u64 { + canonical(OUT_OF_RANGE, r) +} +pub fn invalid_state(r: u64) -> u64 { + canonical(INVALID_STATE, r) +} +pub fn unauthenticated(r: u64) -> u64 { + canonical(UNAUTHENTICATED, r) +} +pub fn permission_denied(r: u64) -> u64 { + canonical(PERMISSION_DENIED, r) +} +pub fn not_found(r: u64) -> u64 { + canonical(NOT_FOUND, r) +} +pub fn aborted(r: u64) -> u64 { + canonical(ABORTED, r) +} +pub fn already_exists(r: u64) -> u64 { + canonical(ALREADY_EXISTS, r) +} +pub fn resource_exhausted(r: u64) -> u64 { + canonical(RESOURCE_EXHAUSTED, r) +} +pub fn internal(r: u64) -> u64 { + canonical(INTERNAL, r) +} +pub fn not_implemented(r: u64) -> u64 { + canonical(NOT_IMPLEMENTED, r) +} +pub fn unavailable(r: u64) -> u64 { + canonical(UNAVAILABLE, r) +} diff --git a/types/src/executable.rs b/types/src/executable.rs index ea4454975cf5c..d1794e4650d10 100644 --- a/types/src/executable.rs +++ b/types/src/executable.rs @@ -3,7 +3,7 @@ use crate::{ access_path::AccessPath, - state_store::state_key::{StateKey, StateKeyInner}, + state_store::state_key::{inner::StateKeyInner, StateKey}, }; use aptos_crypto::HashValue; use std::sync::Arc; diff --git a/types/src/jwks/rsa/mod.rs b/types/src/jwks/rsa/mod.rs index 6017e7c5df1b2..806f89f972be4 100644 --- a/types/src/jwks/rsa/mod.rs +++ b/types/src/jwks/rsa/mod.rs @@ -58,7 +58,7 @@ impl RSA_JWK { } } - pub fn verify_signature(&self, jwt_token: &str) -> Result> { + pub fn verify_signature_without_exp_check(&self, jwt_token: &str) -> Result> { let mut validation = Validation::new(Algorithm::RS256); validation.validate_exp = false; let key = &DecodingKey::from_rsa_components(&self.n, &self.e)?; diff --git a/types/src/keyless/bn254_circom.rs b/types/src/keyless/bn254_circom.rs index d65fbaf3c72d9..5e3bb67873910 100644 --- a/types/src/keyless/bn254_circom.rs +++ b/types/src/keyless/bn254_circom.rs @@ -37,7 +37,7 @@ pub fn g1_projective_str_to_affine(x: &str, y: &str) -> anyhow::Result /// This will do the proper subgroup membership checks. pub fn g2_projective_str_to_affine(x: [&str; 2], y: [&str; 2]) -> anyhow::Result { - let g2_affine = G2Bytes::new_unchecked(x, y)?.as_affine()?; + let g2_affine = G2Bytes::new_unchecked(x, y)?.deserialize_into_affine()?; Ok(g2_affine) } @@ -171,7 +171,7 @@ impl G2Bytes { } } - pub fn as_affine(&self) -> Result { + pub fn deserialize_into_affine(&self) -> Result { self.try_into() } } @@ -309,11 +309,12 @@ pub fn get_public_inputs_hash( // println!("IDC: {}", idc); // println!("exp_timestamp_secs: {}", exp_timestamp_secs); // println!("exp_horizon_secs: {}", exp_horizon_secs); - // println!("iss field hash: {}", pk.iss_val); + // println!("iss field: {}", pk.iss_val); + // println!("iss field hash: {}", iss_field_hash); // println!("Has extra field: {}", has_extra_field); // println!("Extra field val: {:?}", proof.extra_field); // println!("Extra field hash: {}", extra_field_hash); - // println!("JWT header val: {}", jwt_header_with_separator); + // println!("JWT header val: {}", jwt_header_b64_with_separator); // println!("JWT header hash: {}", jwt_header_hash); // println!("JWK hash: {}", jwk_hash); // println!("Override aud hash: {}", override_aud_val_hash); diff --git a/types/src/keyless/circuit_constants.rs b/types/src/keyless/circuit_constants.rs index cb96cb8af6b4e..00f86e1900329 100644 --- a/types/src/keyless/circuit_constants.rs +++ b/types/src/keyless/circuit_constants.rs @@ -55,12 +55,12 @@ pub fn devnet_prepared_vk() -> PreparedVerifyingKey { let delta_g2 = g2_projective_str_to_affine( [ - "11038625261519760309511691545722998501631692377566390215069950407690100922829", - "9045018223873734526503532473687024591416925617500500581428042052317762793759", + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634", ], [ - "20166732306934471422121024584846381419879187010146836985740993661927686641928", - "15544422242248962072995604691444439927989259756652133409538743550999342479668", + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531", ], ) .unwrap(); @@ -68,13 +68,13 @@ pub fn devnet_prepared_vk() -> PreparedVerifyingKey { let mut gamma_abc_g1 = Vec::new(); for points in [ g1_projective_str_to_affine( - "19969429920450141902172268650961329312290082884093184976727612790263548895589", - "5146534318147005445214564431741941940406412758913409113743201385319569618289", + "19759886250806183187785579505109257837989251596255610913102572077808842056375", + "8515569072948108462120402914801299810016610043704833841603450087200707784492", ) .unwrap(), g1_projective_str_to_affine( - "15192959234143920396735876774520785358155749431089461580802816710466908168006", - "18346895842267323773878010013182465710347574804392898846929667361700890467565", + "18250059095913215666541561118844673017538035392793529003420365565251085504261", + "21846936675713878002567053788450833465715833259428778772043736890983365407823", ) .unwrap(), ] { diff --git a/types/src/keyless/circuit_testcases.rs b/types/src/keyless/circuit_testcases.rs index bccc980421987..bcd7d573e1d55 100644 --- a/types/src/keyless/circuit_testcases.rs +++ b/types/src/keyless/circuit_testcases.rs @@ -9,11 +9,14 @@ use crate::{ keyless::{ base64url_encode_str, bn254_circom::{G1Bytes, G2Bytes}, - Claims, Configuration, Groth16Proof, IdCommitment, KeylessPublicKey, OpenIdSig, Pepper, + g1_projective_str_to_affine, g2_projective_str_to_affine, Claims, Configuration, + Groth16Proof, IdCommitment, KeylessPublicKey, OpenIdSig, Pepper, }, transaction::authenticator::EphemeralPublicKey, }; use aptos_crypto::{ed25519::Ed25519PrivateKey, PrivateKey, Uniform}; +use ark_bn254::Bn254; +use ark_groth16::{PreparedVerifyingKey, VerifyingKey}; use once_cell::sync::Lazy; use ring::signature::RsaKeyPair; use rsa::{pkcs1::EncodeRsaPrivateKey, pkcs8::DecodePrivateKey}; @@ -46,17 +49,38 @@ static SAMPLE_NONCE: Lazy = Lazy::new(|| { pub(crate) const SAMPLE_TEST_ISS_VALUE: &str = "test.oidc.provider"; -/// TODO(keyless): Use a multiline format here, for diff-friendliness pub(crate) static SAMPLE_JWT_PAYLOAD_JSON: Lazy = Lazy::new(|| { format!( - r#"{{"iss":"{}","azp":"407408718192.apps.googleusercontent.com","aud":"407408718192.apps.googleusercontent.com","sub":"113990307082899718775","hd":"aptoslabs.com","email":"michael@aptoslabs.com","email_verified":true,"at_hash":"bxIESuI59IoZb5alCASqBg","name":"Michael Straka","picture":"https://lh3.googleusercontent.com/a/ACg8ocJvY4kVUBRtLxe1IqKWL5i7tBDJzFp9YuWVXMzwPpbs=s96-c","given_name":"Michael","family_name":"Straka","locale":"en","iat":1700255944,"exp":2700259544,"nonce":"{}"}}"#, + r#"{{ + "iss":"{}", + "azp":"407408718192.apps.googleusercontent.com", + "aud":"407408718192.apps.googleusercontent.com", + "sub":"113990307082899718775", + "hd":"aptoslabs.com", + "email":"michael@aptoslabs.com", + "email_verified":true, + "at_hash":"bxIESuI59IoZb5alCASqBg", + "name":"Michael Straka", + "picture":"https://lh3.googleusercontent.com/a/ACg8ocJvY4kVUBRtLxe1IqKWL5i7tBDJzFp9YuWVXMzwPpbs=s96-c", + "given_name":"Michael", + {} + "locale":"en", + "iat":1700255944, + "nonce":"{}", + "exp":2700259544 + }}"#, SAMPLE_TEST_ISS_VALUE, + SAMPLE_JWT_EXTRA_FIELD.as_str(), SAMPLE_NONCE.as_str() ) }); /// Consistent with what is in `SAMPLE_JWT_PAYLOAD_JSON` -pub(crate) const SAMPLE_JWT_EXTRA_FIELD: &str = r#""family_name":"Straka","#; +pub(crate) const SAMPLE_JWT_EXTRA_FIELD_KEY: &str = "family_name"; + +/// Consistent with what is in `SAMPLE_JWT_PAYLOAD_JSON` +pub(crate) static SAMPLE_JWT_EXTRA_FIELD: Lazy = + Lazy::new(|| format!(r#""{}":"Straka","#, SAMPLE_JWT_EXTRA_FIELD_KEY)); /// The JWT parsed as a struct pub(crate) static SAMPLE_JWT_PARSED: Lazy = @@ -65,7 +89,7 @@ pub(crate) static SAMPLE_JWT_PARSED: Lazy = /// The JWK under which the JWT is signed, taken from https://token.dev pub(crate) static SAMPLE_JWK: Lazy = Lazy::new(|| { RSA_JWK { - kid: "test_jwk".to_owned(), + kid: "test-rsa".to_owned(), kty: "RSA".to_owned(), alg: "RS256".to_owned(), e: "AQAB".to_owned(), @@ -129,7 +153,11 @@ pub(crate) static SAMPLE_ESK: Lazy = pub(crate) static SAMPLE_EPK: Lazy = Lazy::new(|| EphemeralPublicKey::ed25519(SAMPLE_ESK.public_key())); -pub(crate) static SAMPLE_EPK_BLINDER: Lazy> = Lazy::new(|| vec![42u8]); +pub(crate) static SAMPLE_EPK_BLINDER: Lazy> = Lazy::new(|| { + let mut byte_vector = vec![0; 31]; + byte_vector[0] = 42; + byte_vector +}); pub(crate) static SAMPLE_PK: Lazy = Lazy::new(|| { assert_eq!(SAMPLE_UID_KEY, "sub"); @@ -153,9 +181,9 @@ pub(crate) static SAMPLE_PK: Lazy = Lazy::new(|| { /// https://github.com/aptos-labs/devnet-groth16-keys/commit/02e5675f46ce97f8b61a4638e7a0aaeaa4351f76 pub(crate) static SAMPLE_PROOF: Lazy = Lazy::new(|| { Groth16Proof::new( - G1Bytes::new_from_vec(hex::decode("bc1b31c0d35d8ea1086640f209dc1fda01d9b57e7aff138687549ece67f45780").unwrap()).unwrap(), - G2Bytes::new_from_vec(hex::decode("7104f991a6324f8e8287e2f6e32b225b65b90ed33d02a8105652c889ecf8b50672bbc55caf9ff0fcd07d5c26fbaa6ffd0d24c690aed4ee8ee8cebfdfc51e2d1b").unwrap()).unwrap(), - G1Bytes::new_from_vec(hex::decode("246c9d4b5029b41274dfa53491061f6d1358a7a1b02988f9959091e5f871aba2").unwrap()).unwrap(), + G1Bytes::new_from_vec(hex::decode("0093f692e4b0fb2e04acf52b862abf7d629a729cc1cd888ff46843dd4ced0d2e").unwrap()).unwrap(), + G2Bytes::new_from_vec(hex::decode("2e8deaf247490013eef4d8bbb1a407e72bf932cd141ef9347b1b49c0c4cc5a12b1ffd67e3b1119b384f4c821df35f9d3540f027c3766a4a4acc67cc0d804ff28").unwrap()).unwrap(), + G1Bytes::new_from_vec(hex::decode("a94683ea56b099fafb157321a52ddd7578f1ba5dc85acef3e231d1b5f1c03713").unwrap()).unwrap(), ) }); @@ -166,8 +194,91 @@ pub(crate) static SAMPLE_PROOF: Lazy = Lazy::new(|| { /// https://github.com/aptos-labs/devnet-groth16-keys/commit/02e5675f46ce97f8b61a4638e7a0aaeaa4351f76 pub(crate) static SAMPLE_PROOF_NO_EXTRA_FIELD: Lazy = Lazy::new(|| { Groth16Proof::new( - G1Bytes::new_from_vec(hex::decode("8f350299bbbd9d3d9940c893186f0a187d488214f6e2de928afc44ccd314d10d").unwrap()).unwrap(), - G2Bytes::new_from_vec(hex::decode("d90534077ba332278b4850218855a1e370aa77aaaf4c7ae35b5ba42d4073e40b9b89a667f74e608558baab4f44758ffeff0b081d46735c8044f7e03f57e0d012").unwrap()).unwrap(), - G1Bytes::new_from_vec(hex::decode("96ce90fd67ede76d4b6eb19a116f2a52b9f4e86d82c6d94a18731de8d2794819").unwrap()).unwrap(), + G1Bytes::new_from_vec(hex::decode("6bfcb02a4a0c4aaefa70b3d5a535d1a306c2b23cc6bb23f0c25992e5e3839324").unwrap()).unwrap(), + G2Bytes::new_from_vec(hex::decode("55af188580d37264a4876560bbe763b608be566849697778830aa0d47ab27129434d02b33179a6c39c648f1bf0c3074e48c5b58a63aba83b3567a7fc6de87202").unwrap()).unwrap(), + G1Bytes::new_from_vec(hex::decode("49513acd5cf07b77d1558387d14b69ebe55a95a886ebb735dc73d456b1116113").unwrap()).unwrap(), + ) +}); + +/// A new Groth16 VK to test the VK rotation. +pub(crate) static SAMPLE_UPGRADED_VK: Lazy> = Lazy::new(|| { + let alpha_g1 = g1_projective_str_to_affine( + "20491192805390485299153009773594534940189261866228447918068658471970481763042", + "9383485363053290200918347156157836566562967994039712273449902621266178545958", + ) + .unwrap(); + + let beta_g2 = g2_projective_str_to_affine( + [ + "6375614351688725206403948262868962793625744043794305715222011528459656738731", + "4252822878758300859123897981450591353533073413197771768651442665752259397132", + ], + [ + "10505242626370262277552901082094356697409835680220590971873171140371331206856", + "21847035105528745403288232691147584728191162732299865338377159692350059136679", + ], + ) + .unwrap(); + + let gamma_g2 = g2_projective_str_to_affine( + [ + "10857046999023057135944570762232829481370756359578518086990519993285655852781", + "11559732032986387107991004021392285783925812861821192530917403151452391805634", + ], + [ + "8495653923123431417604973247489272438418190587263600148770280649306958101930", + "4082367875863433681332203403145435568316851327593401208105741076214120093531", + ], + ) + .unwrap(); + + let delta_g2 = g2_projective_str_to_affine( + [ + "15739617451905904008434505563810388078669603068902989994513586227673794325099", + "21857380320483623058628157959587768917537193338055331958890662600728443003915", + ], + [ + "19098250091710633666997475602144489052978746302163092635335135789683361496958", + "5464980335669797405967071507706948120862078317539655982950789440091501244210", + ], + ) + .unwrap(); + + let mut gamma_abc_g1 = Vec::new(); + for points in [ + g1_projective_str_to_affine( + "19759886250806183187785579505109257837989251596255610913102572077808842056375", + "8515569072948108462120402914801299810016610043704833841603450087200707784492", + ) + .unwrap(), + g1_projective_str_to_affine( + "18250059095913215666541561118844673017538035392793529003420365565251085504261", + "21846936675713878002567053788450833465715833259428778772043736890983365407823", + ) + .unwrap(), + ] { + gamma_abc_g1.push(points); + } + + let vk = VerifyingKey { + alpha_g1, + beta_g2, + gamma_g2, + delta_g2, + gamma_abc_g1, + }; + + // println!("SAMPLE_UPGRADED_VK: {}", Groth16VerificationKey::from(&PreparedVerifyingKey::from(vk)).hash()); + + PreparedVerifyingKey::from(vk) +}); + +/// Like `SAMPLE_PROOF` but w.r.t. to `SAMPLE_UPGRADED_VK`. +pub(crate) static SAMPLE_PROOF_FOR_UPGRADED_VK: Lazy = Lazy::new(|| { + Groth16Proof::new( + G1Bytes::new_from_vec(hex::decode("f8c6b4182fcb28be5e1392297e86e03ed97c0166fcda3861cdb2b17a77778006").unwrap()).unwrap(), + G2Bytes::new_from_vec(hex::decode("0264b7e4bb0ab8eecbed406f02d11f6b0c22a055aa9918a84a81bcf93a5a1324be81a8098c44127eab5cc4fb9cf06d58e1562d69d3b43686d82a1886fd41bf15").unwrap()).unwrap(), + G1Bytes::new_from_vec(hex::decode("58c3e6c6ad0fa09123e4c415b3759b8b61d9ffebf90119b7592a5dc707016299").unwrap()).unwrap(), ) + // println!("SAMPLE_PROOF_FOR_UPGRADED_VK: {}", &proof.hash()); }); diff --git a/types/src/keyless/groth16_sig.rs b/types/src/keyless/groth16_sig.rs index 1308f25aa1301..917ef6bf1081f 100644 --- a/types/src/keyless/groth16_sig.rs +++ b/types/src/keyless/groth16_sig.rs @@ -9,9 +9,9 @@ use crate::{ }, zkp_sig::ZKP, }, - transaction::authenticator::{EphemeralPublicKey, EphemeralSignature}, + transaction::authenticator::EphemeralSignature, }; -use anyhow::{anyhow, bail}; +use anyhow::bail; use aptos_crypto::CryptoMaterialError; use aptos_crypto_derive::{BCSCryptoHash, CryptoHasher}; use ark_bn254::{Bn254, Fr}; @@ -50,13 +50,28 @@ pub struct ZeroKnowledgeSig { /// This struct is used to wrap together the Groth16 ZKP and the statement it proves so that the /// prover service can sign them together. It is only used during signature verification & never /// sent over the network. -#[derive(Debug, CryptoHasher, BCSCryptoHash, PartialEq, Eq)] +#[derive(Clone, Debug, CryptoHasher, BCSCryptoHash, Hash, PartialEq, Eq)] pub struct Groth16ProofAndStatement { pub proof: Groth16Proof, // TODO(keyless): implement Serialize/Deserialize for Fr and use Fr here directly pub public_inputs_hash: [u8; 32], } +impl Groth16ProofAndStatement { + pub fn new(proof: Groth16Proof, public_inputs_hash: Fr) -> Self { + let public_inputs_hash: [u8; 32] = public_inputs_hash + .into_bigint() + .to_bytes_le() + .try_into() + .expect("expected 32-byte public inputs hash"); + + Groth16ProofAndStatement { + proof, + public_inputs_hash, + } + } +} + impl<'de> Deserialize<'de> for Groth16ProofAndStatement { fn deserialize(deserializer: D) -> std::result::Result where @@ -140,32 +155,6 @@ impl Serialize for Groth16ProofAndStatement { } impl ZeroKnowledgeSig { - pub fn verify_training_wheels_sig( - &self, - pub_key: &EphemeralPublicKey, - public_inputs_hash: &Fr, - ) -> anyhow::Result<()> { - if let Some(training_wheels_signature) = &self.training_wheels_signature { - let public_inputs_hash: [u8; 32] = public_inputs_hash - .into_bigint() - .to_bytes_le() - .try_into() - .map_err(|_| anyhow!("expected 32-byte public inputs hash"))?; - - // TODO(keyless): unnecessary cloning here; requires refactoring of our CryptoHasher trait which requires Deserialize to be implemented - let proof_and_statement = Groth16ProofAndStatement { - proof: match self.proof { - ZKP::Groth16(proof) => proof, - }, - public_inputs_hash, - }; - - training_wheels_signature.verify(&proof_and_statement, pub_key) - } else { - bail!("No training_wheels_signature found") - } - } - pub fn verify_groth16_proof( &self, public_inputs_hash: Fr, @@ -217,13 +206,18 @@ impl Groth16Proof { public_inputs_hash: Fr, pvk: &PreparedVerifyingKey, ) -> anyhow::Result<()> { + // let start = std::time::Instant::now(); let proof: Proof = Proof { a: self.a.deserialize_into_affine()?, - b: self.b.as_affine()?, + b: self.b.deserialize_into_affine()?, c: self.c.deserialize_into_affine()?, }; - let result = Groth16::::verify_proof(pvk, &proof, &[public_inputs_hash])?; - if !result { + // println!("Deserialization time: {:?}", start.elapsed()); + + // let start = std::time::Instant::now(); + let verified = Groth16::::verify_proof(pvk, &proof, &[public_inputs_hash])?; + // println!("Proof verification time: {:?}", start.elapsed()); + if !verified { bail!("groth16 proof verification failed") } Ok(()) diff --git a/types/src/keyless/groth16_vk.rs b/types/src/keyless/groth16_vk.rs index 8424b16054cb1..263fcd7a36955 100644 --- a/types/src/keyless/groth16_vk.rs +++ b/types/src/keyless/groth16_vk.rs @@ -5,6 +5,7 @@ use crate::{ keyless::KEYLESS_ACCOUNT_MODULE_NAME, move_utils::as_move_value::AsMoveValue, serialize, }; use aptos_crypto::CryptoMaterialError; +use aptos_crypto_derive::{BCSCryptoHash, CryptoHasher}; use ark_bn254::{Bn254, G1Affine, G2Affine}; use ark_groth16::{PreparedVerifyingKey, VerifyingKey}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -18,7 +19,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; /// Reflection of aptos_framework::keyless_account::Groth16VerificationKey -#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)] +#[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Debug, BCSCryptoHash, CryptoHasher)] pub struct Groth16VerificationKey { pub alpha_g1: Vec, pub beta_g2: Vec, @@ -50,10 +51,22 @@ impl TryFrom for PreparedVerifyingKey { type Error = CryptoMaterialError; fn try_from(vk: Groth16VerificationKey) -> Result { + (&vk).try_into() + } +} + +impl TryFrom<&Groth16VerificationKey> for PreparedVerifyingKey { + type Error = CryptoMaterialError; + + fn try_from(vk: &Groth16VerificationKey) -> Result { if vk.gamma_abc_g1.len() != 2 { return Err(CryptoMaterialError::DeserializationError); } + // NOTE: Technically, we already validate the points when we set the VK in Move, so we could + // make this 2x faster by avoiding the point validation checks via + // `deserialize_with_mode(..., Compress::Yes, Validate::No)`. Due to paranoia, will not + // optimize this for now. Ok(Self::from(VerifyingKey { alpha_g1: G1Affine::deserialize_compressed(vk.alpha_g1.as_slice()) .map_err(|_| CryptoMaterialError::DeserializationError)?, @@ -75,6 +88,12 @@ impl TryFrom for PreparedVerifyingKey { impl From> for Groth16VerificationKey { fn from(pvk: PreparedVerifyingKey) -> Self { + (&pvk).into() + } +} + +impl From<&PreparedVerifyingKey> for Groth16VerificationKey { + fn from(pvk: &PreparedVerifyingKey) -> Self { let PreparedVerifyingKey { vk: VerifyingKey { @@ -104,6 +123,13 @@ impl From> for Groth16VerificationKey { } } +impl PartialEq> for Groth16VerificationKey { + fn eq(&self, other: &PreparedVerifyingKey) -> bool { + let other_vk: Groth16VerificationKey = other.into(); + self == &other_vk + } +} + impl Display for Groth16VerificationKey { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "alpha_g1: {}", hex::encode(&self.alpha_g1))?; diff --git a/types/src/keyless/mod.rs b/types/src/keyless/mod.rs index f3d9522e353d7..96d99328dc80e 100644 --- a/types/src/keyless/mod.rs +++ b/types/src/keyless/mod.rs @@ -99,7 +99,7 @@ pub struct KeylessSignature { /// A short lived public key used to verify the `ephemeral_signature`. pub ephemeral_pubkey: EphemeralPublicKey, - /// A signature ove the transaction and, if present, the ZKP, under `ephemeral_pubkey`. + /// A signature over the transaction and, if present, the ZKP, under `ephemeral_pubkey`. /// The ZKP is included in this signature to prevent malleability attacks. pub ephemeral_signature: EphemeralSignature, } diff --git a/types/src/keyless/openid_sig.rs b/types/src/keyless/openid_sig.rs index c08b0e79c8d47..e61cae065beba 100644 --- a/types/src/keyless/openid_sig.rs +++ b/types/src/keyless/openid_sig.rs @@ -126,7 +126,7 @@ impl OpenIdSig { base64url_encode_str(&self.jwt_payload_json), base64url_encode_bytes(&self.jwt_sig) ); - rsa_jwk.verify_signature(&jwt_b64)?; + rsa_jwk.verify_signature_without_exp_check(&jwt_b64)?; Ok(()) } diff --git a/types/src/keyless/test_utils.rs b/types/src/keyless/test_utils.rs index 5484eccdaf2cc..e3433a87de39e 100644 --- a/types/src/keyless/test_utils.rs +++ b/types/src/keyless/test_utils.rs @@ -10,7 +10,8 @@ use crate::{ SAMPLE_EPK, SAMPLE_EPK_BLINDER, SAMPLE_ESK, SAMPLE_EXP_DATE, SAMPLE_EXP_HORIZON_SECS, SAMPLE_JWK, SAMPLE_JWK_SK, SAMPLE_JWT_EXTRA_FIELD, SAMPLE_JWT_HEADER_B64, SAMPLE_JWT_HEADER_JSON, SAMPLE_JWT_PARSED, SAMPLE_JWT_PAYLOAD_JSON, SAMPLE_PEPPER, - SAMPLE_PK, SAMPLE_PROOF, SAMPLE_PROOF_NO_EXTRA_FIELD, SAMPLE_UID_KEY, + SAMPLE_PK, SAMPLE_PROOF, SAMPLE_PROOF_FOR_UPGRADED_VK, SAMPLE_PROOF_NO_EXTRA_FIELD, + SAMPLE_UID_KEY, SAMPLE_UPGRADED_VK, }, get_public_inputs_hash, zkp_sig::ZKP, @@ -22,6 +23,8 @@ use crate::{ use aptos_crypto::{ ed25519::Ed25519PrivateKey, poseidon_bn254::fr_to_bytes_le, SigningKey, Uniform, }; +use ark_bn254::Bn254; +use ark_groth16::PreparedVerifyingKey; use base64::{encode_config, URL_SAFE_NO_PAD}; use once_cell::sync::Lazy; use ring::signature; @@ -50,6 +53,22 @@ pub fn get_sample_pepper() -> Pepper { SAMPLE_PEPPER.clone() } +pub fn get_sample_epk_blinder() -> Vec { + SAMPLE_EPK_BLINDER.clone() +} + +pub fn get_sample_exp_date() -> u64 { + SAMPLE_EXP_DATE +} + +pub fn get_sample_jwt_header_json() -> String { + SAMPLE_JWT_HEADER_JSON.to_string() +} + +pub fn get_sample_uid_key() -> String { + SAMPLE_UID_KEY.to_string() +} + pub fn get_sample_groth16_zkp_and_statement() -> Groth16ProofAndStatement { let config = Configuration::new_for_testing(); let (sig, pk) = get_sample_groth16_sig_and_pk(); @@ -99,6 +118,34 @@ pub fn get_sample_groth16_sig_and_pk() -> (KeylessSignature, KeylessPublicKey) { (sig, SAMPLE_PK.clone()) } +pub fn get_upgraded_vk() -> PreparedVerifyingKey { + SAMPLE_UPGRADED_VK.clone() +} + +/// Note: Does not have a valid ephemeral signature. Use the SAMPLE_ESK to compute one over the +/// desired TXN. +pub fn get_groth16_sig_and_pk_for_upgraded_vk() -> (KeylessSignature, KeylessPublicKey) { + let proof = *SAMPLE_PROOF_FOR_UPGRADED_VK; + + let zks = ZeroKnowledgeSig { + proof: proof.into(), + extra_field: Some(SAMPLE_JWT_EXTRA_FIELD.to_string()), + exp_horizon_secs: SAMPLE_EXP_HORIZON_SECS, + override_aud_val: None, + training_wheels_signature: None, + }; + + let sig = KeylessSignature { + cert: EphemeralCertificate::ZeroKnowledgeSig(zks.clone()), + jwt_header_json: SAMPLE_JWT_HEADER_JSON.to_string(), + exp_date_secs: SAMPLE_EXP_DATE, + ephemeral_pubkey: SAMPLE_EPK.clone(), + ephemeral_signature: DUMMY_EPHEMERAL_SIGNATURE.clone(), + }; + + (sig, SAMPLE_PK.clone()) +} + /// Note: Does not have a valid ephemeral signature. Use the SAMPLE_ESK to compute one over the /// desired TXN. pub fn get_sample_groth16_sig_and_pk_no_extra_field() -> (KeylessSignature, KeylessPublicKey) { @@ -123,9 +170,7 @@ pub fn get_sample_groth16_sig_and_pk_no_extra_field() -> (KeylessSignature, Keyl (sig, SAMPLE_PK.clone()) } -/// Note: Does not have a valid ephemeral signature. Use the SAMPLE_ESK to compute one over the -/// desired TXN. -pub fn get_sample_openid_sig_and_pk() -> (KeylessSignature, KeylessPublicKey) { +pub fn get_sample_jwt_token() -> String { let jwt_header_b64 = SAMPLE_JWT_HEADER_B64.to_string(); let jwt_payload_b64 = base64url_encode_str(SAMPLE_JWT_PAYLOAD_JSON.as_str()); let msg = jwt_header_b64.clone() + "." + jwt_payload_b64.as_str(); @@ -143,7 +188,26 @@ pub fn get_sample_openid_sig_and_pk() -> (KeylessSignature, KeylessPublicKey) { let base64url_string = encode_config(jwt_sig.clone(), URL_SAFE_NO_PAD); - println!("JWT token is: {}.{}", msg, base64url_string); + format!("{}.{}", msg, base64url_string) +} + +/// Note: Does not have a valid ephemeral signature. Use the SAMPLE_ESK to compute one over the +/// desired TXN. +pub fn get_sample_openid_sig_and_pk() -> (KeylessSignature, KeylessPublicKey) { + let jwt_header_b64 = SAMPLE_JWT_HEADER_B64.to_string(); + let jwt_payload_b64 = base64url_encode_str(SAMPLE_JWT_PAYLOAD_JSON.as_str()); + let msg = jwt_header_b64.clone() + "." + jwt_payload_b64.as_str(); + let rng = ring::rand::SystemRandom::new(); + let sk = &*SAMPLE_JWK_SK; + let mut jwt_sig = vec![0u8; sk.public_modulus_len()]; + + sk.sign( + &signature::RSA_PKCS1_SHA256, + &rng, + msg.as_bytes(), + jwt_sig.as_mut_slice(), + ) + .unwrap(); let openid_sig = OpenIdSig { jwt_sig, @@ -197,12 +261,26 @@ pub fn maul_raw_groth16_txn( #[cfg(test)] mod test { - use crate::keyless::{ - circuit_testcases::{SAMPLE_EPK, SAMPLE_EPK_BLINDER, SAMPLE_EXP_DATE, SAMPLE_JWK}, - get_public_inputs_hash, - test_utils::get_sample_groth16_sig_and_pk, - Configuration, OpenIdSig, + use crate::{ + keyless::{ + circuit_testcases::{ + SAMPLE_EPK, SAMPLE_EPK_BLINDER, SAMPLE_EXP_DATE, SAMPLE_EXP_HORIZON_SECS, + SAMPLE_JWK, SAMPLE_JWT_EXTRA_FIELD_KEY, + }, + get_public_inputs_hash, + test_utils::{ + get_sample_epk_blinder, get_sample_esk, get_sample_exp_date, + get_sample_groth16_sig_and_pk, get_sample_jwt_token, get_sample_pepper, + }, + Configuration, Groth16Proof, OpenIdSig, DEVNET_VERIFICATION_KEY, + }, + transaction::authenticator::EphemeralPublicKey, }; + use aptos_crypto::PrivateKey; + use ark_ff::PrimeField; + use reqwest::Client; + use serde_json::{json, Value}; + use std::ops::Deref; /// Since our proof generation toolkit is incomplete; currently doing it here. #[test] @@ -227,4 +305,97 @@ mod test { println!("Public inputs hash: {}", public_inputs_hash); } + + #[derive(Debug, serde::Deserialize)] + struct ProverResponse { + proof: Groth16Proof, + #[serde(with = "hex")] + public_inputs_hash: [u8; 32], + } + + // Run the prover service locally - https://github.com/aptos-labs/prover-service + // Then run ./scripts/dev_setup.sh + // Lastly run ./scripts/run_test_server.sh + #[ignore] + #[tokio::test] + async fn fetch_sample_proofs_from_prover() { + let client = Client::new(); + + let body = json!({ + "jwt_b64": get_sample_jwt_token(), + "epk": hex::encode(bcs::to_bytes(&EphemeralPublicKey::ed25519(get_sample_esk().public_key())).unwrap()), + "epk_blinder": hex::encode(get_sample_epk_blinder()), + "exp_date_secs": get_sample_exp_date(), + "exp_horizon_secs": SAMPLE_EXP_HORIZON_SECS, + "pepper": hex::encode(get_sample_pepper().to_bytes()), + "uid_key": "sub", + "extra_field": SAMPLE_JWT_EXTRA_FIELD_KEY + }); + make_prover_request(&client, body, "SAMPLE_PROOF").await; + + let body = json!({ + "jwt_b64": get_sample_jwt_token(), + "epk": hex::encode(bcs::to_bytes(&EphemeralPublicKey::ed25519(get_sample_esk().public_key())).unwrap()), + "epk_blinder": hex::encode(get_sample_epk_blinder()), + "exp_date_secs": get_sample_exp_date(), + "exp_horizon_secs": SAMPLE_EXP_HORIZON_SECS, + "pepper": hex::encode(get_sample_pepper().to_bytes()), + "uid_key": "sub" + }); + make_prover_request(&client, body, "SAMPLE_PROOF_NO_EXTRA_FIELD").await; + } + + async fn make_prover_request( + client: &Client, + body: Value, + test_proof_name: &str, + ) -> ProverResponse { + let url = "http://localhost:8080/v0/prove"; + + // Send the POST request and await the response + let response = client.post(url).json(&body).send().await.unwrap(); + + // Check if the request was successful + if response.status().is_success() { + let prover_response = response.json::().await.unwrap(); + let proof = prover_response.proof; + let public_inputs_hash = + ark_bn254::Fr::from_le_bytes_mod_order(&prover_response.public_inputs_hash); + + let code = format!( + r#" + Groth16Proof::new( + G1Bytes::new_from_vec(hex::decode("{}").unwrap()).unwrap(), + G2Bytes::new_from_vec(hex::decode("{}").unwrap()).unwrap(), + G1Bytes::new_from_vec(hex::decode("{}").unwrap()).unwrap(), + ) + "#, + hex::encode(proof.get_a().0), + hex::encode(proof.get_b().0), + hex::encode(proof.get_c().0) + ); + println!(); + println!( + "----- Update the {} in circuit_testcases.rs with the output below -----", + test_proof_name + ); + println!("{}", code); + println!("----------------------------------------------------------------------------------"); + + // TODO: Assumes proofs are to be generated w.r.t the devnet VK. This must be manually + // modified to deal with generating proofs for a different VK. + + // Verify the proof with the test verifying key. If this fails the verifying key does not match the proving used + // to generate the proof. + proof + .verify_proof(public_inputs_hash, DEVNET_VERIFICATION_KEY.deref()) + .unwrap(); + + prover_response + } else { + // Print an error message if the request failed + println!("Request failed with status code: {}", response.status()); + panic!("Prover request failed") + } + } } diff --git a/types/src/keyless/tests.rs b/types/src/keyless/tests.rs index 3e6587c6d57bc..9e0c81a7e34d0 100644 --- a/types/src/keyless/tests.rs +++ b/types/src/keyless/tests.rs @@ -5,11 +5,48 @@ use crate::keyless::{ bn254_circom::get_public_inputs_hash, circuit_testcases::*, test_utils::{get_sample_groth16_sig_and_pk, get_sample_openid_sig_and_pk}, - Configuration, EphemeralCertificate, DEVNET_VERIFICATION_KEY, + Configuration, EphemeralCertificate, KeylessPublicKey, KeylessSignature, + DEVNET_VERIFICATION_KEY, }; use aptos_crypto::poseidon_bn254::fr_to_bytes_le; use std::ops::{AddAssign, Deref}; +/// Outputs: +/// KeylessSignature BCS size: 318 +/// KeylessPublicKey BCS size: 61 +/// +/// Signature size would have been 294 if the extra_field was set to None. +#[test] +#[ignore] +fn test_keyless_groth16_sizes() { + let (sig, pk) = get_sample_groth16_sig_and_pk(); + print_keyless_sizes("Groth16 sizes", sig, pk) +} + +/// Outputs: +/// KeylessSignature BCS size: 1033 +/// KeylessPublicKey BCS size: 61 +#[test] +#[ignore] +fn test_keyless_openid_sizes() { + let (sig, pk) = get_sample_openid_sig_and_pk(); + + print_keyless_sizes("OpenID sizes", sig, pk) +} + +fn print_keyless_sizes(ty: &str, sig: KeylessSignature, pk: KeylessPublicKey) { + println!("{}", ty); + println!("--------------"); + println!( + "KeylessSignature BCS size: {} bytes", + bcs::to_bytes(&sig).unwrap().len() + ); + println!( + "KeylessPublicKey BCS size: {} bytes", + bcs::to_bytes(&pk).unwrap().len() + ); +} + // TODO(keyless): Add instructions on how to produce this test case. #[test] fn test_keyless_groth16_proof_verification() { diff --git a/types/src/lib.rs b/types/src/lib.rs index 64d54ceb376a5..f76c5a467865a 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -15,6 +15,7 @@ pub mod contract_event; pub mod dkg; pub mod epoch_change; pub mod epoch_state; +pub mod error; pub mod event; pub mod executable; pub mod fee_statement; diff --git a/types/src/on_chain_config/aptos_features.rs b/types/src/on_chain_config/aptos_features.rs index 344639f68a714..5bf309fce1db3 100644 --- a/types/src/on_chain_config/aptos_features.rs +++ b/types/src/on_chain_config/aptos_features.rs @@ -70,6 +70,11 @@ pub enum FeatureFlag { DELEGATION_POOL_ALLOWLISTING = 56, MODULE_EVENT_MIGRATION = 57, REJECT_UNSTABLE_BYTECODE = 58, + TRANSACTION_CONTEXT_EXTENSION = 59, + COIN_TO_FUNGIBLE_ASSET_MIGRATION = 60, + PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS = 61, + OBJECT_NATIVE_DERIVED_ADDRESS = 62, + DISPATCHABLE_FUNGIBLE_ASSET = 63, } impl FeatureFlag { @@ -126,6 +131,10 @@ impl FeatureFlag { FeatureFlag::DELEGATION_POOL_ALLOWLISTING, FeatureFlag::MODULE_EVENT_MIGRATION, FeatureFlag::REJECT_UNSTABLE_BYTECODE, + FeatureFlag::TRANSACTION_CONTEXT_EXTENSION, + FeatureFlag::COIN_TO_FUNGIBLE_ASSET_MIGRATION, + FeatureFlag::OBJECT_NATIVE_DERIVED_ADDRESS, + FeatureFlag::DISPATCHABLE_FUNGIBLE_ASSET, ] } } diff --git a/types/src/on_chain_config/mod.rs b/types/src/on_chain_config/mod.rs index a3174be78cf37..48e847eb5a645 100644 --- a/types/src/on_chain_config/mod.rs +++ b/types/src/on_chain_config/mod.rs @@ -29,6 +29,7 @@ mod consensus_config; mod execution_config; mod gas_schedule; mod jwk_consensus_config; +pub mod randomness_api_v0_config; mod randomness_config; mod timed_features; mod timestamp; @@ -177,11 +178,9 @@ pub trait OnChainConfig: Send + Sync + DeserializeOwned { where T: ConfigStorage + ?Sized, { - match storage.fetch_config_bytes(&StateKey::resource(Self::address(), &Self::struct_tag())) - { - Some(bytes) => Self::deserialize_into_config(&bytes).ok(), - None => None, - } + let state_key = StateKey::on_chain_config::().ok()?; + let bytes = storage.fetch_config_bytes(&state_key)?; + Self::deserialize_into_config(&bytes).ok() } fn address() -> &'static AccountAddress { diff --git a/types/src/on_chain_config/randomness_api_v0_config.rs b/types/src/on_chain_config/randomness_api_v0_config.rs new file mode 100644 index 0000000000000..5a6190de71abb --- /dev/null +++ b/types/src/on_chain_config/randomness_api_v0_config.rs @@ -0,0 +1,34 @@ +// Copyright (c) Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{move_utils::as_move_value::AsMoveValue, on_chain_config::OnChainConfig}; +use move_core_types::value::{MoveStruct, MoveValue}; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +pub struct RequiredGasDeposit { + pub gas_amount: Option, +} + +impl RequiredGasDeposit { + pub fn default_for_genesis() -> Self { + Self { + gas_amount: Some(10_000), + } + } + + pub fn default_if_missing() -> Self { + Self { gas_amount: None } + } +} + +impl OnChainConfig for RequiredGasDeposit { + const MODULE_IDENTIFIER: &'static str = "randomness_api_v0_config"; + const TYPE_IDENTIFIER: &'static str = "RequiredGasDeposit"; +} + +impl AsMoveValue for RequiredGasDeposit { + fn as_move_value(&self) -> MoveValue { + MoveValue::Struct(MoveStruct::Runtime(vec![self.gas_amount.as_move_value()])) + } +} diff --git a/types/src/proptest_types.rs b/types/src/proptest_types.rs index 9084a50d57e25..77298f9ed0d38 100644 --- a/types/src/proptest_types.rs +++ b/types/src/proptest_types.rs @@ -5,7 +5,6 @@ #![allow(clippy::arc_with_non_send_sync)] use crate::{ - access_path::AccessPath, account_address::{self, AccountAddress}, account_config::{AccountResource, CoinStoreResource}, aggregate_signature::PartialSignatures, @@ -92,12 +91,13 @@ impl Arbitrary for WriteSet { fn arbitrary_with(_args: ()) -> Self::Strategy { // XXX there's no checking for repeated access paths here, nor in write_set. Is that // important? Not sure. - vec((any::(), any::()), 0..64) + vec((vec(any::(), 1..100), any::()), 0..64) .prop_map(|write_set| { - let write_set_mut = - WriteSetMut::new(write_set.iter().map(|(access_path, write_op)| { - (StateKey::access_path(access_path.clone()), write_op.clone()) - })); + let write_set_mut = WriteSetMut::new( + write_set + .iter() + .map(|(raw_key, write_op)| (StateKey::raw(raw_key), write_op.clone())), + ); write_set_mut .freeze() .expect("generated write sets should always be valid") @@ -688,11 +688,11 @@ impl AccountStateGen { let balance_resource = self.balance_resource_gen.materialize(); vec![ ( - StateKey::resource_typed::(address), + StateKey::resource_typed::(address).unwrap(), bcs::to_bytes(&account_resource).unwrap(), ), ( - StateKey::resource_typed::(address), + StateKey::resource_typed::(address).unwrap(), bcs::to_bytes(&balance_resource).unwrap(), ), ] diff --git a/types/src/state_store/mod.rs b/types/src/state_store/mod.rs index 096119e00bdef..a0e34f75af336 100644 --- a/types/src/state_store/mod.rs +++ b/types/src/state_store/mod.rs @@ -19,7 +19,6 @@ use std::{collections::HashMap, ops::Deref}; pub mod errors; pub mod in_memory_state_view; pub mod state_key; -pub mod state_key_prefix; pub mod state_storage_usage; pub mod state_value; pub mod table; @@ -124,7 +123,7 @@ pub trait MoveResourceExt: MoveResource { state_view: &dyn StateView, address: &AccountAddress, ) -> Result> { - let state_key = StateKey::resource_typed::(address); + let state_key = StateKey::resource_typed::(address)?; Ok(state_view .get_state_value_bytes(&state_key)? .map(|bytes| bcs::from_bytes(&bytes)) diff --git a/types/src/state_store/state_key.rs b/types/src/state_store/state_key.rs deleted file mode 100644 index 7142324b57e28..0000000000000 --- a/types/src/state_store/state_key.rs +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright © Aptos Foundation -// SPDX-License-Identifier: Apache-2.0 - -#![allow(clippy::non_canonical_partial_ord_impl)] - -use crate::{ - access_path::AccessPath, on_chain_config::OnChainConfig, state_store::table::TableHandle, -}; -use anyhow::Result; -use aptos_crypto::{ - hash::{CryptoHash, CryptoHasher, DummyHasher}, - HashValue, -}; -use aptos_crypto_derive::CryptoHasher; -use derivative::Derivative; -use move_core_types::{ - account_address::AccountAddress, language_storage::StructTag, move_resource::MoveResource, -}; -use num_derive::{FromPrimitive, ToPrimitive}; -use num_traits::FromPrimitive; -use once_cell::sync::OnceCell; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::{ - convert::TryInto, - fmt, - fmt::{Debug, Formatter}, - hash::Hash, - ops::Deref, -}; -use thiserror::Error; - -#[derive(Clone, Debug, Derivative)] -#[derivative(PartialEq, PartialOrd, Hash, Ord)] -#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))] -pub struct StateKey { - inner: StateKeyInner, - #[derivative( - Hash = "ignore", - Ord = "ignore", - PartialEq = "ignore", - PartialOrd = "ignore" - )] - #[cfg_attr(any(test, feature = "fuzzing"), proptest(value = "OnceCell::new()"))] - hash: OnceCell, -} - -#[derive(Clone, CryptoHasher, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd, Hash)] -#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))] -#[serde(rename = "StateKey")] -pub enum StateKeyInner { - AccessPath(AccessPath), - TableItem { - handle: TableHandle, - #[serde(with = "serde_bytes")] - key: Vec, - }, - // Only used for testing - #[serde(with = "serde_bytes")] - Raw(Vec), -} - -impl fmt::Debug for StateKeyInner { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - StateKeyInner::AccessPath(ap) => { - write!(f, "{:?}", ap) - }, - StateKeyInner::TableItem { handle, key } => { - write!( - f, - "TableItem {{ handle: {:x}, key: {} }}", - handle.0, - hex::encode(key), - ) - }, - StateKeyInner::Raw(bytes) => { - write!(f, "Raw({})", hex::encode(bytes),) - }, - } - } -} - -#[repr(u8)] -#[derive(Clone, Debug, FromPrimitive, ToPrimitive)] -pub enum StateKeyTag { - AccessPath, - TableItem, - Raw = 255, -} - -impl StateKey { - pub fn new(inner: StateKeyInner) -> Self { - Self { - inner, - hash: OnceCell::new(), - } - } - - /// Recovers from serialized bytes in physical storage. - pub fn decode(val: &[u8]) -> Result { - if val.is_empty() { - return Err(StateKeyDecodeErr::EmptyInput); - } - let tag = val[0]; - let state_key_tag = - StateKeyTag::from_u8(tag).ok_or(StateKeyDecodeErr::UnknownTag { unknown_tag: tag })?; - match state_key_tag { - StateKeyTag::AccessPath => { - Ok(StateKeyInner::AccessPath(bcs::from_bytes(&val[1..])?).into()) - }, - StateKeyTag::TableItem => { - const HANDLE_SIZE: usize = std::mem::size_of::(); - if val.len() < 1 + HANDLE_SIZE { - return Err(StateKeyDecodeErr::NotEnoughBytes { - tag, - num_bytes: val.len(), - }); - } - let handle = bcs::from_bytes( - val[1..1 + HANDLE_SIZE] - .try_into() - .expect("Bytes too short."), - )?; - let key = val[1 + HANDLE_SIZE..].to_vec(); - Ok(StateKey::table_item(handle, key)) - }, - StateKeyTag::Raw => Ok(StateKey::raw(val[1..].to_vec())), - } - } - - pub fn size(&self) -> usize { - match &self.inner { - StateKeyInner::AccessPath(access_path) => access_path.size(), - StateKeyInner::TableItem { handle, key } => handle.size() + key.len(), - StateKeyInner::Raw(bytes) => bytes.len(), - } - } - - pub fn access_path(access_path: AccessPath) -> Self { - Self::new(StateKeyInner::AccessPath(access_path)) - } - - pub fn resource(address: &AccountAddress, struct_tag: &StructTag) -> Self { - Self::access_path( - AccessPath::resource_access_path(*address, struct_tag.to_owned()).unwrap(), - ) - } - - pub fn resource_typed(address: &AccountAddress) -> Self { - Self::resource(address, &T::struct_tag()) - } - - pub fn on_chain_config() -> Self { - Self::resource(T::address(), &T::struct_tag()) - } - - pub fn table_item(handle: TableHandle, key: Vec) -> Self { - Self::new(StateKeyInner::TableItem { handle, key }) - } - - pub fn raw(raw_key: Vec) -> Self { - Self::new(StateKeyInner::Raw(raw_key)) - } - - pub fn inner(&self) -> &StateKeyInner { - &self.inner - } - - pub fn into_inner(self) -> StateKeyInner { - self.inner - } - - pub fn get_shard_id(&self) -> u8 { - CryptoHash::hash(self).nibble(0) - } - - pub fn is_aptos_code(&self) -> bool { - match self.inner() { - StateKeyInner::AccessPath(access_path) => { - access_path.is_code() - && (access_path.address == AccountAddress::ONE - || access_path.address == AccountAddress::THREE - || access_path.address == AccountAddress::FOUR) - }, - _ => false, - } - } -} - -impl StateKeyInner { - /// Serializes to bytes for physical storage. - pub fn encode(&self) -> anyhow::Result> { - let mut out = vec![]; - - let (prefix, raw_key) = match self { - StateKeyInner::AccessPath(access_path) => { - (StateKeyTag::AccessPath, bcs::to_bytes(access_path)?) - }, - StateKeyInner::TableItem { handle, key } => { - let mut bytes = bcs::to_bytes(&handle)?; - bytes.extend(key); - (StateKeyTag::TableItem, bytes) - }, - StateKeyInner::Raw(raw_bytes) => (StateKeyTag::Raw, raw_bytes.to_vec()), - }; - out.push(prefix as u8); - out.extend(raw_key); - Ok(out) - } -} - -impl CryptoHash for StateKey { - type Hasher = DummyHasher; - - fn hash(&self) -> HashValue { - *self.hash.get_or_init(|| CryptoHash::hash(&self.inner)) - } -} - -impl Serialize for StateKey { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - self.inner.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for StateKey { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let inner = StateKeyInner::deserialize(deserializer)?; - Ok(Self::new(inner)) - } -} - -impl Deref for StateKey { - type Target = StateKeyInner; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl Eq for StateKey {} - -impl From for StateKey { - fn from(inner: StateKeyInner) -> Self { - StateKey::new(inner) - } -} - -impl CryptoHash for StateKeyInner { - type Hasher = StateKeyInnerHasher; - - fn hash(&self) -> HashValue { - let mut state = Self::Hasher::default(); - state.update( - self.encode() - .expect("Failed to serialize the state key") - .as_ref(), - ); - state.finish() - } -} - -/// Error thrown when a [`StateKey`] fails to be deserialized out of a byte sequence stored in physical -/// storage, via [`StateKey::decode`]. -#[derive(Debug, Error)] -pub enum StateKeyDecodeErr { - /// Input is empty. - #[error("Missing tag due to empty input")] - EmptyInput, - - /// The first byte of the input is not a known tag representing one of the variants. - #[error("lead tag byte is unknown: {}", unknown_tag)] - UnknownTag { unknown_tag: u8 }, - - #[error("Not enough bytes: tag: {}, num bytes: {}", tag, num_bytes)] - NotEnoughBytes { tag: u8, num_bytes: usize }, - - #[error(transparent)] - BcsError(#[from] bcs::Error), -} - -#[cfg(test)] -mod tests { - use crate::state_store::state_key::{AccessPath, StateKey}; - use aptos_crypto::hash::CryptoHash; - use move_core_types::language_storage::ModuleId; - - #[test] - fn test_access_path_hash() { - let key = StateKey::access_path(AccessPath::new("0x1002".parse().unwrap(), vec![7, 2, 3])); - let expected_hash = "0e0960bcabe04c40e8814ecc0e6de415163573243fb5059e9951f5890e9481ef" - .parse() - .unwrap(); - assert_eq!(CryptoHash::hash(&key), expected_hash); - } - - #[test] - fn test_table_item_hash() { - let key = StateKey::table_item("0x1002".parse().unwrap(), vec![7, 2, 3]); - let expected_hash = "6f5550015f7a6036f88b2458f98a7e4800aba09e83f8f294dbf70bff77f224e6" - .parse() - .unwrap(); - assert_eq!(CryptoHash::hash(&key), expected_hash); - } - - #[test] - fn test_raw_hash() { - let key = StateKey::raw(vec![1, 2, 3]); - let expected_hash = "655ab5766bc87318e18d9287f32d318e15535d3db9d21a6e5a2b41a51b535aff" - .parse() - .unwrap(); - assert_eq!(CryptoHash::hash(&key), expected_hash); - } - - #[test] - fn test_debug() { - // code - let key = StateKey::access_path(AccessPath::code_access_path(ModuleId::new( - "0xcafe".parse().unwrap(), - "my_module".parse().unwrap(), - ))); - assert_eq!( - &format!("{:?}", key), - "StateKey { inner: AccessPath { address: 0xcafe, path: \"Code(000000000000000000000000000000000000000000000000000000000000cafe::my_module)\" }, hash: OnceCell(Uninit) }" - ); - - // resource - let key = StateKey::access_path( - AccessPath::resource_access_path( - "0xcafe".parse().unwrap(), - "0x1::account::Account".parse().unwrap(), - ) - .unwrap(), - ); - assert_eq!( - &format!("{:?}", key), - "StateKey { inner: AccessPath { address: 0xcafe, path: \"Resource(0x1::account::Account)\" }, hash: OnceCell(Uninit) }", - ); - - // table item - let key = StateKey::table_item("0x123".parse().unwrap(), vec![1]); - assert_eq!( - &format!("{:?}", key), - "StateKey { inner: TableItem { handle: 0000000000000000000000000000000000000000000000000000000000000123, key: 01 }, hash: OnceCell(Uninit) }" - ); - - // raw - let key = StateKey::raw(vec![1, 2, 3]); - assert_eq!( - &format!("{:?}", key), - "StateKey { inner: Raw(010203), hash: OnceCell(Uninit) }" - ); - - // with hash - let _hash = CryptoHash::hash(&key); - assert_eq!( - &format!("{:?}", key), - "StateKey { inner: Raw(010203), hash: OnceCell(HashValue(655ab5766bc87318e18d9287f32d318e15535d3db9d21a6e5a2b41a51b535aff)) }" - ); - } -} diff --git a/types/src/state_store/state_key/inner.rs b/types/src/state_store/state_key/inner.rs new file mode 100644 index 0000000000000..a56593f0eadab --- /dev/null +++ b/types/src/state_store/state_key/inner.rs @@ -0,0 +1,115 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{access_path::AccessPath, state_store::table::TableHandle}; +use aptos_crypto::{ + hash::{CryptoHash, CryptoHasher}, + HashValue, +}; +use aptos_crypto_derive::CryptoHasher; +use num_derive::{FromPrimitive, ToPrimitive}; +use serde::{Deserialize, Serialize}; +use std::{ + fmt, + fmt::{Debug, Formatter}, +}; +use thiserror::Error; + +#[repr(u8)] +#[derive(Clone, Debug, FromPrimitive, ToPrimitive)] +pub enum StateKeyTag { + AccessPath, + TableItem, + Raw = 255, +} + +impl CryptoHash for StateKeyInner { + type Hasher = StateKeyInnerHasher; + + fn hash(&self) -> HashValue { + let mut state = Self::Hasher::default(); + state.update( + self.encode() + .expect("Failed to serialize the state key") + .as_ref(), + ); + state.finish() + } +} + +/// Error thrown when a [`StateKey`] fails to be deserialized out of a byte sequence stored in physical +/// storage, via [`StateKey::decode`]. +#[derive(Debug, Error)] +pub enum StateKeyDecodeErr { + /// Input is empty. + #[error("Missing tag due to empty input")] + EmptyInput, + + /// The first byte of the input is not a known tag representing one of the variants. + #[error("lead tag byte is unknown: {}", unknown_tag)] + UnknownTag { unknown_tag: u8 }, + + #[error("Not enough bytes: tag: {}, num bytes: {}", tag, num_bytes)] + NotEnoughBytes { tag: u8, num_bytes: usize }, + + #[error(transparent)] + BcsError(#[from] bcs::Error), +} + +#[derive(Clone, CryptoHasher, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd, Hash)] +#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))] +#[serde(rename = "StateKey")] +pub enum StateKeyInner { + AccessPath(AccessPath), + TableItem { + handle: TableHandle, + #[serde(with = "serde_bytes")] + key: Vec, + }, + // Only used for testing + #[serde(with = "serde_bytes")] + Raw(Vec), +} + +impl StateKeyInner { + /// Serializes to bytes for physical storage. + pub fn encode(&self) -> anyhow::Result> { + let mut out = vec![]; + + let (prefix, raw_key) = match self { + StateKeyInner::AccessPath(access_path) => { + (StateKeyTag::AccessPath, bcs::to_bytes(access_path)?) + }, + StateKeyInner::TableItem { handle, key } => { + let mut bytes = bcs::to_bytes(&handle)?; + bytes.extend(key); + (StateKeyTag::TableItem, bytes) + }, + StateKeyInner::Raw(raw_bytes) => (StateKeyTag::Raw, raw_bytes.to_vec()), + }; + out.push(prefix as u8); + out.extend(raw_key); + Ok(out) + } +} + +impl Debug for StateKeyInner { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + StateKeyInner::AccessPath(ap) => { + write!(f, "StateKey::{:?}", ap) + }, + StateKeyInner::TableItem { handle, key } => { + write!( + f, + "StateKey::TableItem {{ handle: {:x}, key: {} }}", + handle.0, + hex::encode(key), + ) + }, + StateKeyInner::Raw(bytes) => { + write!(f, "StateKey::Raw({})", hex::encode(bytes),) + }, + } + } +} diff --git a/types/src/state_store/state_key/mod.rs b/types/src/state_store/state_key/mod.rs new file mode 100644 index 0000000000000..656b427df69c6 --- /dev/null +++ b/types/src/state_store/state_key/mod.rs @@ -0,0 +1,215 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::non_canonical_partial_ord_impl)] + +pub mod inner; +pub mod prefix; +#[cfg(test)] +mod tests; + +use crate::{ + access_path::AccessPath, on_chain_config::OnChainConfig, state_store::table::TableHandle, +}; +use anyhow::Result; +use aptos_crypto::{ + hash::{CryptoHash, DummyHasher}, + HashValue, +}; +use derivative::Derivative; +use inner::{StateKeyDecodeErr, StateKeyInner, StateKeyTag}; +use move_core_types::{ + account_address::AccountAddress, + identifier::IdentStr, + language_storage::{ModuleId, StructTag}, + move_resource::MoveResource, +}; +use num_traits::FromPrimitive; +use once_cell::sync::OnceCell; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::{ + convert::TryInto, + fmt, + fmt::{Debug, Formatter}, + ops::Deref, +}; + +#[derive(Clone, Derivative)] +#[derivative(PartialEq, PartialOrd, Hash, Ord)] +#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))] +pub struct StateKey { + inner: StateKeyInner, + #[derivative( + Hash = "ignore", + Ord = "ignore", + PartialEq = "ignore", + PartialOrd = "ignore" + )] + #[cfg_attr(any(test, feature = "fuzzing"), proptest(value = "OnceCell::new()"))] + hash: OnceCell, +} + +impl Debug for StateKey { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + self.inner.fmt(f) + } +} + +impl StateKey { + pub fn new(inner: StateKeyInner) -> Self { + Self { + inner, + hash: OnceCell::new(), + } + } + + /// Recovers from serialized bytes in physical storage. + pub fn decode(val: &[u8]) -> Result { + if val.is_empty() { + return Err(StateKeyDecodeErr::EmptyInput); + } + let tag = val[0]; + let state_key_tag = + StateKeyTag::from_u8(tag).ok_or(StateKeyDecodeErr::UnknownTag { unknown_tag: tag })?; + match state_key_tag { + StateKeyTag::AccessPath => { + Ok(StateKeyInner::AccessPath(bcs::from_bytes(&val[1..])?).into()) + }, + StateKeyTag::TableItem => { + const HANDLE_SIZE: usize = std::mem::size_of::(); + if val.len() < 1 + HANDLE_SIZE { + return Err(StateKeyDecodeErr::NotEnoughBytes { + tag, + num_bytes: val.len(), + }); + } + let handle = bcs::from_bytes( + val[1..1 + HANDLE_SIZE] + .try_into() + .expect("Bytes too short."), + )?; + Ok(StateKey::table_item(&handle, &val[1 + HANDLE_SIZE..])) + }, + StateKeyTag::Raw => Ok(StateKey::raw(&val[1..])), + } + } + + pub fn size(&self) -> usize { + match &self.inner { + StateKeyInner::AccessPath(access_path) => access_path.size(), + StateKeyInner::TableItem { handle, key } => handle.size() + key.len(), + StateKeyInner::Raw(bytes) => bytes.len(), + } + } + + fn access_path(access_path: AccessPath) -> Self { + Self::new(StateKeyInner::AccessPath(access_path)) + } + + pub fn resource(address: &AccountAddress, struct_tag: &StructTag) -> Result { + Ok(Self::access_path(AccessPath::resource_access_path( + *address, + struct_tag.to_owned(), + )?)) + } + + pub fn resource_typed(address: &AccountAddress) -> Result { + Self::resource(address, &T::struct_tag()) + } + + pub fn resource_group(address: &AccountAddress, struct_tag: &StructTag) -> Self { + Self::access_path(AccessPath::resource_group_access_path( + *address, + struct_tag.to_owned(), + )) + } + + pub fn module(address: &AccountAddress, name: &IdentStr) -> Self { + Self::access_path(AccessPath::code_access_path(ModuleId::new( + *address, + name.to_owned(), + ))) + } + + pub fn module_id(module_id: &ModuleId) -> Self { + Self::module(module_id.address(), module_id.name()) + } + + pub fn on_chain_config() -> Result { + Self::resource(T::address(), &T::struct_tag()) + } + + pub fn table_item(handle: &TableHandle, key: &[u8]) -> Self { + Self::new(StateKeyInner::TableItem { + handle: *handle, + key: key.to_vec(), + }) + } + + pub fn raw(raw_key: &[u8]) -> Self { + Self::new(StateKeyInner::Raw(raw_key.to_vec())) + } + + pub fn inner(&self) -> &StateKeyInner { + &self.inner + } + + pub fn get_shard_id(&self) -> u8 { + CryptoHash::hash(self).nibble(0) + } + + pub fn is_aptos_code(&self) -> bool { + match self.inner() { + StateKeyInner::AccessPath(access_path) => { + access_path.is_code() + && (access_path.address == AccountAddress::ONE + || access_path.address == AccountAddress::THREE + || access_path.address == AccountAddress::FOUR) + }, + _ => false, + } + } +} + +impl CryptoHash for StateKey { + type Hasher = DummyHasher; + + fn hash(&self) -> HashValue { + *self.hash.get_or_init(|| CryptoHash::hash(&self.inner)) + } +} + +impl Serialize for StateKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.inner.serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for StateKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let inner = StateKeyInner::deserialize(deserializer)?; + Ok(Self::new(inner)) + } +} + +impl Deref for StateKey { + type Target = StateKeyInner; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl Eq for StateKey {} + +impl From for StateKey { + fn from(inner: StateKeyInner) -> Self { + StateKey::new(inner) + } +} diff --git a/types/src/state_store/state_key_prefix.rs b/types/src/state_store/state_key/prefix.rs similarity index 83% rename from types/src/state_store/state_key_prefix.rs rename to types/src/state_store/state_key/prefix.rs index 9c007b9cc10dc..4f971afafde50 100644 --- a/types/src/state_store/state_key_prefix.rs +++ b/types/src/state_store/state_key/prefix.rs @@ -1,7 +1,7 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 -use crate::state_store::state_key::{StateKey, StateKeyTag}; +use crate::state_store::state_key::{inner::StateKeyTag, StateKey}; use move_core_types::account_address::AccountAddress; // Struct for defining prefix of a state key, which can be used for finding all the values with a @@ -45,11 +45,8 @@ impl From for StateKeyPrefix { #[cfg(test)] mod tests { use crate::{ - access_path::AccessPath, - state_store::{ - state_key::{StateKey, StateKeyTag}, - state_key_prefix::StateKeyPrefix, - }, + account_config::{AccountResource, CoinStoreResource}, + state_store::state_key::{inner::StateKeyTag, prefix::StateKeyPrefix, StateKey}, }; use move_core_types::account_address::AccountAddress; @@ -57,8 +54,8 @@ mod tests { fn test_state_key_prefix() { let address1 = AccountAddress::new([12u8; AccountAddress::LENGTH]); let address2 = AccountAddress::new([22u8; AccountAddress::LENGTH]); - let key1 = StateKey::access_path(AccessPath::new(address1, b"state_key".to_vec())); - let key2 = StateKey::access_path(AccessPath::new(address2, b"state_key".to_vec())); + let key1 = StateKey::resource_typed::(&address1).unwrap(); + let key2 = StateKey::resource_typed::(&address2).unwrap(); let account1_key_prefx = StateKeyPrefix::new(StateKeyTag::AccessPath, address1.to_vec()); let account2_key_prefx = StateKeyPrefix::new(StateKeyTag::AccessPath, address2.to_vec()); diff --git a/types/src/state_store/state_key/tests.rs b/types/src/state_store/state_key/tests.rs new file mode 100644 index 0000000000000..9b5c8702b57b1 --- /dev/null +++ b/types/src/state_store/state_key/tests.rs @@ -0,0 +1,89 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + account_config::{AccountResource, ObjectGroupResource}, + state_store::state_key::StateKey, +}; +use aptos_crypto::hash::CryptoHash; +use move_core_types::{account_address::AccountAddress, ident_str, move_resource::MoveStructType}; + +fn assert_crypto_hash(key: &StateKey, expected_hash: &str) { + let expected_hash = expected_hash.parse().unwrap(); + assert_eq!(CryptoHash::hash(key), expected_hash); +} + +#[test] +fn test_resource_hash() { + assert_crypto_hash( + &StateKey::resource_typed::(&AccountAddress::TWO).unwrap(), + "8f9ab5d5e3c9f5b885fcceea388fecd16bdb490da08aac9d4f026ddc66733def", + ); +} + +#[test] +fn test_resource_group_hash() { + assert_crypto_hash( + &StateKey::resource_group(&AccountAddress::TWO, &ObjectGroupResource::struct_tag()), + "87973d52189ac6a25ea543214305c4c8fb3bc2ceea8c34600361b03527578133", + ); +} + +#[test] +fn test_module_hash() { + assert_crypto_hash( + &StateKey::module(&AccountAddress::TWO, ident_str!("mymodule")), + "83d33b345c5e4b25d8f4dfe2b98b492024313b3b6e4febea6bfa844dbd850200", + ); +} + +#[test] +fn test_table_item_hash() { + assert_crypto_hash( + &StateKey::table_item(&"0x1002".parse().unwrap(), &[7, 2, 3]), + "6f5550015f7a6036f88b2458f98a7e4800aba09e83f8f294dbf70bff77f224e6", + ); +} + +#[test] +fn test_raw_hash() { + assert_crypto_hash( + &StateKey::raw(&[1, 2, 3]), + "655ab5766bc87318e18d9287f32d318e15535d3db9d21a6e5a2b41a51b535aff", + ) +} + +#[test] +fn test_debug() { + // code + let key = StateKey::module(&AccountAddress::ONE, ident_str!("account")); + assert_eq!( + &format!("{:?}", key), + "StateKey::AccessPath { address: 0x1, path: \"Code(0000000000000000000000000000000000000000000000000000000000000001::account)\" }", + ); + + // resource + let key = StateKey::resource_typed::(&AccountAddress::FOUR).unwrap(); + assert_eq!( + &format!("{:?}", key), + "StateKey::AccessPath { address: 0x4, path: \"Resource(0x1::account::Account)\" }", + ); + + // resource group + let key = StateKey::resource_group(&AccountAddress::THREE, &ObjectGroupResource::struct_tag()); + assert_eq!( + &format!("{:?}", key), + "StateKey::AccessPath { address: 0x3, path: \"ResourceGroup(0x1::object::ObjectGroup)\" }", + ); + + // table item + let key = StateKey::table_item(&"0x123".parse().unwrap(), &[1]); + assert_eq!( + &format!("{:?}", key), + "StateKey::TableItem { handle: 0000000000000000000000000000000000000000000000000000000000000123, key: 01 }" + ); + + // raw + let key = StateKey::raw(&[1, 2, 3]); + assert_eq!(&format!("{:?}", key), "StateKey::Raw(010203)",); +} diff --git a/types/src/state_store/table.rs b/types/src/state_store/table.rs index bade243389a61..3fa9b20c26d38 100644 --- a/types/src/state_store/table.rs +++ b/types/src/state_store/table.rs @@ -33,6 +33,12 @@ impl From for TableHandle { } } +impl From<&move_table_extension::TableHandle> for TableHandle { + fn from(hdl: &move_table_extension::TableHandle) -> Self { + Self(hdl.0) + } +} + #[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] #[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))] pub struct TableInfo { diff --git a/types/src/transaction/analyzed_transaction.rs b/types/src/transaction/analyzed_transaction.rs index 124da2a6f0574..ae9073ae6fc25 100644 --- a/types/src/transaction/analyzed_transaction.rs +++ b/types/src/transaction/analyzed_transaction.rs @@ -157,33 +157,33 @@ impl From for AnalyzedTransaction { } pub fn account_resource_location(address: AccountAddress) -> StorageLocation { - StorageLocation::Specific(StateKey::resource_typed::(&address)) + StorageLocation::Specific(StateKey::resource_typed::(&address).unwrap()) } pub fn coin_store_location(address: AccountAddress) -> StorageLocation { - StorageLocation::Specific(StateKey::resource_typed::(&address)) + StorageLocation::Specific(StateKey::resource_typed::(&address).unwrap()) } pub fn current_ts_location() -> StorageLocation { - StorageLocation::Specific(StateKey::on_chain_config::()) + StorageLocation::Specific(StateKey::on_chain_config::().unwrap()) } pub fn features_location() -> StorageLocation { - StorageLocation::Specific(StateKey::on_chain_config::()) + StorageLocation::Specific(StateKey::on_chain_config::().unwrap()) } pub fn aptos_coin_info_location() -> StorageLocation { - StorageLocation::Specific(StateKey::resource_typed::( - &AccountAddress::ONE, - )) + StorageLocation::Specific( + StateKey::resource_typed::(&AccountAddress::ONE).unwrap(), + ) } pub fn chain_id_location() -> StorageLocation { - StorageLocation::Specific(StateKey::on_chain_config::()) + StorageLocation::Specific(StateKey::on_chain_config::().unwrap()) } pub fn transaction_fee_burn_cap_location() -> StorageLocation { - StorageLocation::Specific(StateKey::on_chain_config::()) + StorageLocation::Specific(StateKey::on_chain_config::().unwrap()) } pub fn rw_set_for_coin_transfer( diff --git a/types/src/transaction/authenticator.rs b/types/src/transaction/authenticator.rs index 6af3cd64fb6ee..7aa6ede30680a 100644 --- a/types/src/transaction/authenticator.rs +++ b/types/src/transaction/authenticator.rs @@ -637,11 +637,18 @@ impl AuthenticationKey { } /// Construct a preimage from a transaction-derived AUID as (txn_hash || auid_scheme_id) - pub fn auid(txn_hash: Vec, auid_counter: u64) -> Self { - let mut hash_arg = Vec::new(); - hash_arg.extend(txn_hash); - hash_arg.extend(auid_counter.to_le_bytes().to_vec()); - Self::from_preimage(hash_arg, Scheme::DeriveAuid) + pub fn auid(mut txn_hash: Vec, auid_counter: u64) -> Self { + txn_hash.extend(auid_counter.to_le_bytes().to_vec()); + Self::from_preimage(txn_hash, Scheme::DeriveAuid) + } + + pub fn object_address_from_object( + source: &AccountAddress, + derive_from: &AccountAddress, + ) -> AuthenticationKey { + let mut bytes = source.to_vec(); + bytes.append(&mut derive_from.to_vec()); + Self::from_preimage(bytes, Scheme::DeriveObjectAddressFromObject) } /// Create an authentication key from an Ed25519 public key @@ -991,6 +998,15 @@ impl AnySignature { Self::Keyless { signature } } + pub fn name(&self) -> &'static str { + match self { + Self::Ed25519 { .. } => "Ed25519", + Self::Secp256k1Ecdsa { .. } => "Secp256k1Ecdsa", + Self::WebAuthn { .. } => "WebAuthn", + Self::Keyless { .. } => "Keyless", + } + } + pub fn verify( &self, public_key: &AnyPublicKey, diff --git a/types/src/transaction/mod.rs b/types/src/transaction/mod.rs index cfef45781b2bc..ad35d7a797e26 100644 --- a/types/src/transaction/mod.rs +++ b/types/src/transaction/mod.rs @@ -48,6 +48,7 @@ mod module; mod multisig; mod script; pub mod signature_verified_transaction; +pub mod user_transaction_context; pub mod webauthn; #[cfg(any(test, feature = "fuzzing"))] diff --git a/types/src/transaction/multisig.rs b/types/src/transaction/multisig.rs index d4aac39e2f970..a08e036a7ec5b 100644 --- a/types/src/transaction/multisig.rs +++ b/types/src/transaction/multisig.rs @@ -1,7 +1,7 @@ // Copyright © Aptos Foundation // SPDX-License-Identifier: Apache-2.0 -use crate::transaction::EntryFunction; +use crate::transaction::{user_transaction_context::MultisigPayload, EntryFunction}; use move_core_types::{account_address::AccountAddress, vm_status::VMStatus}; use serde::{Deserialize, Serialize}; @@ -22,6 +22,19 @@ pub enum MultisigTransactionPayload { EntryFunction(EntryFunction), } +impl Multisig { + pub fn as_multisig_payload(&self) -> MultisigPayload { + MultisigPayload { + multisig_address: self.multisig_address, + entry_function_payload: self.transaction_payload.as_ref().map( + |MultisigTransactionPayload::EntryFunction(entry)| { + entry.as_entry_function_payload() + }, + ), + } + } +} + /// Contains information about execution failure. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ExecutionError { diff --git a/types/src/transaction/script.rs b/types/src/transaction/script.rs index cb67638aea800..c2fc4cea836a4 100644 --- a/types/src/transaction/script.rs +++ b/types/src/transaction/script.rs @@ -2,7 +2,7 @@ // Parts of the project are originally copyright © Meta Platforms, Inc. // SPDX-License-Identifier: Apache-2.0 -use crate::serde_helper::vec_bytes; +use crate::{serde_helper::vec_bytes, transaction::user_transaction_context::EntryFunctionPayload}; pub use move_core_types::abi::{ ArgumentABI, ScriptFunctionABI as EntryFunctionABI, TransactionScriptABI, TypeArgumentABI, }; @@ -149,4 +149,14 @@ impl EntryFunction { pub fn into_inner(self) -> (ModuleId, Identifier, Vec, Vec>) { (self.module, self.function, self.ty_args, self.args) } + + pub fn as_entry_function_payload(&self) -> EntryFunctionPayload { + EntryFunctionPayload::new( + self.module.address, + self.module.name().to_string(), + self.function.to_string(), + self.ty_args.iter().map(|ty| ty.to_string()).collect(), + self.args.clone(), + ) + } } diff --git a/types/src/transaction/user_transaction_context.rs b/types/src/transaction/user_transaction_context.rs new file mode 100644 index 0000000000000..4c9d3f71d3d12 --- /dev/null +++ b/types/src/transaction/user_transaction_context.rs @@ -0,0 +1,115 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use move_core_types::account_address::AccountAddress; + +#[derive(Debug)] +pub struct UserTransactionContext { + sender: AccountAddress, + secondary_signers: Vec, + gas_payer: AccountAddress, + max_gas_amount: u64, + gas_unit_price: u64, + chain_id: u8, + entry_function_payload: Option, + multisig_payload: Option, +} + +impl UserTransactionContext { + pub fn new( + sender: AccountAddress, + secondary_signers: Vec, + gas_payer: AccountAddress, + max_gas_amount: u64, + gas_unit_price: u64, + chain_id: u8, + entry_function_payload: Option, + multisig_payload: Option, + ) -> Self { + Self { + sender, + secondary_signers, + gas_payer, + max_gas_amount, + gas_unit_price, + chain_id, + entry_function_payload, + multisig_payload, + } + } + + pub fn sender(&self) -> AccountAddress { + self.sender + } + + pub fn secondary_signers(&self) -> Vec { + self.secondary_signers.clone() + } + + pub fn gas_payer(&self) -> AccountAddress { + self.gas_payer + } + + pub fn max_gas_amount(&self) -> u64 { + self.max_gas_amount + } + + pub fn gas_unit_price(&self) -> u64 { + self.gas_unit_price + } + + pub fn chain_id(&self) -> u8 { + self.chain_id + } + + pub fn entry_function_payload(&self) -> Option { + self.entry_function_payload.clone() + } + + pub fn multisig_payload(&self) -> Option { + self.multisig_payload.clone() + } +} + +#[derive(Debug, Clone)] +pub struct EntryFunctionPayload { + pub account_address: AccountAddress, + pub module_name: String, + pub function_name: String, + pub ty_arg_names: Vec, + pub args: Vec>, +} +impl EntryFunctionPayload { + pub fn new( + account_address: AccountAddress, + module_name: String, + function_name: String, + ty_arg_names: Vec, + args: Vec>, + ) -> Self { + Self { + account_address, + module_name, + function_name, + ty_arg_names, + args, + } + } +} + +#[derive(Debug, Clone)] +pub struct MultisigPayload { + pub multisig_address: AccountAddress, + pub entry_function_payload: Option, +} +impl MultisigPayload { + pub fn new( + multisig_address: AccountAddress, + entry_function_payload: Option, + ) -> Self { + Self { + multisig_address, + entry_function_payload, + } + } +} diff --git a/types/src/write_set.rs b/types/src/write_set.rs index 74bc3055e1690..159b33e7ba63a 100644 --- a/types/src/write_set.rs +++ b/types/src/write_set.rs @@ -27,10 +27,10 @@ use std::{ // genesis directly if necessary. pub static TOTAL_SUPPLY_STATE_KEY: Lazy = Lazy::new(|| { StateKey::table_item( - "1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca" + &"1b854694ae746cdbd8d44186ca4929b2b337df21d1c74633be19b2710552fdca" .parse() .unwrap(), - vec![ + &[ 6, 25, 220, 41, 160, 170, 200, 250, 20, 103, 20, 5, 142, 141, 214, 210, 208, 243, 189, 245, 246, 51, 25, 7, 191, 145, 243, 172, 216, 30, 105, 53, ],