diff --git a/.github/runs-on.yml b/.github/runs-on.yml new file mode 100644 index 0000000000000..01760868f0e61 --- /dev/null +++ b/.github/runs-on.yml @@ -0,0 +1,5 @@ +images: + aptos-ubuntu-x64: + platform: "linux" + arch: "x64" + ami: "ami-0d8c19bef4893b1ea" diff --git a/.github/workflows/forge-stable.yaml b/.github/workflows/forge-stable.yaml index 584e20595c881..b11985e169f04 100644 --- a/.github/workflows/forge-stable.yaml +++ b/.github/workflows/forge-stable.yaml @@ -24,15 +24,14 @@ on: required: false type: string description: The git SHA1 to checkout. This affects the Forge test runner that is used. If not specified, the latest main will be used + # NOTE: to support testing different branches on different schedules, you need to specify the cron schedule in the 'determine-test-branch' step as well below + # Reference: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule schedule: - - cron: "0 6 * * *" # The main branch cadence. This runs every day at 6am UTC. + - cron: "0 22 * * 0,2,4" # The main branch cadence. This runs every Sun,Tues,Thurs pull_request: paths: - ".github/workflows/forge-stable.yaml" - "testsuite/find_latest_image.py" - push: - branches: - - aptos-release-v* # the aptos release branches env: AWS_ACCOUNT_NUM: ${{ secrets.ENV_ECR_AWS_ACCOUNT_NUM }} @@ -55,9 +54,10 @@ jobs: - name: Determine branch based on cadence id: determine-test-branch + # NOTE: the schedule cron MUST match the one in the 'on.schedule.cron' section above run: | if [[ "${{ github.event_name }}" == "schedule" ]]; then - if [[ "${{ github.event.schedule }}" == "0 6 * * *" ]]; then + if [[ "${{ github.event.schedule }}" == "0 22 * * 0,2,4" ]]; then echo "Branch: main" echo "BRANCH=main" >> $GITHUB_OUTPUT else @@ -136,7 +136,7 @@ jobs: run-forge-realistic-env-max-load-long: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-framework-upgrade-test ] # Only run after the previous job completes + 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 with: @@ -148,7 +148,7 @@ jobs: run-forge-realistic-env-load-sweep: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-realistic-env-max-load-long ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-realistic-env-max-load-long] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -160,7 +160,7 @@ jobs: run-forge-realistic-env-workload-sweep: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-realistic-env-load-sweep ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-realistic-env-load-sweep] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -172,7 +172,7 @@ jobs: run-forge-realistic-env-graceful-overload: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-realistic-env-workload-sweep ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-realistic-env-workload-sweep] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -184,7 +184,7 @@ jobs: run-forge-realistic-network-tuned-for-throughput: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-realistic-env-graceful-overload ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-realistic-env-graceful-overload] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -199,7 +199,7 @@ jobs: run-forge-consensus-stress-test: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-realistic-network-tuned-for-throughput ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-realistic-network-tuned-for-throughput] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -211,7 +211,7 @@ jobs: run-forge-workload-mix-test: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-consensus-stress-test ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-consensus-stress-test] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -223,7 +223,7 @@ jobs: run-forge-single-vfn-perf: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-workload-mix-test ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-workload-mix-test] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -235,7 +235,7 @@ jobs: run-forge-fullnode-reboot-stress-test: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-single-vfn-perf ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-single-vfn-perf] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -249,7 +249,7 @@ jobs: run-forge-compat: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-fullnode-reboot-stress-test ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-fullnode-reboot-stress-test] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -265,7 +265,7 @@ jobs: run-forge-changing-working-quorum-test: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-compat ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-compat] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -278,7 +278,7 @@ jobs: run-forge-changing-working-quorum-test-high-load: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-changing-working-quorum-test ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-changing-working-quorum-test] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: @@ -292,7 +292,7 @@ jobs: # Measures PFN latencies with a constant TPS (with a realistic environment) run-forge-pfn-const-tps-realistic-env: if: ${{ github.event_name != 'pull_request' && always() }} - needs: [ determine-test-metadata, run-forge-changing-working-quorum-test-high-load ] # Only run after the previous job completes + needs: [determine-test-metadata, run-forge-changing-working-quorum-test-high-load] # Only run after the previous job completes uses: aptos-labs/aptos-core/.github/workflows/workflow-run-forge.yaml@main secrets: inherit with: diff --git a/.github/workflows/replay-verify.yaml b/.github/workflows/replay-verify.yaml index 489f561ac8db3..d0e91d30a3723 100644 --- a/.github/workflows/replay-verify.yaml +++ b/.github/workflows/replay-verify.yaml @@ -23,7 +23,7 @@ on: - ".github/workflows/replay-verify.yaml" - "testsuite/replay_verify.py" schedule: - - cron: "0 22 * * 0,2,4" + - cron: "0 22 * * 0,2,4" # The main branch cadence. This runs every Sun,Tues,Thurs # cancel redundant builds concurrency: @@ -82,7 +82,7 @@ jobs: TIMEOUT_MINUTES: 480 test-replay: - if: ${{ github.event_name == 'pull_request' }} + if: ${{ (github.event_name == 'pull_request') && contains(github.event.pull_request.labels.*.name, 'CICD:test-replay')}} needs: determine-test-metadata uses: ./.github/workflows/workflow-run-replay-verify.yaml secrets: inherit diff --git a/Cargo.lock b/Cargo.lock index 40e97e4d1d437..f90fd7f8daca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2182,6 +2182,7 @@ dependencies = [ "aptos-logger", "aptos-mempool", "aptos-runtimes", + "aptos-schemadb", "aptos-storage-interface", "aptos-types", "flate2", @@ -2834,6 +2835,7 @@ dependencies = [ "thiserror", "tokio", "tokio-retry", + "tokio-stream", "tokio-util 0.7.10", ] @@ -2994,6 +2996,7 @@ dependencies = [ "aptos-peer-monitoring-service-types", "aptos-runtimes", "aptos-safety-rules", + "aptos-schemadb", "aptos-state-sync-driver", "aptos-storage-interface", "aptos-storage-service-client", @@ -3640,6 +3643,7 @@ dependencies = [ "aptos-data-client", "aptos-data-streaming-service", "aptos-db", + "aptos-db-indexer-schemas", "aptos-event-notifications", "aptos-executor", "aptos-executor-test-helpers", @@ -4307,7 +4311,6 @@ dependencies = [ "aptos-proptest-helpers", "aptos-types", "aptos-vm", - "aptos-vm-types", "bcs 0.1.4", "bytes", "move-core-types", @@ -4377,6 +4380,7 @@ dependencies = [ "either", "move-binary-format", "move-core-types", + "move-vm-runtime", "move-vm-types", "rand 0.7.3", "serde", @@ -4425,20 +4429,12 @@ name = "aptos-writeset-generator" version = "0.1.0" dependencies = [ "anyhow", - "aptos-cached-packages", "aptos-crypto", - "aptos-framework", - "aptos-gas-schedule", "aptos-types", "aptos-vm", - "aptos-vm-types", - "handlebars", - "move-compiler", "move-core-types", "move-vm-runtime", "move-vm-types", - "serde", - "tempfile", ] [[package]] @@ -8175,7 +8171,6 @@ dependencies = [ "move-binary-format", "move-bytecode-verifier", "move-core-types", - "move-vm-runtime", "move-vm-types", "once_cell", "rayon", @@ -10424,6 +10419,7 @@ dependencies = [ "arbitrary", "backtrace", "indexmap 1.9.3", + "move-bytecode-spec", "move-core-types", "proptest", "proptest-derive", @@ -10451,6 +10447,15 @@ dependencies = [ "serde", ] +[[package]] +name = "move-bytecode-spec" +version = "0.1.0" +dependencies = [ + "once_cell", + "quote", + "syn 1.0.109", +] + [[package]] name = "move-bytecode-utils" version = "0.1.0" @@ -11110,6 +11115,7 @@ dependencies = [ "difference", "move-binary-format", "move-bytecode-source-map", + "move-bytecode-verifier", "move-command-line-common", "move-compiler", "move-compiler-v2", @@ -14826,6 +14832,7 @@ dependencies = [ "aptos-consensus", "aptos-crypto", "aptos-db", + "aptos-db-indexer-schemas", "aptos-debugger", "aptos-dkg", "aptos-faucet-core", @@ -14836,6 +14843,7 @@ dependencies = [ "aptos-genesis", "aptos-global-constants", "aptos-indexer", + "aptos-indexer-grpc-table-info", "aptos-infallible", "aptos-inspection-service", "aptos-keygen", @@ -14844,6 +14852,7 @@ dependencies = [ "aptos-release-builder", "aptos-rest-client", "aptos-rosetta", + "aptos-schemadb", "aptos-sdk", "aptos-secure-storage", "aptos-storage-interface", @@ -14868,6 +14877,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml 0.8.26", + "tempfile", "tokio", "url", "walkdir", diff --git a/Cargo.toml b/Cargo.toml index 00509ca2c4e26..78792c45d7105 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -198,6 +198,7 @@ members = [ "third_party/move/move-binary-format", "third_party/move/move-binary-format/serializer-tests", "third_party/move/move-borrow-graph", + "third_party/move/move-bytecode-spec", "third_party/move/move-bytecode-verifier", "third_party/move/move-bytecode-verifier/bytecode-verifier-tests", "third_party/move/move-bytecode-verifier/fuzz", @@ -803,6 +804,7 @@ z3tracer = "0.8.0" # MOVE DEPENDENCIES move-abigen = { path = "third_party/move/move-prover/move-abigen" } move-binary-format = { path = "third_party/move/move-binary-format" } +move-bytecode-spec = { path = "third_party/move/move-bytecode-spec" } move-bytecode-verifier = { path = "third_party/move/move-bytecode-verifier" } move-bytecode-utils = { path = "third_party/move/tools/move-bytecode-utils" } move-cli = { path = "third_party/move/tools/move-cli" } diff --git a/SECURITY.md b/SECURITY.md index b956e520c47eb..acb4ca035fe1c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,4 +2,4 @@ The Aptos Foundation welcomes feedback from security researchers and the general public to help improve the security of the Aptos Network, and, at its sole discretion, offers bounty rewards for security reports that identify previously unknown, in-scope security vulnerabilities. -To learn more visit the [Aptos Foundation Bounty Program](https://hackenproof.com/aptos-labs/aptos-network) page. +To learn more visit the [Aptos Foundation Bounty Program](https://hackenproof.com/aptos) page. diff --git a/api/goldens/aptos_api__tests__transactions_test__test_simulation_failure_with_detail_error.json b/api/goldens/aptos_api__tests__transactions_test__test_simulation_failure_with_detail_error.json new file mode 100644 index 0000000000000..0e9929fbdde81 --- /dev/null +++ b/api/goldens/aptos_api__tests__transactions_test__test_simulation_failure_with_detail_error.json @@ -0,0 +1,95 @@ +[ + { + "version": "0", + "hash": "", + "state_change_hash": "", + "event_root_hash": "", + "state_checkpoint_hash": null, + "gas_used": "3", + "success": false, + "vm_status": "LINKER_ERROR\nExecution failed with message: Linker Error: Module 0000000000000000000000000000000000000000000000000000000000000001::MemeCoin doesn't exist", + "accumulator_root_hash": "", + "changes": [ + { + "address": "0xa550c18", + "state_key_hash": "", + "data": { + "type": "0x1::account::Account", + "data": { + "authentication_key": "0xcef8ffd1ab9017e96132df8a56b22de39a8155e1c3fc32affbbf93eb624b532a", + "coin_register_events": { + "counter": "1", + "guid": { + "id": { + "addr": "0xa550c18", + "creation_num": "0" + } + } + }, + "guid_creation_num": "4", + "key_rotation_events": { + "counter": "0", + "guid": { + "id": { + "addr": "0xa550c18", + "creation_num": "1" + } + } + }, + "rotation_capability_offer": { + "for": { + "vec": [] + } + }, + "sequence_number": "1", + "signer_capability_offer": { + "for": { + "vec": [] + } + } + } + }, + "type": "write_resource" + } + ], + "sender": "0xa550c18", + "sequence_number": "0", + "max_gas_amount": "100000000", + "gas_unit_price": "0", + "expiration_timestamp_secs": "18446744073709551615", + "payload": { + "function": "0x1::MemeCoin::transfer", + "type_arguments": [ + "0x1::aptos_coin::AptosCoin" + ], + "arguments": [ + "0x00000000000000000000000000000000000000000000000000000000000000dd", + "0x0100000000000000" + ], + "type": "entry_function_payload" + }, + "signature": { + "public_key": "0x14418f867a0bd6d42abb2daa50cd68a5a869ce208282481f57504f630510d0d3", + "signature": "0x1d4f1d6c0b140deb6c63e81c742ffd546c832683a14970c687fa823641d34395197548c242c126ea7226730ce66b9ab2f695a2bcda982f30944163179f9a3c08", + "type": "ed25519_signature" + }, + "events": [ + { + "guid": { + "creation_number": "0", + "account_address": "0x0" + }, + "sequence_number": "0", + "type": "0x1::transaction_fee::FeeStatement", + "data": { + "execution_gas_units": "3", + "io_gas_units": "0", + "storage_fee_octas": "0", + "storage_fee_refund_octas": "0", + "total_charge_gas_units": "3" + } + } + ], + "timestamp": "0" + } +] diff --git a/api/goldens/aptos_api__tests__transactions_test__test_simulation_failure_with_move_abort_error_rendering.json b/api/goldens/aptos_api__tests__transactions_test__test_simulation_failure_with_move_abort_error_rendering.json new file mode 100644 index 0000000000000..836779403fc98 --- /dev/null +++ b/api/goldens/aptos_api__tests__transactions_test__test_simulation_failure_with_move_abort_error_rendering.json @@ -0,0 +1,93 @@ +[ + { + "version": "3", + "hash": "", + "state_change_hash": "", + "event_root_hash": "", + "state_checkpoint_hash": null, + "gas_used": "11", + "success": false, + "vm_status": "Move abort in 0x1::coin: EINSUFFICIENT_BALANCE(0x10006): Not enough coins to complete transaction", + "accumulator_root_hash": "", + "changes": [ + { + "address": "0x34bf7e2d17674feb234371a7ea58efd715f0e56ba20ebf13789480d9d643afaf", + "state_key_hash": "", + "data": { + "type": "0x1::account::Account", + "data": { + "authentication_key": "0x34bf7e2d17674feb234371a7ea58efd715f0e56ba20ebf13789480d9d643afaf", + "coin_register_events": { + "counter": "1", + "guid": { + "id": { + "addr": "0x34bf7e2d17674feb234371a7ea58efd715f0e56ba20ebf13789480d9d643afaf", + "creation_num": "0" + } + } + }, + "guid_creation_num": "4", + "key_rotation_events": { + "counter": "0", + "guid": { + "id": { + "addr": "0x34bf7e2d17674feb234371a7ea58efd715f0e56ba20ebf13789480d9d643afaf", + "creation_num": "1" + } + } + }, + "rotation_capability_offer": { + "for": { + "vec": [] + } + }, + "sequence_number": "1", + "signer_capability_offer": { + "for": { + "vec": [] + } + } + } + }, + "type": "write_resource" + } + ], + "sender": "0x34bf7e2d17674feb234371a7ea58efd715f0e56ba20ebf13789480d9d643afaf", + "sequence_number": "0", + "max_gas_amount": "100000000", + "gas_unit_price": "0", + "expiration_timestamp_secs": "18446744073709551615", + "payload": { + "function": "0x1::aptos_account::transfer", + "type_arguments": [], + "arguments": [ + "0x1", + "999999999999999999" + ], + "type": "entry_function_payload" + }, + "signature": { + "public_key": "0xd5a781494d2bf1a174ddffde1e02cb8881cff6dab70e61cbdef393deac0ce639", + "signature": "0x0090fadcba9d32d9918286f8b651772a4d04a23633cc9d10f4339ad4d0b1b7c4ca4829542aa9a8b5a6a28e0e63dfd52863d38ca1ba1d2a57c4bf1efc72c0fb06", + "type": "ed25519_signature" + }, + "events": [ + { + "guid": { + "creation_number": "0", + "account_address": "0x0" + }, + "sequence_number": "0", + "type": "0x1::transaction_fee::FeeStatement", + "data": { + "execution_gas_units": "6", + "io_gas_units": "6", + "storage_fee_octas": "0", + "storage_fee_refund_octas": "0", + "total_charge_gas_units": "11" + } + } + ], + "timestamp": "500000" + } +] diff --git a/api/src/tests/transactions_test.rs b/api/src/tests/transactions_test.rs index b7e95d6c7c928..537d8ac34b01a 100644 --- a/api/src/tests/transactions_test.rs +++ b/api/src/tests/transactions_test.rs @@ -1504,6 +1504,42 @@ async fn test_simulation_failure_error_message() { .contains("Division by zero")); } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_simulation_failure_with_move_abort_error_rendering() { + let mut context = new_test_context(current_function_name!()); + let account = context.create_account().await; + let raw_txn = context + .transaction_factory() + .entry_function(EntryFunction::new( + ModuleId::new( + AccountAddress::from_hex_literal("0x1").unwrap(), + Identifier::new("aptos_account").unwrap(), + ), + Identifier::new("transfer").unwrap(), + vec![], + vec![ + bcs::to_bytes(&AccountAddress::from_hex_literal("0x1").unwrap()).unwrap(), + bcs::to_bytes(&999999999999999999u64).unwrap(), + ], + )) + .sender(account.address()) + .sequence_number(account.sequence_number()) + .expiration_timestamp_secs(u64::MAX) + .build(); + let invalid_key = AccountKey::generate(&mut context.rng()); + + let txn = raw_txn + .sign(invalid_key.private_key(), account.public_key().clone()) + .unwrap() + .into_inner(); + let body = bcs::to_bytes(&txn).unwrap(); + let resp = context + .expect_status_code(200) + .post_bcs_txn("/transactions/simulate", body) + .await; + context.check_golden_output(resp); +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_simulation_failure_with_detail_error() { let mut context = new_test_context(current_function_name!()); @@ -1536,10 +1572,7 @@ async fn test_simulation_failure_with_detail_error() { .expect_status_code(200) .post_bcs_txn("/transactions/simulate", body) .await; - assert!(resp.as_array().unwrap()[0]["vm_status"] - .as_str() - .unwrap() - .contains("LINKER_ERROR")); + context.check_golden_output(resp); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] diff --git a/api/src/transactions.rs b/api/src/transactions.rs index a0433209a6bf8..b7d2d75f0290f 100644 --- a/api/src/transactions.rs +++ b/api/src/transactions.rs @@ -1370,7 +1370,10 @@ impl TransactionsApi { let version = ledger_info.version(); // Ensure that all known statuses return their values in the output (even if they aren't supposed to) - let exe_status = ExecutionStatus::convert_vm_status_for_simulation(vm_status.clone()); + let exe_status = ExecutionStatus::conmbine_vm_status_for_simulation( + output.auxiliary_data(), + output.status().clone(), + ); let stats_key = match txn.payload() { TransactionPayload::Script(_) => { diff --git a/aptos-move/aptos-aggregator/src/delta_change_set.rs b/aptos-move/aptos-aggregator/src/delta_change_set.rs index 06422fb82ef79..a1bea4eb752e3 100644 --- a/aptos-move/aptos-aggregator/src/delta_change_set.rs +++ b/aptos-move/aptos-aggregator/src/delta_change_set.rs @@ -513,10 +513,6 @@ mod test { type ResourceGroupTag = (); type ResourceKey = (); - fn is_delayed_field_optimization_capable(&self) -> bool { - unimplemented!("Irrelevant for the test") - } - fn get_delayed_field_value( &self, _id: &Self::Identifier, diff --git a/aptos-move/aptos-aggregator/src/resolver.rs b/aptos-move/aptos-aggregator/src/resolver.rs index 1268758ac56aa..c15c6542f0517 100644 --- a/aptos-move/aptos-aggregator/src/resolver.rs +++ b/aptos-move/aptos-aggregator/src/resolver.rs @@ -140,8 +140,6 @@ pub trait TDelayedFieldView { type ResourceKey; type ResourceGroupTag; - fn is_delayed_field_optimization_capable(&self) -> bool; - /// Fetch a value of a DelayedField. fn get_delayed_field_value( &self, @@ -228,11 +226,6 @@ where type ResourceGroupTag = StructTag; type ResourceKey = StateKey; - fn is_delayed_field_optimization_capable(&self) -> bool { - // For resolvers that are not capable, it cannot be enabled - false - } - fn get_delayed_field_value( &self, _id: &Self::Identifier, diff --git a/aptos-move/aptos-aggregator/src/tests/types.rs b/aptos-move/aptos-aggregator/src/tests/types.rs index c923f4871d4f2..6cae8d5d36fc3 100644 --- a/aptos-move/aptos-aggregator/src/tests/types.rs +++ b/aptos-move/aptos-aggregator/src/tests/types.rs @@ -86,10 +86,6 @@ impl TDelayedFieldView for FakeAggregatorView { type ResourceGroupTag = StructTag; type ResourceKey = StateKey; - fn is_delayed_field_optimization_capable(&self) -> bool { - true - } - fn get_delayed_field_value( &self, id: &Self::Identifier, diff --git a/aptos-move/aptos-debugger/src/aptos_debugger.rs b/aptos-move/aptos-debugger/src/aptos_debugger.rs index 77cdb26e5c860..1fc70796f6cbc 100644 --- a/aptos-move/aptos-debugger/src/aptos_debugger.rs +++ b/aptos-move/aptos-debugger/src/aptos_debugger.rs @@ -84,18 +84,14 @@ impl AptosDebugger { .check_signature() .map_err(|err| format_err!("Unexpected VM Error: {:?}", err))?; - // TODO(Gas): revisit this. - let resolver = state_view.as_move_resolver(); - let vm = AptosVM::new( - &resolver, - /*override_is_delayed_field_optimization_capable=*/ Some(false), - ); - // Module bundle is deprecated! if let TransactionPayload::ModuleBundle(_) = txn.payload() { - anyhow::bail!("Module bundle payload has been removed") + bail!("Module bundle payload has been removed") } + let vm = AptosVM::new(&state_view); + let resolver = state_view.as_move_resolver(); + let (status, output, gas_profiler) = vm.execute_user_transaction_with_modified_gas_meter( &resolver, &txn, diff --git a/aptos-move/aptos-native-interface/src/builder.rs b/aptos-move/aptos-native-interface/src/builder.rs index 6df3a3a40a9cc..140d9fbecc12d 100644 --- a/aptos-move/aptos-native-interface/src/builder.rs +++ b/aptos-move/aptos-native-interface/src/builder.rs @@ -45,6 +45,7 @@ impl SafeNativeBuilder { misc_gas_params: MiscGasParameters, timed_features: TimedFeatures, features: Features, + gas_hook: Option>, ) -> Self { Self { data: Arc::new(SharedData { @@ -55,17 +56,10 @@ impl SafeNativeBuilder { features, }), enable_incremental_gas_charging: true, - gas_hook: None, + gas_hook, } } - pub fn set_gas_hook(&mut self, action: F) - where - F: Fn(DynamicExpression) + Send + Sync + 'static, - { - self.gas_hook = Some(Arc::new(action)); - } - /// Controls the default incremental gas charging behavior of the natives created from this builder. /// /// See [`SafeNativeContext::set_incremental_gas_charging()`] for details. diff --git a/aptos-move/aptos-native-interface/src/context.rs b/aptos-move/aptos-native-interface/src/context.rs index a3e445f423488..1e4b116b748cd 100644 --- a/aptos-move/aptos-native-interface/src/context.rs +++ b/aptos-move/aptos-native-interface/src/context.rs @@ -118,14 +118,4 @@ impl<'a, 'b, 'c, 'd> SafeNativeContext<'a, 'b, 'c, 'd> { pub fn set_incremental_gas_charging(&mut self, enable: bool) { self.enable_incremental_gas_charging = enable; } - - /// Returns true if the aggregator snapshots feature is enabled. - pub fn aggregator_v2_api_enabled(&self) -> bool { - self.get_feature_flags().is_aggregator_v2_api_enabled() - } - - pub fn aggregator_v2_delayed_fields_enabled(&self) -> bool { - self.get_feature_flags() - .is_aggregator_v2_delayed_fields_enabled() - } } 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 2e701e1ed0f3b..1d66cc644cf95 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 @@ -25,6 +25,7 @@ use aptos_types::{ EntryFunction as TransactionEntryFunction, ExecutionStatus, RawTransaction, Script as TransactionScript, Transaction, TransactionOutput, TransactionStatus, }, + vm::configs::set_paranoid_type_checks, }; use aptos_vm::{AptosVM, VMExecutor}; use aptos_vm_genesis::GENESIS_KEYPAIR; @@ -617,7 +618,7 @@ impl<'a> MoveTestAdapter<'a> for AptosTestAdapter<'a> { pre_compiled_deps_v2: Option<&'a PrecompiledFilesModules>, task_opt: Option>, ) -> (Self, Option) { - AptosVM::set_paranoid_type_checks(true); + set_paranoid_type_checks(true); // Named address mapping let additional_named_address_mapping = match task_opt.as_ref().map(|t| &t.command) { Some((InitCommand { named_addresses }, _)) => { @@ -1136,6 +1137,6 @@ pub fn run_aptos_test_with_config( }; let v1_lib = precompiled_v1_stdlib_if_needed(&config); let v2_lib = precompiled_v2_stdlib_if_needed(&config); - AptosVM::set_paranoid_type_checks(true); + set_paranoid_type_checks(true); run_test_impl::(config, path, v1_lib, v2_lib, &suffix) } 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 795ddb2d2854c..9358930eac58e 100644 --- a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs +++ b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs @@ -135,6 +135,7 @@ fn main() -> Result<()> { MiscGasParameters::zeros(), TimedFeaturesBuilder::enable_all().build(), Features::default(), + None, ); let stdlib_addr = AccountAddress::from_hex_literal("0x1").unwrap(); @@ -150,7 +151,7 @@ fn main() -> Result<()> { &mut builder, )); - let vm = MoveVM::new(natives).unwrap(); + let vm = MoveVM::new(natives); let mut storage = InMemoryStorage::new(); let test_modules = compile_test_modules(); diff --git a/aptos-move/aptos-vm-types/Cargo.toml b/aptos-move/aptos-vm-types/Cargo.toml index 72f92e55e866b..b2c5155461224 100644 --- a/aptos-move/aptos-vm-types/Cargo.toml +++ b/aptos-move/aptos-vm-types/Cargo.toml @@ -24,6 +24,7 @@ claims = { workspace = true } either = { workspace = true } move-binary-format = { workspace = true } move-core-types = { workspace = true } +move-vm-runtime = { workspace = true } move-vm-types = { workspace = true } rand = { workspace = true } serde = { workspace = true } diff --git a/aptos-move/aptos-vm-types/src/environment.rs b/aptos-move/aptos-vm-types/src/environment.rs new file mode 100644 index 0000000000000..af1e3b72fabab --- /dev/null +++ b/aptos-move/aptos-vm-types/src/environment.rs @@ -0,0 +1,188 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use aptos_gas_schedule::{gas_feature_versions::RELEASE_V1_15, AptosGasParameters}; +use aptos_types::{ + chain_id::ChainId, + on_chain_config::{ + ConfigurationResource, Features, OnChainConfig, TimedFeatureOverride, TimedFeatures, + TimedFeaturesBuilder, + }, + state_store::StateView, + vm::configs::{aptos_prod_vm_config, get_timed_feature_override}, +}; +use move_vm_runtime::config::VMConfig; +use move_vm_types::loaded_data::runtime_types::TypeBuilder; +use std::sync::Arc; + +// TODO(George): move configs here from types crate. +pub fn aptos_prod_ty_builder( + features: &Features, + gas_feature_version: u64, + gas_params: &AptosGasParameters, +) -> TypeBuilder { + if features.is_limit_type_size_enabled() && gas_feature_version >= RELEASE_V1_15 { + let max_ty_size = gas_params.vm.txn.max_ty_size; + let max_ty_depth = gas_params.vm.txn.max_ty_depth; + TypeBuilder::with_limits(max_ty_size.into(), max_ty_depth.into()) + } else { + aptos_default_ty_builder(features) + } +} + +pub fn aptos_default_ty_builder(features: &Features) -> TypeBuilder { + if features.is_limit_type_size_enabled() { + // Type builder to use when: + // 1. Type size gas parameters are not yet in gas schedule (before V14). + // 2. No gas parameters are found on-chain. + TypeBuilder::with_limits(128, 20) + } else { + TypeBuilder::Legacy + } +} + +/// A runtime environment which can be used for VM initialization and more. +#[derive(Clone)] +pub struct Environment { + chain_id: ChainId, + + features: Features, + timed_features: TimedFeatures, + + vm_config: VMConfig, +} + +impl Environment { + pub fn new(state_view: &impl StateView) -> Self { + let features = Features::fetch_config(state_view).unwrap_or_default(); + + // If no chain ID is in storage, we assume we are in a testing environment. + let chain_id = ChainId::fetch_config(state_view).unwrap_or_else(ChainId::test); + let timestamp = ConfigurationResource::fetch_config(state_view) + .map(|config| config.last_reconfiguration_time()) + .unwrap_or(0); + + let mut timed_features_builder = TimedFeaturesBuilder::new(chain_id, timestamp); + if let Some(profile) = get_timed_feature_override() { + timed_features_builder = timed_features_builder.with_override_profile(profile) + } + let timed_features = timed_features_builder.build(); + + let ty_builder = aptos_default_ty_builder(&features); + Self::initialize(features, timed_features, chain_id, ty_builder) + } + + pub fn testing(chain_id: ChainId) -> Arc { + let features = Features::default(); + + // FIXME: should probably read the timestamp from storage. + let timed_features = TimedFeaturesBuilder::enable_all() + .with_override_profile(TimedFeatureOverride::Testing) + .build(); + + let ty_builder = aptos_default_ty_builder(&features); + Arc::new(Self::initialize( + features, + timed_features, + chain_id, + ty_builder, + )) + } + + pub fn with_features_for_testing(self, features: Features) -> Arc { + let ty_builder = aptos_default_ty_builder(&features); + Arc::new(Self::initialize( + features, + self.timed_features, + self.chain_id, + ty_builder, + )) + } + + pub fn try_enable_delayed_field_optimization(mut self) -> Self { + if self.features.is_aggregator_v2_delayed_fields_enabled() { + self.vm_config.delayed_field_optimization_enabled = true; + } + self + } + + #[inline] + pub fn chain_id(&self) -> ChainId { + self.chain_id + } + + #[inline] + pub fn features(&self) -> &Features { + &self.features + } + + #[inline] + pub fn timed_features(&self) -> &TimedFeatures { + &self.timed_features + } + + #[inline] + pub fn vm_config(&self) -> &VMConfig { + &self.vm_config + } + + fn initialize( + features: Features, + timed_features: TimedFeatures, + chain_id: ChainId, + ty_builder: TypeBuilder, + ) -> Self { + // By default, do not use delayed field optimization. Instead, clients should enable it + // manually where applicable. + let delayed_field_optimization_enabled = false; + + let vm_config = aptos_prod_vm_config( + &features, + &timed_features, + delayed_field_optimization_enabled, + ty_builder, + ); + + Self { + chain_id, + features, + timed_features, + vm_config, + } + } +} + +#[cfg(test)] +pub mod test { + use super::*; + use aptos_language_e2e_tests::data_store::FakeDataStore; + + #[test] + fn test_new_environment() { + // This creates an empty state. + let state_view = FakeDataStore::default(); + let env = Environment::new(&state_view); + + // Check default values. + assert_eq!(&env.features, &Features::default()); + assert_eq!(env.chain_id.id(), ChainId::test().id()); + assert!(!env.vm_config.delayed_field_optimization_enabled); + + let env = env.try_enable_delayed_field_optimization(); + assert!(env.vm_config.delayed_field_optimization_enabled); + } + + #[test] + fn test_environment_for_testing() { + let env = Environment::testing(ChainId::new(55)); + + assert_eq!(&env.features, &Features::default()); + assert_eq!(env.chain_id.id(), 55); + assert!(!env.vm_config.delayed_field_optimization_enabled); + + let expected_timed_features = TimedFeaturesBuilder::enable_all() + .with_override_profile(TimedFeatureOverride::Testing) + .build(); + assert_eq!(&env.timed_features, &expected_timed_features); + } +} diff --git a/aptos-move/aptos-vm-types/src/lib.rs b/aptos-move/aptos-vm-types/src/lib.rs index 43a626727e742..fd66470b0707d 100644 --- a/aptos-move/aptos-vm-types/src/lib.rs +++ b/aptos-move/aptos-vm-types/src/lib.rs @@ -4,6 +4,7 @@ pub mod abstract_write_op; pub mod change_set; pub mod check_change_set; +pub mod environment; pub mod output; pub mod resolver; pub mod resource_group_adapter; diff --git a/aptos-move/aptos-vm/src/aptos_vm.rs b/aptos-move/aptos-vm/src/aptos_vm.rs index ee2b68e4286dd..de461f12aa0de 100644 --- a/aptos-move/aptos-vm/src/aptos_vm.rs +++ b/aptos-move/aptos-vm/src/aptos_vm.rs @@ -32,10 +32,7 @@ use aptos_framework::{ }; use aptos_gas_algebra::{Gas, GasQuantity, NumBytes, Octa}; use aptos_gas_meter::{AptosGasMeter, GasAlgebra}; -use aptos_gas_schedule::{ - gas_feature_versions::RELEASE_V1_15, AptosGasParameters, TransactionGasParameters, - VMGasParameters, -}; +use aptos_gas_schedule::{AptosGasParameters, TransactionGasParameters, VMGasParameters}; use aptos_logger::{enabled, prelude::*, Level}; use aptos_metrics_core::TimerHelper; #[cfg(any(test, feature = "testing"))] @@ -50,12 +47,10 @@ 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, ApprovedExecutionHashes, ConfigStorage, ConfigurationResource, - FeatureFlag, Features, OnChainConfig, TimedFeatureOverride, TimedFeatures, - TimedFeaturesBuilder, + new_epoch_event_key, ApprovedExecutionHashes, ConfigStorage, FeatureFlag, Features, + OnChainConfig, TimedFeatures, }, randomness::Randomness, state_store::{StateView, TStateView}, @@ -66,7 +61,7 @@ use aptos_types::{ TransactionAuxiliaryData, TransactionOutput, TransactionPayload, TransactionStatus, VMValidatorResult, ViewFunctionOutput, WriteSetPayload, }, - vm::configs::{aptos_prod_deserializer_config, RandomnessConfig}, + vm::configs::RandomnessConfig, vm_status::{AbortLocation, StatusCode, VMStatus}, }; use aptos_utils::{aptos_try, return_on_failure}; @@ -74,6 +69,7 @@ use aptos_vm_logging::{log_schema::AdapterLogSchema, speculative_error, speculat use aptos_vm_types::{ abstract_write_op::AbstractResourceWriteOp, change_set::VMChangeSet, + environment::Environment, output::VMOutput, resolver::{ExecutorView, ResourceGroupView}, storage::{change_set_configs::ChangeSetConfigs, StorageGasParameters}, @@ -85,6 +81,7 @@ use fail::fail_point; use move_binary_format::{ access::ModuleAccess, compatibility::Compatibility, + deserializer::DeserializerConfig, errors::{Location, PartialVMError, PartialVMResult, VMError, VMResult}, CompiledModule, }; @@ -102,10 +99,7 @@ use move_vm_runtime::{ logging::expect_no_verification_errors, module_traversal::{TraversalContext, TraversalStorage}, }; -use move_vm_types::{ - gas::{GasMeter, UnmeteredGasMeter}, - loaded_data::runtime_types::TypeBuilder, -}; +use move_vm_types::gas::{GasMeter, UnmeteredGasMeter}; use num_cpus; use once_cell::sync::{Lazy, OnceCell}; use std::{ @@ -118,10 +112,8 @@ use std::{ static EXECUTION_CONCURRENCY_LEVEL: OnceCell = OnceCell::new(); static NUM_EXECUTION_SHARD: OnceCell = OnceCell::new(); static NUM_PROOF_READING_THREADS: OnceCell = OnceCell::new(); -static PARANOID_TYPE_CHECKS: OnceCell = OnceCell::new(); static DISCARD_FAILED_BLOCKS: OnceCell = OnceCell::new(); static PROCESSED_TRANSACTIONS_DETAILED_COUNTERS: OnceCell = OnceCell::new(); -static TIMED_FEATURE_OVERRIDE: OnceCell = OnceCell::new(); // TODO: Don't expose this in AptosVM, and use only in BlockAptosVM! pub static RAYON_EXEC_POOL: Lazy> = Lazy::new(|| { @@ -221,95 +213,43 @@ fn is_approved_gov_script( } } -// TODO(George): move to config file when it is moved from types crate. -pub fn aptos_prod_ty_builder( - features: &Features, - gas_feature_version: u64, - gas_params: &AptosGasParameters, -) -> TypeBuilder { - if features.is_limit_type_size_enabled() && gas_feature_version >= RELEASE_V1_15 { - let max_ty_size = gas_params.vm.txn.max_ty_size; - let max_ty_depth = gas_params.vm.txn.max_ty_depth; - TypeBuilder::with_limits(max_ty_size.into(), max_ty_depth.into()) - } else { - aptos_default_ty_builder(features) - } -} - -pub fn aptos_default_ty_builder(features: &Features) -> TypeBuilder { - if features.is_limit_type_size_enabled() { - // Type builder to use when: - // 1. Type size gas parameters are not yet in gas schedule (before V14). - // 2. No gas parameters are found on-chain. - TypeBuilder::with_limits(128, 20) - } else { - TypeBuilder::Legacy - } -} - pub struct AptosVM { is_simulation: bool, move_vm: MoveVmExt, pub(crate) gas_feature_version: u64, gas_params: Result, pub(crate) storage_gas_params: Result, - timed_features: TimedFeatures, /// For a new chain, or even mainnet, the VK might not necessarily be set. pvk: Option>, randomness_config: RandomnessConfig, } impl AptosVM { - pub fn new( - resolver: &impl AptosMoveResolver, - override_is_delayed_field_optimization_capable: Option, - ) -> Self { - let _timer = TIMER.timer_with(&["AptosVM::new"]); - let features = Features::fetch_config(resolver).unwrap_or_default(); - let randomness_config = RandomnessConfig::fetch(resolver); - let (gas_params, storage_gas_params, gas_feature_version) = - get_gas_parameters(&features, resolver); - - // If no chain ID is in storage, we assume we are in a testing environment and use ChainId::TESTING - let chain_id = ChainId::fetch_config(resolver).unwrap_or_else(ChainId::test); - - let timestamp = ConfigurationResource::fetch_config(resolver) - .map(|config| config.last_reconfiguration_time()) - .unwrap_or(0); + /// Creates a new VM instance, initializing the runtime environment from the state. + pub fn new(state_view: &impl StateView) -> Self { + let env = Arc::new(Environment::new(state_view)); + Self::new_with_environment(env, state_view) + } - let mut timed_features_builder = TimedFeaturesBuilder::new(chain_id, timestamp); - if let Some(profile) = Self::get_timed_feature_override() { - timed_features_builder = timed_features_builder.with_override_profile(profile) - } - let timed_features = timed_features_builder.build(); + /// Creates a new VM instance based on the runtime environment, and used by block + /// executor to create multiple tasks sharing the same execution configurations. + // TODO: Passing `state_view` is not needed once we move keyless and gas-related + // configs to the environment. + pub(crate) fn new_with_environment(env: Arc, state_view: &impl StateView) -> Self { + let _timer = TIMER.timer_with(&["AptosVM::new"]); - // If aggregator execution is enabled, we need to tag aggregator_v2 types, - // so they can be exchanged with identifiers during VM execution. - let override_is_delayed_field_optimization_capable = - override_is_delayed_field_optimization_capable - .unwrap_or_else(|| resolver.is_delayed_field_optimization_capable()); - let aggregator_v2_type_tagging = override_is_delayed_field_optimization_capable - && features.is_aggregator_v2_delayed_fields_enabled(); + let (gas_params, storage_gas_params, gas_feature_version) = + get_gas_parameters(env.features(), state_view); - let move_vm = MoveVmExt::new( - gas_feature_version, - gas_params.as_ref(), - chain_id.id(), - features, - timed_features.clone(), - resolver, - aggregator_v2_type_tagging, - ) - .expect("should be able to create Move VM; check if there are duplicated natives"); + let resolver = state_view.as_move_resolver(); + let move_vm = MoveVmExt::new(gas_feature_version, gas_params.as_ref(), env, &resolver); // 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) + 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() - }); + .and_then(|vk| vk.try_into().ok()); + let randomness_config = RandomnessConfig::fetch(state_view); Self { is_simulation: false, @@ -317,7 +257,6 @@ impl AptosVM { gas_feature_version, gas_params, storage_gas_params, - timed_features, pvk, randomness_config, } @@ -335,7 +274,22 @@ impl AptosVM { #[inline(always)] fn features(&self) -> &Features { - self.move_vm.features() + self.move_vm.env.features() + } + + #[inline(always)] + fn timed_features(&self) -> &TimedFeatures { + self.move_vm.env.timed_features() + } + + #[inline(always)] + fn deserializer_config(&self) -> &DeserializerConfig { + &self.move_vm.env.vm_config().deserializer_config + } + + #[inline(always)] + fn chain_id(&self) -> ChainId { + self.move_vm.env.chain_id() } /// Sets execution concurrency level when invoked the first time. @@ -369,20 +323,6 @@ impl AptosVM { } } - /// Sets runtime config when invoked the first time. - pub fn set_paranoid_type_checks(enable: bool) { - // Only the first call succeeds, due to OnceCell semantics. - PARANOID_TYPE_CHECKS.set(enable).ok(); - } - - /// Get the paranoid type check flag if already set, otherwise return default true - pub fn get_paranoid_checks() -> bool { - match PARANOID_TYPE_CHECKS.get() { - Some(enable) => *enable, - None => true, - } - } - /// Sets runtime config when invoked the first time. pub fn set_discard_failed_blocks(enable: bool) { // Only the first call succeeds, due to OnceCell semantics. @@ -397,15 +337,6 @@ impl AptosVM { } } - // Set the override profile for timed features. - pub fn set_timed_feature_override(profile: TimedFeatureOverride) { - TIMED_FEATURE_OVERRIDE.set(profile).ok(); - } - - pub fn get_timed_feature_override() -> Option { - TIMED_FEATURE_OVERRIDE.get().cloned() - } - /// Sets the # of async proof reading threads. pub fn set_num_proof_reading_threads_once(mut num_threads: usize) { // TODO(grao): Do more analysis to tune this magic number. @@ -515,6 +446,7 @@ impl AptosVM { ); } } + let (txn_status, txn_aux_data) = TransactionStatus::from_vm_status( error_vm_status.clone(), self.features() @@ -795,7 +727,7 @@ impl AptosVM { // TODO(Gerardo): consolidate the extended validation to verifier. verifier::event_validation::verify_no_event_emission_in_script( script.code(), - &session.get_vm_config().deserializer_config, + self.deserializer_config(), )?; let args = verifier::transaction_arg_validation::validate_combine_signer_and_txn_args( @@ -1410,12 +1342,12 @@ impl AptosVM { /// Deserialize a module bundle. fn deserialize_module_bundle(&self, modules: &ModuleBundle) -> VMResult> { - let deserializer_config = aptos_prod_deserializer_config(self.features()); - let mut result = vec![]; for module_blob in modules.iter() { - match CompiledModule::deserialize_with_config(module_blob.code(), &deserializer_config) - { + match CompiledModule::deserialize_with_config( + module_blob.code(), + self.deserializer_config(), + ) { Ok(module) => { result.push(module); }, @@ -1582,7 +1514,7 @@ impl AptosVM { } } } - aptos_framework::verify_module_metadata(m, self.features(), &self.timed_features) + aptos_framework::verify_module_metadata(m, self.features(), self.timed_features()) .map_err(|err| Self::metadata_validation_error(&err.to_string()))?; } verifier::resource_groups::validate_resource_groups( @@ -1603,7 +1535,7 @@ impl AptosVM { /// Check whether the bytecode can be published to mainnet based on the unstable tag in the metadata fn reject_unstable_bytecode(&self, modules: &[CompiledModule]) -> VMResult<()> { - if self.move_vm.chain_id().is_mainnet() { + if self.chain_id().is_mainnet() { for module in modules { if let Some(metadata) = aptos_framework::get_compilation_metadata_from_compiled_module(module) @@ -1649,23 +1581,13 @@ impl AptosVM { .map_err(|_| VMStatus::error(StatusCode::INVALID_SIGNATURE, None))?; // If there are keyless TXN authenticators, validate them all. - 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")); - } - - if !self.is_simulation { - keyless_validation::validate_authenticators( - self.pvk.as_ref().unwrap(), - &keyless_authenticators, - self.features(), - resolver, - )?; - } + if !keyless_authenticators.is_empty() && !self.is_simulation { + keyless_validation::validate_authenticators( + &self.pvk, + &keyless_authenticators, + self.features(), + resolver, + )?; } // The prologue MUST be run AFTER any validation. Otherwise you may run prologue and hit @@ -2058,7 +1980,7 @@ impl AptosVM { let change_set = self.execute_write_set( resolver, &write_set_payload, - Some(aptos_types::account_config::reserved_vm_address()), + Some(account_config::reserved_vm_address()), SessionId::genesis(genesis_id), )?; @@ -2223,11 +2145,7 @@ impl AptosVM { arguments: Vec>, max_gas_amount: u64, ) -> ViewFunctionOutput { - let resolver = state_view.as_move_resolver(); - let vm = AptosVM::new( - &resolver, - /*override_is_delayed_field_optimization_capable=*/ Some(false), - ); + let vm = AptosVM::new(state_view); let log_context = AdapterLogSchema::new(state_view.id(), 0); @@ -2253,6 +2171,7 @@ impl AptosVM { max_gas_amount.into(), ); + let resolver = state_view.as_move_resolver(); let mut session = vm.new_session(&resolver, SessionId::Void, None); let execution_result = Self::execute_view_function_in_vm( &mut session, @@ -2642,7 +2561,6 @@ impl VMExecutor for AptosVM { } } -// VMValidator external API impl VMValidator for AptosVM { /// Determine if a transaction is valid. Will return `None` if the transaction is accepted, /// `Some(Err)` if the VM rejects it, with `Err` as an error code. Verification performs the @@ -2757,11 +2675,8 @@ impl VMValidator for AptosVM { pub struct AptosSimulationVM(AptosVM); impl AptosSimulationVM { - pub fn new(resolver: &impl AptosMoveResolver) -> Self { - let mut vm = AptosVM::new( - resolver, - /*override_is_delayed_field_optimization_capable=*/ Some(false), - ); + pub fn new(state_view: &impl StateView) -> Self { + let mut vm = AptosVM::new(state_view); vm.is_simulation = true; Self(vm) } @@ -2778,10 +2693,10 @@ impl AptosSimulationVM { "Simulated transaction should not have a valid signature" ); - let resolver = state_view.as_move_resolver(); - let vm = Self::new(&resolver); + let vm = Self::new(state_view); let log_context = AdapterLogSchema::new(state_view.id(), 0); + let resolver = state_view.as_move_resolver(); let (vm_status, vm_output) = vm.0.execute_user_transaction(&resolver, transaction, &log_context); let txn_output = vm_output diff --git a/aptos-move/aptos-vm/src/block_executor/mod.rs b/aptos-move/aptos-vm/src/block_executor/mod.rs index 1e2279af85ee8..1aec0a6254cf7 100644 --- a/aptos-move/aptos-vm/src/block_executor/mod.rs +++ b/aptos-move/aptos-vm/src/block_executor/mod.rs @@ -31,7 +31,9 @@ use aptos_types::{ write_set::WriteOp, }; use aptos_vm_logging::{flush_speculative_logs, init_speculative_logs}; -use aptos_vm_types::{abstract_write_op::AbstractResourceWriteOp, output::VMOutput}; +use aptos_vm_types::{ + abstract_write_op::AbstractResourceWriteOp, environment::Environment, output::VMOutput, +}; use move_core_types::{ language_storage::StructTag, value::MoveTypeLayout, @@ -415,13 +417,15 @@ impl BlockAptosVM { BLOCK_EXECUTOR_CONCURRENCY.set(config.local.concurrency_level as i64); let executor = BlockExecutor::< SignatureVerifiedTransaction, - AptosExecutorTask, + AptosExecutorTask, S, L, ExecutableTestType, >::new(config, executor_thread_pool, transaction_commit_listener); - let ret = executor.execute_block(state_view, signature_verified_block, state_view); + let environment = + Arc::new(Environment::new(state_view).try_enable_delayed_field_optimization()); + let ret = executor.execute_block(environment, signature_verified_block, state_view); match ret { Ok(block_output) => { let (transaction_outputs, block_end_info) = block_output.into_inner(); diff --git a/aptos-move/aptos-vm/src/block_executor/vm_wrapper.rs b/aptos-move/aptos-vm/src/block_executor/vm_wrapper.rs index 3561599e0cd18..a73dc4bfd78d9 100644 --- a/aptos-move/aptos-vm/src/block_executor/vm_wrapper.rs +++ b/aptos-move/aptos-vm/src/block_executor/vm_wrapper.rs @@ -2,48 +2,43 @@ // Parts of the project are originally copyright © Meta Platforms, Inc. // SPDX-License-Identifier: Apache-2.0 -use crate::{ - aptos_vm::AptosVM, block_executor::AptosTransactionOutput, data_cache::AsMoveResolver, -}; +use crate::{aptos_vm::AptosVM, block_executor::AptosTransactionOutput}; use aptos_block_executor::task::{ExecutionStatus, ExecutorTask}; use aptos_logger::{enabled, Level}; use aptos_mvhashmap::types::TxnIndex; use aptos_types::{ - state_store::StateView, + state_store::{StateView, StateViewId}, transaction::{ signature_verified_transaction::SignatureVerifiedTransaction, Transaction, WriteSetPayload, }, }; use aptos_vm_logging::{log_schema::AdapterLogSchema, prelude::*}; -use aptos_vm_types::resolver::{ExecutorView, ResourceGroupView}; +use aptos_vm_types::{ + environment::Environment, + resolver::{ExecutorView, ResourceGroupView}, +}; use fail::fail_point; use move_core_types::vm_status::{StatusCode, VMStatus}; +use std::sync::Arc; -pub(crate) struct AptosExecutorTask<'a, S> { +pub(crate) struct AptosExecutorTask { vm: AptosVM, - base_view: &'a S, + id: StateViewId, } -impl<'a, S: 'a + StateView + Sync> ExecutorTask for AptosExecutorTask<'a, S> { - type Argument = &'a S; +impl ExecutorTask for AptosExecutorTask { + type Environment = Arc; type Error = VMStatus; type Output = AptosTransactionOutput; type Txn = SignatureVerifiedTransaction; - fn init(argument: &'a S) -> Self { - // AptosVM has to be initialized using configs from storage. - let vm = AptosVM::new( - &argument.as_move_resolver(), - /*override_is_delayed_field_optimization_capable=*/ Some(true), - ); - - Self { - vm, - base_view: argument, - } + fn init(env: Self::Environment, state_view: &impl StateView) -> Self { + let vm = AptosVM::new_with_environment(env, state_view); + let id = state_view.id(); + Self { vm, id } } - // This function is called by the BlockExecutor for each transaction is intends + // This function is called by the BlockExecutor for each transaction it intends // to execute (via the ExecutorTask trait). It can be as a part of sequential // execution, or speculatively as a part of a parallel execution. fn execute_transaction( @@ -56,7 +51,7 @@ impl<'a, S: 'a + StateView + Sync> ExecutorTask for AptosExecutorTask<'a, S> { ExecutionStatus::DelayedFieldsCodeInvariantError("fail points error".into()) }); - let log_context = AdapterLogSchema::new(self.base_view.id(), txn_idx as usize); + let log_context = AdapterLogSchema::new(self.id, txn_idx as usize); let resolver = self .vm .as_move_resolver_with_group_view(executor_with_group_view); diff --git a/aptos-move/aptos-vm/src/data_cache.rs b/aptos-move/aptos-vm/src/data_cache.rs index cec4c7954b085..da4e7a544c1f4 100644 --- a/aptos-move/aptos-vm/src/data_cache.rs +++ b/aptos-move/aptos-vm/src/data_cache.rs @@ -237,10 +237,6 @@ impl<'e, E: ExecutorView> TDelayedFieldView for StorageAdapter<'e, E> { type ResourceGroupTag = StructTag; type ResourceKey = StateKey; - fn is_delayed_field_optimization_capable(&self) -> bool { - self.executor_view.is_delayed_field_optimization_capable() - } - fn get_delayed_field_value( &self, id: &Self::Identifier, diff --git a/aptos-move/aptos-vm/src/keyless_validation.rs b/aptos-move/aptos-vm/src/keyless_validation.rs index 06644bb9ff7c1..bcf69050eb661 100644 --- a/aptos-move/aptos-vm/src/keyless_validation.rs +++ b/aptos-move/aptos-vm/src/keyless_validation.rs @@ -121,19 +121,21 @@ fn get_jwk_for_authenticator( /// Ensures that **all** keyless authenticators in the transaction are valid. pub(crate) fn validate_authenticators( - pvk: &PreparedVerifyingKey, + pvk: &Option>, authenticators: &Vec<(KeylessPublicKey, KeylessSignature)>, features: &Features, resolver: &impl AptosMoveResolver, ) -> Result<(), VMStatus> { + let mut with_zk = false; 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() - { - return Err(VMStatus::error(StatusCode::FEATURE_UNDER_GATING, None)); - } + if matches!(sig.cert, EphemeralCertificate::ZeroKnowledgeSig { .. }) { + if !features.is_zk_keyless_enabled() { + return Err(VMStatus::error(StatusCode::FEATURE_UNDER_GATING, None)); + } + with_zk = true; + } if matches!(sig.cert, EphemeralCertificate::OpenIdSig { .. }) && !features.is_zkless_keyless_enabled() { @@ -146,6 +148,11 @@ pub(crate) fn validate_authenticators( } } + // If there are ZK authenticators, the Groth16 VK must have been set on-chain. + if with_zk && pvk.is_none() { + return Err(invalid_signature!("Groth16 VK has not been set on-chain")); + } + let config = &get_configs_onchain(resolver)?; if authenticators.len() > config.max_signatures_per_txn as usize { // println!("[aptos-vm][groth16] Too many keyless authenticators"); @@ -234,7 +241,8 @@ pub(crate) fn validate_authenticators( } } - let result = zksig.verify_groth16_proof(public_inputs_hash, pvk); + let result = zksig + .verify_groth16_proof(public_inputs_hash, pvk.as_ref().unwrap()); result.map_err(|_| { // println!("[aptos-vm][groth16] ZKP verification failed"); 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 f1d894342257e..bcd7a1f381d1e 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/mod.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/mod.rs @@ -12,7 +12,7 @@ pub(crate) mod write_op_converter; pub use crate::move_vm_ext::{ resolver::{AptosMoveResolver, AsExecutorView, AsResourceGroupView, ResourceGroupResolver}, session::SessionExt, - vm::MoveVmExt, + vm::{GenesisMoveVM, MoveVmExt}, }; use aptos_types::state_store::state_key::StateKey; pub use aptos_types::transaction::user_transaction_context::UserTransactionContext; 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 b5bda793808bd..d08cd89af0f1d 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 @@ -3,15 +3,26 @@ use crate::{ data_cache::get_resource_group_member_from_metadata, - move_vm_ext::{resource_state_key, write_op_converter::WriteOpConverter, AptosMoveResolver}, + move_vm_ext::{ + resource_state_key, write_op_converter::WriteOpConverter, AptosMoveResolver, SessionId, + }, }; use aptos_framework::natives::{ aggregator_natives::{AggregatorChangeSet, AggregatorChangeV1, NativeAggregatorContext}, code::{NativeCodeContext, PublishRequest}, + cryptography::{algebra::AlgebraContext, ristretto255_point::NativeRistrettoPointContext}, event::NativeEventContext, + object::NativeObjectContext, + randomness::RandomnessContext, + state_storage::NativeStateStorageContext, + transaction_context::NativeTransactionContext, }; use aptos_table_natives::{NativeTableContext, TableChangeSet}; -use aptos_types::{contract_event::ContractEvent, state_store::state_key::StateKey}; +use aptos_types::{ + chain_id::ChainId, contract_event::ContractEvent, on_chain_config::Features, + state_store::state_key::StateKey, + transaction::user_transaction_context::UserTransactionContext, +}; use aptos_vm_types::{change_set::VMChangeSet, storage::change_set_configs::ChangeSetConfigs}; use bytes::Bytes; use move_binary_format::errors::{Location, PartialVMError, PartialVMResult, VMResult}; @@ -21,7 +32,9 @@ use move_core_types::{ value::MoveTypeLayout, vm_status::StatusCode, }; -use move_vm_runtime::{move_vm::MoveVM, session::Session}; +use move_vm_runtime::{ + move_vm::MoveVM, native_extensions::NativeContextExtensions, session::Session, +}; use move_vm_types::{value_serde::serialize_and_allow_delayed_values, values::Value}; use std::{ collections::BTreeMap, @@ -46,19 +59,55 @@ pub type BytesWithResourceLayout = (Bytes, Option>); pub struct SessionExt<'r, 'l> { inner: Session<'r, 'l>, - remote: &'r dyn AptosMoveResolver, + resolver: &'r dyn AptosMoveResolver, is_storage_slot_metadata_enabled: bool, } impl<'r, 'l> SessionExt<'r, 'l> { - pub fn new( - inner: Session<'r, 'l>, - remote: &'r dyn AptosMoveResolver, - is_storage_slot_metadata_enabled: bool, + pub(crate) fn new( + session_id: SessionId, + move_vm: &'l MoveVM, + chain_id: ChainId, + features: &Features, + maybe_user_transaction_context: Option, + resolver: &'r R, ) -> Self { + let mut extensions = NativeContextExtensions::default(); + let txn_hash: [u8; 32] = session_id + .as_uuid() + .to_vec() + .try_into() + .expect("HashValue should convert to [u8; 32]"); + + extensions.add(NativeTableContext::new(txn_hash, resolver)); + extensions.add(NativeRistrettoPointContext::new()); + extensions.add(AlgebraContext::new()); + extensions.add(NativeAggregatorContext::new( + txn_hash, + resolver, + move_vm.vm_config().delayed_field_optimization_enabled, + resolver, + )); + extensions.add(RandomnessContext::new()); + extensions.add(NativeTransactionContext::new( + txn_hash.to_vec(), + session_id.into_script_hash(), + chain_id.id(), + maybe_user_transaction_context, + )); + 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. + move_vm.flush_loader_cache_if_invalidated(); + + let is_storage_slot_metadata_enabled = features.is_storage_slot_metadata_enabled(); Self { - inner, - remote, + inner: move_vm.new_session_with_extensions(resolver, extensions), + resolver, is_storage_slot_metadata_enabled, } } @@ -94,7 +143,7 @@ impl<'r, 'l> SessionExt<'r, 'l> { .finish_with_extensions_with_custom_effects(&resource_converter)?; let (change_set, resource_group_change_set) = - Self::split_and_merge_resource_groups(move_vm, self.remote, change_set) + Self::split_and_merge_resource_groups(move_vm, self.resolver, change_set) .map_err(|e| e.finish(Location::Undefined))?; let table_context: NativeTableContext = extensions.remove(); @@ -110,7 +159,7 @@ impl<'r, 'l> SessionExt<'r, 'l> { let event_context: NativeEventContext = extensions.remove(); let events = event_context.into_events(); - let woc = WriteOpConverter::new(self.remote, self.is_storage_slot_metadata_enabled); + let woc = WriteOpConverter::new(self.resolver, self.is_storage_slot_metadata_enabled); let change_set = Self::convert_change_set( &woc, @@ -206,7 +255,7 @@ impl<'r, 'l> SessionExt<'r, 'l> { /// merging them into the a single op corresponding to the whole resource group (V0). fn split_and_merge_resource_groups( runtime: &MoveVM, - remote: &dyn AptosMoveResolver, + resolver: &dyn AptosMoveResolver, change_set: ChangeSet, ) -> PartialVMResult<(ChangeSet, ResourceGroupChangeSet)> { // The use of this implies that we could theoretically call unwrap with no consequences, @@ -217,7 +266,7 @@ impl<'r, 'l> SessionExt<'r, 'l> { }; let mut change_set_filtered = ChangeSet::new(); - let mut maybe_resource_group_cache = remote.release_resource_group_cache().map(|v| { + let mut maybe_resource_group_cache = resolver.release_resource_group_cache().map(|v| { v.into_iter() .map(|(k, v)| (k, v.into_iter().collect::>())) .collect::>() @@ -282,7 +331,8 @@ impl<'r, 'l> SessionExt<'r, 'l> { // Maintain the behavior of failing the transaction on resource // group member existence invariants. for (struct_tag, current_op) in resources.iter() { - let exists = remote.resource_exists_in_group(&state_key, struct_tag)?; + let exists = + resolver.resource_exists_in_group(&state_key, struct_tag)?; if matches!(current_op, MoveStorageOp::New(_)) == exists { // Deletion and Modification require resource to exist, // while creation requires the resource to not exist. 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 b766c729e2279..6566d980006c4 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 @@ -84,11 +84,6 @@ impl<'r> TDelayedFieldView for ExecutorViewWithChangeSet<'r> { type ResourceGroupTag = StructTag; type ResourceKey = StateKey; - fn is_delayed_field_optimization_capable(&self) -> bool { - self.base_executor_view - .is_delayed_field_optimization_capable() - } - fn get_delayed_field_value( &self, id: &Self::Identifier, 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 034af2b99101e..2a68662478123 100644 --- a/aptos-move/aptos-vm/src/move_vm_ext/vm.rs +++ b/aptos-move/aptos-vm/src/move_vm_ext/vm.rs @@ -2,60 +2,120 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - aptos_vm::{aptos_default_ty_builder, aptos_prod_ty_builder}, move_vm_ext::{warm_vm_cache::WarmVmCache, AptosMoveResolver, SessionExt, SessionId}, + natives::aptos_natives_with_builder, }; -use aptos_framework::natives::{ - aggregator_natives::NativeAggregatorContext, - code::NativeCodeContext, - cryptography::{algebra::AlgebraContext, ristretto255_point::NativeRistrettoPointContext}, - event::NativeEventContext, - object::NativeObjectContext, - randomness::RandomnessContext, - state_storage::NativeStateStorageContext, - transaction_context::NativeTransactionContext, -}; +use aptos_crypto::HashValue; use aptos_gas_algebra::DynamicExpression; -use aptos_gas_schedule::{AptosGasParameters, MiscGasParameters, NativeGasParameters}; +use aptos_gas_schedule::{ + AptosGasParameters, MiscGasParameters, NativeGasParameters, LATEST_GAS_FEATURE_VERSION, +}; use aptos_native_interface::SafeNativeBuilder; -use aptos_table_natives::NativeTableContext; use aptos_types::{ chain_id::ChainId, - on_chain_config::{Features, TimedFeatures}, + on_chain_config::{FeatureFlag, Features, TimedFeaturesBuilder}, transaction::user_transaction_context::UserTransactionContext, vm::configs::aptos_prod_vm_config, }; -use move_binary_format::errors::VMResult; -use move_vm_runtime::{move_vm::MoveVM, native_extensions::NativeContextExtensions}; -use std::ops::Deref; +use aptos_vm_types::{ + environment::{aptos_default_ty_builder, aptos_prod_ty_builder, Environment}, + storage::change_set_configs::ChangeSetConfigs, +}; +use move_vm_runtime::{config::VMConfig, move_vm::MoveVM}; +use std::{ops::Deref, sync::Arc}; + +/// MoveVM wrapper which is used to run genesis initializations. Designed as a +/// stand-alone struct to ensure all genesis configurations are in one place, +/// and are modified accordingly. The VM is initialized with default parameters, +/// and should only be used to run genesis sessions. +pub struct GenesisMoveVM { + vm: MoveVM, + chain_id: ChainId, + features: Features, +} + +impl GenesisMoveVM { + pub fn new(chain_id: ChainId) -> Self { + let features = Features::default(); + let timed_features = TimedFeaturesBuilder::enable_all().build(); + + // Genesis runs sessions, where there is no concept of block execution. + // Hence, delayed fields are not enabled. + let delayed_field_optimization_enabled = false; + let vm_config = aptos_prod_vm_config( + &features, + &timed_features, + delayed_field_optimization_enabled, + aptos_default_ty_builder(&features), + ); + + // All genesis sessions run with unmetered gas meter, and here we set + // the gas parameters for natives as zeros (because they do not matter). + let mut native_builder = SafeNativeBuilder::new( + LATEST_GAS_FEATURE_VERSION, + NativeGasParameters::zeros(), + MiscGasParameters::zeros(), + timed_features.clone(), + features.clone(), + None, + ); + + let vm = MoveVM::new_with_config( + aptos_natives_with_builder(&mut native_builder), + vm_config.clone(), + ); + + Self { + vm, + chain_id, + features, + } + } + + pub fn genesis_change_set_configs(&self) -> ChangeSetConfigs { + // Because genesis sessions are not metered, there are no change set + // (storage) costs as well. + ChangeSetConfigs::unlimited_at_gas_feature_version(LATEST_GAS_FEATURE_VERSION) + } + + pub fn new_genesis_session<'r, R: AptosMoveResolver>( + &self, + resolver: &'r R, + genesis_id: HashValue, + ) -> SessionExt<'r, '_> { + let session_id = SessionId::genesis(genesis_id); + SessionExt::new( + session_id, + &self.vm, + self.chain_id, + &self.features, + None, + resolver, + ) + } +} pub struct MoveVmExt { inner: MoveVM, - chain_id: u8, - features: Features, + pub(crate) env: Arc, } impl MoveVmExt { - fn new_impl( + fn new_impl( gas_feature_version: u64, gas_params: Result<&AptosGasParameters, &String>, - chain_id: u8, - features: Features, - timed_features: TimedFeatures, - gas_hook: Option, + env: Arc, + gas_hook: Option>, resolver: &impl AptosMoveResolver, - aggregator_v2_type_tagging: bool, - ) -> VMResult - where - F: Fn(DynamicExpression) + Send + Sync + 'static, - { + ) -> Self { // TODO(Gas): Right now, we have to use some dummy values for gas parameters if they are not found on-chain. // This only happens in a edge case that is probably related to write set transactions or genesis, // which logically speaking, shouldn't be handled by the VM at all. // We should clean up the logic here once we get that refactored. let (native_gas_params, misc_gas_params, ty_builder) = match gas_params { Ok(gas_params) => { - let ty_builder = aptos_prod_ty_builder(&features, gas_feature_version, gas_params); + let ty_builder = + aptos_prod_ty_builder(env.features(), gas_feature_version, gas_params); ( gas_params.natives.clone(), gas_params.vm.misc.clone(), @@ -63,7 +123,7 @@ impl MoveVmExt { ) }, Err(_) => { - let ty_builder = aptos_default_ty_builder(&features); + let ty_builder = aptos_default_ty_builder(env.features()); ( NativeGasParameters::zeros(), MiscGasParameters::zeros(), @@ -72,126 +132,75 @@ impl MoveVmExt { }, }; - let mut builder = SafeNativeBuilder::new( + let builder = SafeNativeBuilder::new( gas_feature_version, native_gas_params, misc_gas_params, - timed_features.clone(), - features.clone(), + env.timed_features().clone(), + env.features().clone(), + gas_hook, ); - if let Some(hook) = gas_hook { - builder.set_gas_hook(hook); - } - let paranoid_type_checks = crate::AptosVM::get_paranoid_checks(); - let vm_config = aptos_prod_vm_config( - &features, - &timed_features, - aggregator_v2_type_tagging, + // TODO(George): Move gas configs to environment to avoid this clone! + let vm_config = VMConfig { + verifier_config: env.vm_config().verifier_config.clone(), + deserializer_config: env.vm_config().deserializer_config.clone(), + paranoid_type_checks: env.vm_config().paranoid_type_checks, + check_invariant_in_swap_loc: env.vm_config().check_invariant_in_swap_loc, + max_value_nest_depth: env.vm_config().max_value_nest_depth, + type_max_cost: env.vm_config().type_max_cost, + type_base_cost: env.vm_config().type_base_cost, + type_byte_cost: env.vm_config().type_byte_cost, + delayed_field_optimization_enabled: env.vm_config().delayed_field_optimization_enabled, ty_builder, - paranoid_type_checks, - ); + }; - Ok(Self { - inner: WarmVmCache::get_warm_vm(builder, vm_config, resolver)?, - chain_id, - features, - }) + Self { + inner: WarmVmCache::get_warm_vm( + builder, + vm_config, + resolver, + env.features().is_enabled(FeatureFlag::VM_BINARY_FORMAT_V7), + ) + .expect("should be able to create Move VM; check if there are duplicated natives"), + env, + } } pub fn new( gas_feature_version: u64, gas_params: Result<&AptosGasParameters, &String>, - chain_id: u8, - features: Features, - timed_features: TimedFeatures, + env: Arc, resolver: &impl AptosMoveResolver, - aggregator_v2_type_tagging: bool, - ) -> VMResult { - Self::new_impl::( - gas_feature_version, - gas_params, - chain_id, - features, - timed_features, - None, - resolver, - aggregator_v2_type_tagging, - ) + ) -> Self { + Self::new_impl(gas_feature_version, gas_params, env, None, resolver) } - pub fn new_with_gas_hook( + pub fn new_with_gas_hook( gas_feature_version: u64, gas_params: Result<&AptosGasParameters, &String>, - chain_id: u8, - features: Features, - timed_features: TimedFeatures, - gas_hook: Option, + env: Arc, + gas_hook: Option>, resolver: &impl AptosMoveResolver, - aggregator_v2_type_tagging: bool, - ) -> VMResult - where - F: Fn(DynamicExpression) + Send + Sync + 'static, - { - Self::new_impl( - gas_feature_version, - gas_params, - chain_id, - features, - timed_features, - gas_hook, - resolver, - aggregator_v2_type_tagging, - ) + ) -> Self { + Self::new_impl(gas_feature_version, gas_params, env, gas_hook, resolver) } - pub fn new_session<'r, S: AptosMoveResolver>( + pub fn new_session<'r, R: AptosMoveResolver>( &self, - resolver: &'r S, + resolver: &'r R, session_id: SessionId, - user_transaction_context_opt: Option, + maybe_user_transaction_context: Option, ) -> SessionExt<'r, '_> { - let mut extensions = NativeContextExtensions::default(); - let txn_hash: [u8; 32] = session_id - .as_uuid() - .to_vec() - .try_into() - .expect("HashValue should convert to [u8; 32]"); - - extensions.add(NativeTableContext::new(txn_hash, resolver)); - extensions.add(NativeRistrettoPointContext::new()); - extensions.add(AlgebraContext::new()); - extensions.add(NativeAggregatorContext::new(txn_hash, resolver, resolver)); - extensions.add(RandomnessContext::new()); - extensions.add(NativeTransactionContext::new( - 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. - self.inner.flush_loader_cache_if_invalidated(); - SessionExt::new( - self.inner.new_session_with_extensions(resolver, extensions), + session_id, + &self.inner, + self.env.chain_id(), + self.env.features(), + maybe_user_transaction_context, resolver, - self.features.is_storage_slot_metadata_enabled(), ) } - - pub(crate) fn features(&self) -> &Features { - &self.features - } - - pub fn chain_id(&self) -> ChainId { - ChainId::new(self.chain_id) - } } impl Deref for MoveVmExt { 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 3d6736999849b..d7f58bff2b542 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 @@ -8,10 +8,7 @@ use aptos_framework::natives::code::PackageRegistry; use aptos_infallible::RwLock; use aptos_metrics_core::TimerHelper; use aptos_native_interface::SafeNativeBuilder; -use aptos_types::{ - on_chain_config::{FeatureFlag, Features, OnChainConfig}, - state_store::state_key::StateKey, -}; +use aptos_types::{on_chain_config::OnChainConfig, state_store::state_key::StateKey}; use bytes::Bytes; use move_binary_format::errors::{Location, PartialVMError, VMResult}; use move_core_types::{ @@ -38,8 +35,9 @@ impl WarmVmCache { native_builder: SafeNativeBuilder, vm_config: VMConfig, resolver: &impl AptosMoveResolver, + bin_v7_enabled: bool, ) -> VMResult { - WARM_VM_CACHE.get(native_builder, vm_config, resolver) + WARM_VM_CACHE.get(native_builder, vm_config, resolver, bin_v7_enabled) } fn get( @@ -47,11 +45,12 @@ impl WarmVmCache { mut native_builder: SafeNativeBuilder, vm_config: VMConfig, resolver: &impl AptosMoveResolver, + bin_v7_enabled: bool, ) -> VMResult { let _timer = TIMER.timer_with(&["warm_vm_get"]); let id = { let _timer = TIMER.timer_with(&["get_warm_vm_id"]); - WarmVmId::new(&native_builder, &vm_config, resolver)? + WarmVmId::new(&native_builder, &vm_config, resolver, bin_v7_enabled)? }; if let Some(vm) = self.cache.read().get(&id) { @@ -67,10 +66,8 @@ impl WarmVmCache { return Ok(vm.clone()); } - let vm = MoveVM::new_with_config( - aptos_natives_with_builder(&mut native_builder), - vm_config, - )?; + let vm = + MoveVM::new_with_config(aptos_natives_with_builder(&mut native_builder), vm_config); Self::warm_vm_up(&vm, resolver); // Not using LruCache because its `::get()` requires &mut self @@ -112,6 +109,7 @@ impl WarmVmId { native_builder: &SafeNativeBuilder, vm_config: &VMConfig, resolver: &impl AptosMoveResolver, + bin_v7_enabled: bool, ) -> VMResult { let natives = { let _timer = TIMER.timer_with(&["serialize_native_builder"]); @@ -121,9 +119,7 @@ impl WarmVmId { natives, vm_config: Self::vm_config_bytes(vm_config), core_packages_registry: Self::core_packages_id_bytes(resolver)?, - bin_v7_enabled: Features::fetch_config(resolver) - .unwrap_or_default() - .is_enabled(FeatureFlag::VM_BINARY_FORMAT_V7), + bin_v7_enabled, }) } diff --git a/aptos-move/aptos-vm/src/natives.rs b/aptos-move/aptos-vm/src/natives.rs index 63ec675443b88..b3732c97507ad 100644 --- a/aptos-move/aptos-vm/src/natives.rs +++ b/aptos-move/aptos-vm/src/natives.rs @@ -85,10 +85,6 @@ impl TDelayedFieldView for AptosBlankStorage { type ResourceGroupTag = StructTag; type ResourceKey = StateKey; - fn is_delayed_field_optimization_capable(&self) -> bool { - false - } - fn get_delayed_field_value( &self, _id: &Self::Identifier, @@ -163,6 +159,7 @@ pub fn aptos_natives( misc_gas_params, timed_features, features, + None, ); aptos_natives_with_builder(&mut builder) @@ -237,6 +234,7 @@ fn unit_test_extensions_hook(exts: &mut NativeContextExtensions) { exts.add(NativeAggregatorContext::new( [0; 32], &*DUMMY_RESOLVER, + false, &*DUMMY_RESOLVER, )); exts.add(NativeRistrettoPointContext::new()); diff --git a/aptos-move/block-executor/src/executor.rs b/aptos-move/block-executor/src/executor.rs index 762815dd6fb14..88bb0dd279dcd 100644 --- a/aptos-move/block-executor/src/executor.rs +++ b/aptos-move/block-executor/src/executor.rs @@ -66,7 +66,7 @@ pub struct BlockExecutor { // Number of active concurrent tasks, corresponding to the maximum number of rayon // threads that may be concurrently participating in parallel execution. config: BlockExecutorConfig, - executor_thread_pool: Arc, + executor_thread_pool: Arc, transaction_commit_hook: Option, phantom: PhantomData<(T, E, S, L, X)>, } @@ -107,13 +107,13 @@ where versioned_cache: &MVHashMap, executor: &E, base_view: &S, - latest_view: ParallelState, + parallel_state: ParallelState, ) -> Result> { let _timer = TASK_EXECUTE_SECONDS.start_timer(); let txn = &signature_verified_block[idx_to_execute as usize]; // VM execution. - let sync_view = LatestView::new(base_view, ViewState::Sync(latest_view), idx_to_execute); + let sync_view = LatestView::new(base_view, ViewState::Sync(parallel_state), idx_to_execute); let execute_result = executor.execute_transaction(&sync_view, txn, idx_to_execute); let mut prev_modified_keys = last_input_output @@ -745,7 +745,7 @@ where fn worker_loop( &self, - executor_arguments: &E::Argument, + env: &E::Environment, block: &[T], last_input_output: &TxnLastInputOutput, versioned_cache: &MVHashMap, @@ -759,7 +759,7 @@ where ) -> Result<(), PanicOr> { // Make executor for each task. TODO: fast concurrent executor. let init_timer = VM_INIT_SECONDS.start_timer(); - let executor = E::init(*executor_arguments); + let executor = E::init(env.clone(), base_view); drop(init_timer); let _timer = WORK_WITH_TASK_SECONDS.start_timer(); @@ -860,7 +860,7 @@ where pub(crate) fn execute_transactions_parallel( &self, - executor_initial_arguments: E::Argument, + env: &E::Environment, signature_verified_block: &[T], base_view: &S, ) -> Result, ()> { @@ -883,6 +883,7 @@ where } let num_txns = signature_verified_block.len(); + let concurrency_level = self.config.local.concurrency_level.min(num_txns / 2).max(2); let shared_commit_state = ExplicitSyncWrapper::new(BlockGasLimitProcessor::new( self.config.onchain.block_gas_limit_type.clone(), @@ -905,10 +906,10 @@ where let timer = RAYON_EXECUTION_SECONDS.start_timer(); self.executor_thread_pool.scope(|s| { - for _ in 0..self.config.local.concurrency_level { + for _ in 0..concurrency_level { s.spawn(|_| { if let Err(err) = self.worker_loop( - &executor_initial_arguments, + env, signature_verified_block, &last_input_output, &versioned_cache, @@ -920,7 +921,7 @@ where &final_results, ) { // If there are multiple errors, they all get logged: - // ModulePathReadWriteError and FatalVMErrorvariant is logged at construction, + // ModulePathReadWriteError and FatalVMError variant is logged at construction, // and below we log CodeInvariantErrors. if let PanicOr::CodeInvariantError(err_msg) = err { alert!("[BlockSTM] worker loop: CodeInvariantError({:?})", err_msg); @@ -1032,14 +1033,14 @@ where pub(crate) fn execute_transactions_sequential( &self, - executor_arguments: E::Argument, + env: E::Environment, signature_verified_block: &[T], base_view: &S, resource_group_bcs_fallback: bool, ) -> Result, SequentialBlockExecutionError> { let num_txns = signature_verified_block.len(); let init_timer = VM_INIT_SECONDS.start_timer(); - let executor = E::init(executor_arguments); + let executor = E::init(env, base_view); drop(init_timer); let start_counter = gen_id_start_value(true); @@ -1343,16 +1344,13 @@ where pub fn execute_block( &self, - executor_arguments: E::Argument, + env: E::Environment, signature_verified_block: &[T], base_view: &S, ) -> BlockExecutionResult, E::Error> { if self.config.local.concurrency_level > 1 { - let parallel_result = self.execute_transactions_parallel( - executor_arguments, - signature_verified_block, - base_view, - ); + let parallel_result = + self.execute_transactions_parallel(&env, signature_verified_block, base_view); // If parallel gave us result, return it if let Ok(output) = parallel_result { @@ -1370,9 +1368,9 @@ where info!("parallel execution requiring fallback"); } - // If we didn't run parallel or it didn't finish successfully - run sequential + // If we didn't run parallel, or it didn't finish successfully - run sequential let sequential_result = self.execute_transactions_sequential( - executor_arguments, + env.clone(), signature_verified_block, base_view, false, @@ -1395,7 +1393,7 @@ where init_speculative_logs(signature_verified_block.len()); let sequential_result = self.execute_transactions_sequential( - executor_arguments, + env, signature_verified_block, base_view, true, diff --git a/aptos-move/block-executor/src/executor_utilities.rs b/aptos-move/block-executor/src/executor_utilities.rs index b5939c01aa505..82274f741c76b 100644 --- a/aptos-move/block-executor/src/executor_utilities.rs +++ b/aptos-move/block-executor/src/executor_utilities.rs @@ -169,7 +169,7 @@ pub(crate) fn map_id_to_values_in_group_writes< >( finalized_groups: Vec<(T::Key, T::Value, Vec<(T::Tag, ValueWithLayout)>)>, latest_view: &LatestView, -) -> ::std::result::Result)>)>, PanicError> { +) -> Result)>)>, PanicError> { let mut patched_finalized_groups = Vec::with_capacity(finalized_groups.len()); for (group_key, group_metadata_op, resource_vec) in finalized_groups.into_iter() { let mut patched_resource_vec = Vec::with_capacity(resource_vec.len()); diff --git a/aptos-move/block-executor/src/proptest_types/bencher.rs b/aptos-move/block-executor/src/proptest_types/bencher.rs index c3904b76b5d6b..4a3550f31afe4 100644 --- a/aptos-move/block-executor/src/proptest_types/bencher.rs +++ b/aptos-move/block-executor/src/proptest_types/bencher.rs @@ -136,7 +136,7 @@ where NoOpTransactionCommitHook, E>, usize>, ExecutableTestType, >::new(config, executor_thread_pool, None) - .execute_transactions_parallel((), &self.transactions, &data_view); + .execute_transactions_parallel(&(), &self.transactions, &data_view); self.baseline_output.assert_parallel_output(&output); } diff --git a/aptos-move/block-executor/src/proptest_types/tests.rs b/aptos-move/block-executor/src/proptest_types/tests.rs index 259ab3c337c8c..85a6f65d4cc3f 100644 --- a/aptos-move/block-executor/src/proptest_types/tests.rs +++ b/aptos-move/block-executor/src/proptest_types/tests.rs @@ -82,7 +82,7 @@ fn run_transactions( executor_thread_pool.clone(), None, ) - .execute_transactions_parallel((), &transactions, &data_view); + .execute_transactions_parallel(&(), &transactions, &data_view); if module_access.0 && module_access.1 { assert_matches!(output, Err(())); @@ -217,7 +217,7 @@ fn deltas_writes_mixed_with_block_gas_limit(num_txns: usize, maybe_block_gas_lim executor_thread_pool.clone(), None, ) - .execute_transactions_parallel((), &transactions, &data_view); + .execute_transactions_parallel(&(), &transactions, &data_view); BaselineOutput::generate(&transactions, maybe_block_gas_limit) .assert_parallel_output(&output); @@ -268,7 +268,7 @@ fn deltas_resolver_with_block_gas_limit(num_txns: usize, maybe_block_gas_limit: executor_thread_pool.clone(), None, ) - .execute_transactions_parallel((), &transactions, &data_view); + .execute_transactions_parallel(&(), &transactions, &data_view); BaselineOutput::generate(&transactions, maybe_block_gas_limit) .assert_parallel_output(&output); @@ -424,7 +424,7 @@ fn publishing_fixed_params_with_block_gas_limit( executor_thread_pool, None, ) - .execute_transactions_parallel((), &transactions, &data_view); + .execute_transactions_parallel(&(), &transactions, &data_view); assert_ok!(output); // Adjust the reads of txn indices[2] to contain module read to key 42. @@ -469,7 +469,7 @@ fn publishing_fixed_params_with_block_gas_limit( executor_thread_pool.clone(), None, ) // Ensure enough gas limit to commit the module txns (4 is maximum gas per txn) - .execute_transactions_parallel((), &transactions, &data_view); + .execute_transactions_parallel(&(), &transactions, &data_view); assert_matches!(output, Err(())); } @@ -548,7 +548,7 @@ fn non_empty_group( executor_thread_pool.clone(), None, ) - .execute_transactions_parallel((), &transactions, &data_view); + .execute_transactions_parallel(&(), &transactions, &data_view); BaselineOutput::generate(&transactions, None).assert_parallel_output(&output); } diff --git a/aptos-move/block-executor/src/proptest_types/types.rs b/aptos-move/block-executor/src/proptest_types/types.rs index d4161e17cdbe8..2e2fed2badd4e 100644 --- a/aptos-move/block-executor/src/proptest_types/types.rs +++ b/aptos-move/block-executor/src/proptest_types/types.rs @@ -860,12 +860,12 @@ where K: PartialOrd + Ord + Send + Sync + Clone + Hash + Eq + ModulePath + Debug + 'static, E: Send + Sync + Debug + Clone + TransactionEvent + 'static, { - type Argument = (); + type Environment = (); type Error = usize; type Output = MockOutput; type Txn = MockTransaction; - fn init(_argument: Self::Argument) -> Self { + fn init(_env: Self::Environment, _state_view: &impl TStateView) -> Self { Self::new() } diff --git a/aptos-move/block-executor/src/task.rs b/aptos-move/block-executor/src/task.rs index 2653da650728d..350b566175924 100644 --- a/aptos-move/block-executor/src/task.rs +++ b/aptos-move/block-executor/src/task.rs @@ -8,9 +8,11 @@ use aptos_aggregator::{ }; use aptos_mvhashmap::types::TxnIndex; use aptos_types::{ - delayed_fields::PanicError, fee_statement::FeeStatement, - state_store::state_value::StateValueMetadata, - transaction::BlockExecutableTransaction as Transaction, write_set::WriteOp, + delayed_fields::PanicError, + fee_statement::FeeStatement, + state_store::{state_value::StateValueMetadata, TStateView}, + transaction::BlockExecutableTransaction as Transaction, + write_set::WriteOp, }; use aptos_vm_types::resolver::{TExecutorView, TResourceGroupView}; use move_core_types::{value::MoveTypeLayout, vm_status::StatusCode}; @@ -57,12 +59,15 @@ pub trait ExecutorTask: Sync { /// Type of error when the executor failed to process a transaction and needs to abort. type Error: Debug + Clone + Send + Sync + Eq + 'static; - /// Type to initialize the single thread transaction executor. Copy and Sync are required because + /// Type to initialize the single thread transaction executor. Clone and Sync are required because /// we will create an instance of executor on each individual thread. - type Argument: Sync + Copy; + type Environment: Sync + Clone; /// Create an instance of the transaction executor. - fn init(args: Self::Argument) -> Self; + fn init( + env: Self::Environment, + state_view: &impl TStateView::Key>, + ) -> Self; /// Execute a single transaction given the view of the current state. fn execute_transaction( diff --git a/aptos-move/block-executor/src/unit_tests/mod.rs b/aptos-move/block-executor/src/unit_tests/mod.rs index 25c12e6abef4e..82472dd15aad5 100644 --- a/aptos-move/block-executor/src/unit_tests/mod.rs +++ b/aptos-move/block-executor/src/unit_tests/mod.rs @@ -98,7 +98,7 @@ fn resource_group_bcs_fallback() { ); // Execute the block normally. - let output = block_executor.execute_transactions_parallel((), &transactions, &data_view); + let output = block_executor.execute_transactions_parallel(&(), &transactions, &data_view); match output { Ok(block_output) => { let txn_outputs = block_output.into_transaction_outputs_forced(); @@ -116,7 +116,7 @@ fn resource_group_bcs_fallback() { fail::cfg("fail-point-resource-group-serialization", "return()").unwrap(); assert!(!fail::list().is_empty()); - let par_output = block_executor.execute_transactions_parallel((), &transactions, &data_view); + let par_output = block_executor.execute_transactions_parallel(&(), &transactions, &data_view); assert_matches!(par_output, Err(())); let seq_output = @@ -196,7 +196,7 @@ fn block_output_err_precedence() { assert!(!fail::list().is_empty()); // Pause the thread that processes the aborting txn1, so txn2 can halt the scheduler first. // Confirm that the fatal VM error is still detected and sequential fallback triggered. - let output = block_executor.execute_transactions_parallel((), &transactions, &data_view); + let output = block_executor.execute_transactions_parallel(&(), &transactions, &data_view); assert_matches!(output, Err(())); scenario.teardown(); } @@ -229,7 +229,7 @@ fn skip_rest_gas_limit() { ); // Should hit block limit on the skip transaction. - let _ = block_executor.execute_transactions_parallel((), &transactions, &data_view); + let _ = block_executor.execute_transactions_parallel(&(), &transactions, &data_view); } // TODO: add unit test for block gas limit! @@ -260,7 +260,7 @@ where executor_thread_pool, None, ) - .execute_transactions_parallel((), &transactions, &data_view); + .execute_transactions_parallel(&(), &transactions, &data_view); let baseline = BaselineOutput::generate(&transactions, None); baseline.assert_parallel_output(&output); diff --git a/aptos-move/block-executor/src/view.rs b/aptos-move/block-executor/src/view.rs index 2e13168ec6ddb..f72a408749488 100644 --- a/aptos-move/block-executor/src/view.rs +++ b/aptos-move/block-executor/src/view.rs @@ -1301,15 +1301,6 @@ impl<'a, T: Transaction, S: TStateView, X: Executable> LatestView< state_key, ); - let layout = if self.is_delayed_field_optimization_capable() { - layout - } else { - match layout { - UnknownOrLayout::Known(_) => UnknownOrLayout::Known(None), - UnknownOrLayout::Unknown => UnknownOrLayout::Unknown, - } - }; - let state = self.latest_view.get_resource_state(); let mut ret = state.read_cached_data_by_kind( @@ -1472,8 +1463,6 @@ impl<'a, T: Transaction, S: TStateView, X: Executable> TResourceGr resource_tag: &Self::ResourceTag, maybe_layout: Option<&Self::Layout>, ) -> PartialVMResult> { - let maybe_layout = maybe_layout.filter(|_| self.is_delayed_field_optimization_capable()); - let mut group_read = self .latest_view .get_resource_group_state() @@ -1613,13 +1602,6 @@ impl<'a, T: Transaction, S: TStateView, X: Executable> TDelayedFie type ResourceGroupTag = T::Tag; type ResourceKey = T::Key; - fn is_delayed_field_optimization_capable(&self) -> bool { - match &self.latest_view { - ViewState::Sync(_) => true, - ViewState::Unsync(_) => true, - } - } - fn get_delayed_field_value( &self, id: &Self::Identifier, diff --git a/aptos-move/e2e-move-tests/src/harness.rs b/aptos-move/e2e-move-tests/src/harness.rs index 84d693e95c7ff..e0703cdb252ad 100644 --- a/aptos-move/e2e-move-tests/src/harness.rs +++ b/aptos-move/e2e-move-tests/src/harness.rs @@ -32,7 +32,6 @@ use aptos_types::{ ViewFunctionOutput, }, }; -use aptos_vm::{data_cache::AsMoveResolver, AptosVM}; use claims::assert_ok; use move_core_types::{ language_storage::{StructTag, TypeTag}, @@ -920,13 +919,6 @@ impl MoveHarness { .unwrap() } - pub fn new_vm(&self) -> AptosVM { - AptosVM::new( - &self.executor.data_store().as_move_resolver(), - /*override_is_delayed_field_optimization_capable=*/ None, - ) - } - pub fn set_default_gas_unit_price(&mut self, gas_unit_price: u64) { self.default_gas_unit_price = gas_unit_price; } 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..b4917624d5a61 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 @@ -22,7 +22,7 @@ use move_core_types::{identifier::Identifier, vm_status::StatusCode}; fn access_path_panic() { // github.com/aptos-labs/aptos-core/security/advisories/GHSA-rpw2-84hq-48jj let mut ty = SignatureToken::Bool; - for _ in 0..20 { + for _ in 0..18 { ty = SignatureToken::StructInstantiation(StructHandleIndex(0), vec![ty]); } diff --git a/aptos-move/e2e-move-tests/src/tests/gas.rs b/aptos-move/e2e-move-tests/src/tests/gas.rs index da5fc2a5941ff..6a9f1b34c9ad2 100644 --- a/aptos-move/e2e-move-tests/src/tests/gas.rs +++ b/aptos-move/e2e-move-tests/src/tests/gas.rs @@ -18,8 +18,8 @@ use aptos_types::{ account_address::{default_stake_pool_address, AccountAddress}, account_config::CORE_CODE_ADDRESS, transaction::{EntryFunction, TransactionPayload}, + vm::configs::set_paranoid_type_checks, }; -use aptos_vm::AptosVM; use move_core_types::{identifier::Identifier, language_storage::ModuleId}; use sha3::{Digest, Sha3_512}; use std::path::Path; @@ -111,7 +111,7 @@ fn test_gas() { } }; - AptosVM::set_paranoid_type_checks(true); + set_paranoid_type_checks(true); run( &mut harness, diff --git a/aptos-move/e2e-move-tests/src/tests/storage_refund.rs b/aptos-move/e2e-move-tests/src/tests/storage_refund.rs index c0925645e88ea..ff510308a8b6b 100644 --- a/aptos-move/e2e-move-tests/src/tests/storage_refund.rs +++ b/aptos-move/e2e-move-tests/src/tests/storage_refund.rs @@ -97,9 +97,8 @@ const LEEWAY: u64 = 2000; fn read_slot_fee_from_gas_schedule(h: &MoveHarness) -> u64 { let slot_fee = h - .new_vm() - .gas_params() - .unwrap() + .get_gas_params() + .1 .vm .txn .storage_fee_per_state_slot diff --git a/aptos-move/e2e-move-tests/src/tests/vm.rs b/aptos-move/e2e-move-tests/src/tests/vm.rs index 7dafd13a3cd71..5ba1cb339b599 100644 --- a/aptos-move/e2e-move-tests/src/tests/vm.rs +++ b/aptos-move/e2e-move-tests/src/tests/vm.rs @@ -6,7 +6,7 @@ use aptos_cached_packages::aptos_stdlib::aptos_account_transfer; use aptos_types::{ state_store::state_key::StateKey, transaction::ExecutionStatus, write_set::WriteOp, }; -use aptos_vm::{data_cache::AsMoveResolver, AptosVM}; +use aptos_vm::AptosVM; use claims::{assert_ok_eq, assert_some}; use move_core_types::vm_status::{StatusCode, VMStatus}; use test_case::test_case; @@ -28,10 +28,7 @@ fn failed_transaction_cleanup_charges_gas(status_code: StatusCode) { .sign(); let state_view = h.executor.get_state_view(); - let vm = AptosVM::new( - &state_view.as_move_resolver(), - /*override_is_delayed_field_optimization_capable=*/ Some(false), - ); + let vm = AptosVM::new(state_view); let balance = 10_000; let output = vm diff --git a/aptos-move/e2e-tests/src/executor.rs b/aptos-move/e2e-tests/src/executor.rs index 45294c4d442dd..ece654e35b19f 100644 --- a/aptos-move/e2e-tests/src/executor.rs +++ b/aptos-move/e2e-tests/src/executor.rs @@ -34,10 +34,7 @@ use aptos_types::{ chain_id::ChainId, contract_event::ContractEvent, move_utils::MemberId, - on_chain_config::{ - AptosVersion, FeatureFlag, Features, OnChainConfig, TimedFeatureOverride, - TimedFeaturesBuilder, ValidatorSet, - }, + on_chain_config::{AptosVersion, FeatureFlag, Features, OnChainConfig, ValidatorSet}, state_store::{state_key::StateKey, state_value::StateValue, StateView, TStateView}, transaction::{ signature_verified_transaction::{ @@ -59,7 +56,10 @@ use aptos_vm::{ }; use aptos_vm_genesis::{generate_genesis_change_set_for_testing_with_count, GenesisOptions}; use aptos_vm_logging::log_schema::AdapterLogSchema; -use aptos_vm_types::storage::{change_set_configs::ChangeSetConfigs, StorageGasParameters}; +use aptos_vm_types::{ + environment::Environment, + storage::{change_set_configs::ChangeSetConfigs, StorageGasParameters}, +}; use bytes::Bytes; use move_core_types::{ account_address::AccountAddress, @@ -69,8 +69,6 @@ use move_core_types::{ }; use move_vm_runtime::module_traversal::{TraversalContext, TraversalStorage}; use move_vm_types::gas::UnmeteredGasMeter; -#[cfg(any(test, feature = "fuzzing"))] -use rayon::ThreadPool; use serde::Serialize; use std::{ collections::BTreeSet, @@ -123,13 +121,11 @@ pub struct FakeExecutor { executed_output: Option, trace_dir: Option, rng: KeyGen, - /// If set, determines whether or not to execute a comparison test with the parallel - /// block executor. + /// If set, determines whether to execute a comparison test with the parallel block executor. /// If not set, environment variable E2E_PARALLEL_EXEC must be set /// s.t. the comparison test is executed (BothComparison). executor_mode: Option, - features: Features, - chain_id: u8, + env: Arc, allow_block_executor_fallback: bool, } @@ -162,8 +158,7 @@ impl FakeExecutor { trace_dir: None, rng: KeyGen::from_seed(RNG_SEED), executor_mode: None, - features: Features::default(), - chain_id: chain_id.id(), + env: Environment::testing(chain_id), allow_block_executor_fallback: true, }; executor.apply_write_set(write_set); @@ -174,7 +169,7 @@ impl FakeExecutor { pub fn from_genesis_with_existing_thread_pool( write_set: &WriteSet, chain_id: ChainId, - executor_thread_pool: Arc, + executor_thread_pool: Arc, ) -> Self { let mut executor = FakeExecutor { data_store: FakeDataStore::default(), @@ -185,8 +180,7 @@ impl FakeExecutor { trace_dir: None, rng: KeyGen::from_seed(RNG_SEED), executor_mode: None, - features: Features::default(), - chain_id: chain_id.id(), + env: Environment::testing(chain_id), allow_block_executor_fallback: true, }; executor.apply_write_set(write_set); @@ -269,8 +263,7 @@ impl FakeExecutor { trace_dir: None, rng: KeyGen::from_seed(RNG_SEED), executor_mode: None, - features: Features::default(), - chain_id: ChainId::test().id(), + env: Environment::testing(ChainId::test()), allow_block_executor_fallback: true, } } @@ -681,11 +674,9 @@ impl FakeExecutor { let log_context = AdapterLogSchema::new(self.data_store.id(), 0); // TODO(Gas): revisit this. - let resolver = self.data_store.as_move_resolver(); - let vm = AptosVM::new( - &resolver, /*override_is_delayed_field_optimization_capable=*/ None, - ); + let vm = AptosVM::new(self.get_state_view()); + let resolver = self.data_store.as_move_resolver(); let (_status, output, gas_profiler) = vm.execute_user_transaction_with_modified_gas_meter( &resolver, &txn, @@ -752,10 +743,7 @@ impl FakeExecutor { /// Verifies the given transaction by running it through the VM verifier. pub fn validate_transaction(&self, txn: SignedTransaction) -> VMValidatorResult { - let vm = AptosVM::new( - &self.get_state_view().as_move_resolver(), - /*override_is_delayed_field_optimization_capable=*/ None, - ); + let vm = AptosVM::new(self.get_state_view()); vm.validate_transaction(txn, &self.data_store) } @@ -861,11 +849,6 @@ impl FakeExecutor { dynamic_args: ExecFuncTimerDynamicArgs, gas_meter_type: GasMeterType, ) -> u128 { - // FIXME: should probably read the timestamp from storage. - let timed_features = TimedFeaturesBuilder::enable_all() - .with_override_profile(TimedFeatureOverride::Testing) - .build(); - let mut extra_accounts = match &dynamic_args { ExecFuncTimerDynamicArgs::DistinctSigners | ExecFuncTimerDynamicArgs::DistinctSignersAndFixed(_) => (0..iterations) @@ -882,7 +865,8 @@ impl FakeExecutor { StorageGasParameters::latest(), ), GasMeterType::UnmeteredGasMeter => ( - AptosGasParameters::zeros(), + // In case of unmetered execution, we still want to enforce limits. + AptosGasParameters::initial(), StorageGasParameters::unlimited(), ), }; @@ -890,13 +874,9 @@ impl FakeExecutor { let vm = MoveVmExt::new( LATEST_GAS_FEATURE_VERSION, Ok(&gas_params), - self.chain_id, - self.features.clone(), - timed_features, + self.env.clone(), &resolver, - false, - ) - .unwrap(); + ); // start measuring here to reduce measurement errors (i.e., the time taken to load vm, module, etc.) let mut i = 0; @@ -995,27 +975,18 @@ impl FakeExecutor { let a2 = Arc::clone(&a1); let (write_set, _events) = { - // FIXME: should probably read the timestamp from storage. - let timed_features = TimedFeaturesBuilder::enable_all() - .with_override_profile(TimedFeatureOverride::Testing) - .build(); - let resolver = self.data_store.as_move_resolver(); // TODO(Gas): we probably want to switch to non-zero costs in the future let vm = MoveVmExt::new_with_gas_hook( LATEST_GAS_FEATURE_VERSION, Ok(&AptosGasParameters::zeros()), - self.chain_id, - self.features.clone(), - timed_features, - Some(move |expression| { + self.env.clone(), + Some(Arc::new(move |expression| { a2.lock().unwrap().push(expression); - }), + })), &resolver, - /*aggregator_v2_type_tagging=*/ false, - ) - .unwrap(); + ); let mut session = vm.new_session(&resolver, SessionId::void(), None); let fun_name = Self::name(function_name); @@ -1036,7 +1007,6 @@ impl FakeExecutor { false, 10000000000000, ), - // coeff_buffer: BTreeMap::new(), shared_buffer: Arc::clone(&a1), }), &mut TraversalContext::new(&storage), @@ -1074,24 +1044,14 @@ impl FakeExecutor { args: Vec>, ) { let (write_set, events) = { - // FIXME: should probably read the timestamp from storage. - let timed_features = TimedFeaturesBuilder::enable_all() - .with_override_profile(TimedFeatureOverride::Testing) - .build(); - let resolver = self.data_store.as_move_resolver(); - // TODO(Gas): we probably want to switch to non-zero costs in the future let vm = MoveVmExt::new( LATEST_GAS_FEATURE_VERSION, - Ok(&AptosGasParameters::zeros()), - self.chain_id, - self.features.clone(), - timed_features, + Ok(&AptosGasParameters::initial()), + self.env.clone(), &resolver, - false, - ) - .unwrap(); + ); let mut session = vm.new_session(&resolver, SessionId::void(), None); let storage = TraversalStorage::new(); session @@ -1100,6 +1060,7 @@ impl FakeExecutor { &Self::name(function_name), type_params, args, + // TODO(Gas): we probably want to switch to metered execution in the future &mut UnmeteredGasMeter, &mut TraversalContext::new(&storage), ) @@ -1145,20 +1106,19 @@ impl FakeExecutor { let (gas_params, storage_gas_params, gas_feature_version) = get_gas_parameters(&features, state_view); - let timed_features = TimedFeaturesBuilder::enable_all() - .with_override_profile(TimedFeatureOverride::Testing) - .build(); - let struct_constructors = features.is_enabled(FeatureFlag::STRUCT_CONSTRUCTORS); + let are_struct_constructors_enabled = features.is_enabled(FeatureFlag::STRUCT_CONSTRUCTORS); + let env = self + .env + .as_ref() + .clone() + .with_features_for_testing(features); + let vm = MoveVmExt::new( LATEST_GAS_FEATURE_VERSION, gas_params.as_ref(), - self.chain_id, - features, - timed_features, + env, state_view, - false, - ) - .unwrap(); + ); let mut session = vm.new_session(state_view, SessionId::void(), None); let func = @@ -1168,7 +1128,7 @@ impl FakeExecutor { senders, entry_fn.args().to_vec(), &func, - struct_constructors, + are_struct_constructors_enabled, )?; let mut gas_meter = make_prod_gas_meter( @@ -1210,19 +1170,12 @@ impl FakeExecutor { args: Vec>, ) -> Result<(WriteSet, Vec), VMStatus> { let resolver = self.data_store.as_move_resolver(); - - // TODO(Gas): we probably want to switch to non-zero costs in the future let vm = MoveVmExt::new( LATEST_GAS_FEATURE_VERSION, - Ok(&AptosGasParameters::zeros()), - self.chain_id, - self.features.clone(), - // FIXME: should probably read the timestamp from storage. - TimedFeaturesBuilder::enable_all().build(), + Ok(&AptosGasParameters::initial()), + self.env.clone(), &resolver, - false, - ) - .unwrap(); + ); let mut session = vm.new_session(&resolver, SessionId::void(), None); let storage = TraversalStorage::new(); session @@ -1231,6 +1184,7 @@ impl FakeExecutor { &Self::name(function_name), type_params, args, + // TODO(Gas): we probably want to switch to metered execution in the future &mut UnmeteredGasMeter, &mut TraversalContext::new(&storage), ) @@ -1255,14 +1209,14 @@ impl FakeExecutor { type_args: Vec, arguments: Vec>, ) -> ViewFunctionOutput { - // No gas limit + let max_gas_amount = u64::MAX; AptosVM::execute_view_function( self.get_state_view(), fun.module_id, fun.member_id, type_args, arguments, - u64::MAX, + max_gas_amount, ) } } diff --git a/aptos-move/framework/aptos-framework/doc/fungible_asset.md b/aptos-move/framework/aptos-framework/doc/fungible_asset.md index b3e4e9c3c1861..25a863d8482c9 100644 --- a/aptos-move/framework/aptos-framework/doc/fungible_asset.md +++ b/aptos-move/framework/aptos-framework/doc/fungible_asset.md @@ -18,6 +18,7 @@ metadata object can be any object that equipped with 0x1::object::ObjectGroup])] -struct Metadata has key +struct Metadata has copy, drop, key @@ -478,6 +483,34 @@ BurnRef can be used to burn fungible assets from a given holder account. +
+Fields + + +
+
+metadata: object::Object<fungible_asset::Metadata> +
+
+ +
+
+ + +
+ + + +## Struct `MutateMetadataRef` + +MutateMetadataRef can be used to directly modify the fungible asset's Metadata. + + +
struct MutateMetadataRef has drop, store
+
+ + +
Fields @@ -1491,6 +1524,34 @@ This can only be called at object creation time as constructor_ref is only avail +
+ + + +## Function `generate_mutate_metadata_ref` + +Creates a mutate metadata ref that can be used to change the metadata information of 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_mutate_metadata_ref(constructor_ref: &object::ConstructorRef): fungible_asset::MutateMetadataRef
+
+ + + +
+Implementation + + +
public fun generate_mutate_metadata_ref(constructor_ref: &ConstructorRef): MutateMetadataRef {
+    let metadata = object::object_from_constructor_ref<Metadata>(constructor_ref);
+    MutateMetadataRef { metadata }
+}
+
+ + +
@@ -1697,6 +1758,32 @@ Get the project uri from the metadata object. + + + + +## Function `metadata` + +Get the metadata struct from the metadata object. + + +
#[view]
+public fun metadata<T: key>(metadata: object::Object<T>): fungible_asset::Metadata
+
+ + + +
+Implementation + + +
public fun metadata<T: key>(metadata: Object<T>): Metadata acquires Metadata {
+    *borrow_fungible_metadata(&metadata)
+}
+
+ + +
@@ -2255,6 +2342,31 @@ Get the underlying metadata object from the + +## Function `object_from_metadata_ref` + +Get the underlying metadata object from the MutateMetadataRef. + + +
public fun object_from_metadata_ref(ref: &fungible_asset::MutateMetadataRef): object::Object<fungible_asset::Metadata>
+
+ + + +
+Implementation + + +
public fun object_from_metadata_ref(ref: &MutateMetadataRef): Object<Metadata> {
+    ref.metadata
+}
+
+ + +
@@ -2868,6 +2980,55 @@ Transfer amount of the fungible asset with + +## Function `mutate_metadata` + +Mutate specified fields of the fungible asset's Metadata. + + +
public fun mutate_metadata(metadata_ref: &fungible_asset::MutateMetadataRef, name: option::Option<string::String>, symbol: option::Option<string::String>, decimals: option::Option<u8>, icon_uri: option::Option<string::String>, project_uri: option::Option<string::String>)
+
+ + + +
+Implementation + + +
public fun mutate_metadata(
+    metadata_ref: &MutateMetadataRef,
+    name: Option<String>,
+    symbol: Option<String>,
+    decimals: Option<u8>,
+    icon_uri: Option<String>,
+    project_uri: Option<String>,
+) acquires Metadata {
+    let metadata_address = object::object_address(&metadata_ref.metadata);
+    let mutable_metadata = borrow_global_mut<Metadata>(metadata_address);
+
+    if (option::is_some(&name)){
+        mutable_metadata.name = option::extract(&mut name);
+    };
+    if (option::is_some(&symbol)){
+        mutable_metadata.symbol = option::extract(&mut symbol);
+    };
+    if (option::is_some(&decimals)){
+        mutable_metadata.decimals = option::extract(&mut decimals);
+    };
+    if (option::is_some(&icon_uri)){
+        mutable_metadata.icon_uri = option::extract(&mut icon_uri);
+    };
+    if (option::is_some(&project_uri)){
+        mutable_metadata.project_uri = option::extract(&mut project_uri);
+    };
+}
+
+ + +
diff --git a/aptos-move/framework/aptos-framework/sources/fungible_asset.move b/aptos-move/framework/aptos-framework/sources/fungible_asset.move index a629fb29acd1b..1d86762e01e73 100644 --- a/aptos-move/framework/aptos-framework/sources/fungible_asset.move +++ b/aptos-move/framework/aptos-framework/sources/fungible_asset.move @@ -112,7 +112,7 @@ module aptos_framework::fungible_asset { #[resource_group_member(group = aptos_framework::object::ObjectGroup)] /// Metadata of a Fungible asset - struct Metadata has key { + struct Metadata has key, copy, drop { /// Name of the fungible metadata, i.e., "USDT". name: String, /// Symbol of the fungible metadata, usually a shorter version of the name. @@ -182,6 +182,11 @@ module aptos_framework::fungible_asset { metadata: Object } + /// MutateMetadataRef can be used to directly modify the fungible asset's Metadata. + struct MutateMetadataRef has drop, store { + metadata: Object + } + #[event] /// Emitted when fungible assets are deposited into a store. struct Deposit has drop, store { @@ -401,6 +406,14 @@ module aptos_framework::fungible_asset { TransferRef { metadata } } + /// Creates a mutate metadata ref that can be used to change the metadata information of 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_mutate_metadata_ref(constructor_ref: &ConstructorRef): MutateMetadataRef { + let metadata = object::object_from_constructor_ref(constructor_ref); + MutateMetadataRef { metadata } + } + #[view] /// Get the current supply from the `metadata` object. public fun supply(metadata: Object): Option acquires Supply, ConcurrentSupply { @@ -467,6 +480,12 @@ module aptos_framework::fungible_asset { borrow_fungible_metadata(&metadata).project_uri } + #[view] + /// Get the metadata struct from the `metadata` object. + public fun metadata(metadata: Object): Metadata acquires Metadata { + *borrow_fungible_metadata(&metadata) + } + #[view] /// Return whether the provided address has a store initialized. public fun store_exists(store: address): bool { @@ -625,6 +644,11 @@ module aptos_framework::fungible_asset { ref.metadata } + /// Get the underlying metadata object from the `MutateMetadataRef`. + public fun object_from_metadata_ref(ref: &MutateMetadataRef): Object { + ref.metadata + } + /// 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( @@ -858,6 +882,35 @@ module aptos_framework::fungible_asset { deposit_with_ref(transfer_ref, to, fa); } + /// Mutate specified fields of the fungible asset's `Metadata`. + public fun mutate_metadata( + metadata_ref: &MutateMetadataRef, + name: Option, + symbol: Option, + decimals: Option, + icon_uri: Option, + project_uri: Option, + ) acquires Metadata { + let metadata_address = object::object_address(&metadata_ref.metadata); + let mutable_metadata = borrow_global_mut(metadata_address); + + if (option::is_some(&name)){ + mutable_metadata.name = option::extract(&mut name); + }; + if (option::is_some(&symbol)){ + mutable_metadata.symbol = option::extract(&mut symbol); + }; + if (option::is_some(&decimals)){ + mutable_metadata.decimals = option::extract(&mut decimals); + }; + if (option::is_some(&icon_uri)){ + mutable_metadata.icon_uri = option::extract(&mut icon_uri); + }; + if (option::is_some(&project_uri)){ + mutable_metadata.project_uri = option::extract(&mut project_uri); + }; + } + /// Create a fungible asset with zero amount. /// This can be useful when starting a series of computations where the initial value is 0. public fun zero(metadata: Object): FungibleAsset { @@ -1081,7 +1134,7 @@ module aptos_framework::fungible_asset { } #[test_only] - public fun init_test_metadata(constructor_ref: &ConstructorRef): (MintRef, TransferRef, BurnRef) { + public fun init_test_metadata(constructor_ref: &ConstructorRef): (MintRef, TransferRef, BurnRef, MutateMetadataRef) { add_fungibility( constructor_ref, option::some(100) /* max supply */, @@ -1094,16 +1147,17 @@ module aptos_framework::fungible_asset { let mint_ref = generate_mint_ref(constructor_ref); let burn_ref = generate_burn_ref(constructor_ref); let transfer_ref = generate_transfer_ref(constructor_ref); - (mint_ref, transfer_ref, burn_ref) + let mutate_metadata_ref= generate_mutate_metadata_ref(constructor_ref); + (mint_ref, transfer_ref, burn_ref, mutate_metadata_ref) } #[test_only] public fun create_fungible_asset( creator: &signer - ): (MintRef, TransferRef, BurnRef, Object) { + ): (MintRef, TransferRef, BurnRef, MutateMetadataRef, Object) { let (creator_ref, token_object) = create_test_token(creator); - let (mint, transfer, burn) = init_test_metadata(&creator_ref); - (mint, transfer, burn, object::convert(token_object)) + let (mint, transfer, burn, mutate_metadata) = init_test_metadata(&creator_ref); + (mint, transfer, burn, mutate_metadata, object::convert(token_object)) } #[test_only] @@ -1127,10 +1181,18 @@ module aptos_framework::fungible_asset { assert!(icon_uri(metadata) == string::utf8(b"http://www.example.com/favicon.ico"), 6); assert!(project_uri(metadata) == string::utf8(b"http://www.example.com"), 7); + assert!(metadata(metadata) == Metadata { + name: string::utf8(b"TEST"), + symbol: string::utf8(b"@@"), + decimals: 0, + icon_uri: string::utf8(b"http://www.example.com/favicon.ico"), + project_uri: string::utf8(b"http://www.example.com"), + }, 8); + increase_supply(&metadata, 50); - assert!(supply(metadata) == option::some(50), 8); + assert!(supply(metadata) == option::some(50), 9); decrease_supply(&metadata, 30); - assert!(supply(metadata) == option::some(20), 9); + assert!(supply(metadata) == option::some(20), 10); } #[test(creator = @0xcafe)] @@ -1143,7 +1205,7 @@ module aptos_framework::fungible_asset { #[test(creator = @0xcafe)] fun test_create_and_remove_store(creator: &signer) acquires FungibleStore, FungibleAssetEvents, ConcurrentFungibleBalance { - let (_, _, _, metadata) = create_fungible_asset(creator); + let (_, _, _, _, metadata) = create_fungible_asset(creator); let creator_ref = object::create_object_from_account(creator); create_store(&creator_ref, metadata); let delete_ref = object::generate_delete_ref(&creator_ref); @@ -1154,8 +1216,8 @@ module aptos_framework::fungible_asset { fun test_e2e_basic_flow( creator: &signer, aaron: &signer, - ) acquires FungibleStore, Supply, ConcurrentSupply, DispatchFunctionStore, ConcurrentFungibleBalance { - let (mint_ref, transfer_ref, burn_ref, test_token) = create_fungible_asset(creator); + ) acquires FungibleStore, Supply, ConcurrentSupply, DispatchFunctionStore, ConcurrentFungibleBalance, Metadata { + let (mint_ref, transfer_ref, burn_ref, mutate_metadata_ref, test_token) = create_fungible_asset(creator); let metadata = mint_ref.metadata; let creator_store = create_test_store(creator, metadata); let aaron_store = create_test_store(aaron, metadata); @@ -1180,6 +1242,20 @@ module aptos_framework::fungible_asset { set_frozen_flag(&transfer_ref, aaron_store, true); assert!(is_frozen(aaron_store), 7); + // Mutate Metadata + mutate_metadata( + &mutate_metadata_ref, + option::some(string::utf8(b"mutated_name")), + option::some(string::utf8(b"mutated_symbol")), + option::none(), + option::none(), + option::none() + ); + assert!(name(metadata) == string::utf8(b"mutated_name"), 8); + assert!(symbol(metadata) == string::utf8(b"mutated_symbol"), 9); + assert!(decimals(metadata) == 0, 10); + assert!(icon_uri(metadata) == string::utf8(b"http://www.example.com/favicon.ico"), 11); + assert!(project_uri(metadata) == string::utf8(b"http://www.example.com"), 12); } #[test(creator = @0xcafe)] @@ -1187,7 +1263,7 @@ module aptos_framework::fungible_asset { fun test_frozen( creator: &signer ) acquires FungibleStore, Supply, ConcurrentSupply, DispatchFunctionStore, ConcurrentFungibleBalance { - let (mint_ref, transfer_ref, _burn_ref, _) = create_fungible_asset(creator); + let (mint_ref, transfer_ref, _burn_ref, _mutate_metadata_ref, _) = create_fungible_asset(creator); let creator_store = create_test_store(creator, mint_ref.metadata); let fa = mint(&mint_ref, 100); @@ -1200,7 +1276,7 @@ module aptos_framework::fungible_asset { fun test_mint_to_frozen( creator: &signer ) acquires FungibleStore, ConcurrentFungibleBalance, Supply, ConcurrentSupply, DispatchFunctionStore { - let (mint_ref, transfer_ref, _burn_ref, _) = create_fungible_asset(creator); + let (mint_ref, transfer_ref, _burn_ref, _mutate_metadata_ref, _) = create_fungible_asset(creator); let creator_store = create_test_store(creator, mint_ref.metadata); set_frozen_flag(&transfer_ref, creator_store, true); @@ -1213,7 +1289,7 @@ module aptos_framework::fungible_asset { creator: &signer ) { let (creator_ref, _) = create_test_token(creator); - let (mint_ref, _, _) = init_test_metadata(&creator_ref); + let (mint_ref, _, _, _) = init_test_metadata(&creator_ref); set_untransferable(&creator_ref); let creator_store = create_test_store(creator, mint_ref.metadata); @@ -1225,7 +1301,7 @@ module aptos_framework::fungible_asset { creator: &signer, aaron: &signer, ) acquires FungibleStore, Supply, ConcurrentSupply, ConcurrentFungibleBalance { - let (mint_ref, transfer_ref, _burn_ref, _) = create_fungible_asset(creator); + let (mint_ref, transfer_ref, _burn_ref, _mutate_metadata_ref, _) = create_fungible_asset(creator); let metadata = mint_ref.metadata; let creator_store = create_test_store(creator, metadata); let aaron_store = create_test_store(aaron, metadata); @@ -1241,9 +1317,53 @@ module aptos_framework::fungible_asset { assert!(!!is_frozen(aaron_store), 4); } + #[test(creator = @0xcafe)] + fun test_mutate_metadata( + creator: &signer + ) acquires Metadata { + let (mint_ref, _transfer_ref, _burn_ref, mutate_metadata_ref, _) = create_fungible_asset(creator); + let metadata = mint_ref.metadata; + + mutate_metadata( + &mutate_metadata_ref, + option::some(string::utf8(b"mutated_name")), + option::some(string::utf8(b"mutated_symbol")), + option::some(10), + option::some(string::utf8(b"http://www.mutated-example.com/favicon.ico")), + option::some(string::utf8(b"http://www.mutated-example.com")) + ); + assert!(name(metadata) == string::utf8(b"mutated_name"), 1); + assert!(symbol(metadata) == string::utf8(b"mutated_symbol"), 2); + assert!(decimals(metadata) == 10, 3); + assert!(icon_uri(metadata) == string::utf8(b"http://www.mutated-example.com/favicon.ico"), 4); + assert!(project_uri(metadata) == string::utf8(b"http://www.mutated-example.com"), 5); + } + + #[test(creator = @0xcafe)] + fun test_partial_mutate_metadata( + creator: &signer + ) acquires Metadata { + let (mint_ref, _transfer_ref, _burn_ref, mutate_metadata_ref, _) = create_fungible_asset(creator); + let metadata = mint_ref.metadata; + + mutate_metadata( + &mutate_metadata_ref, + option::some(string::utf8(b"mutated_name")), + option::some(string::utf8(b"mutated_symbol")), + option::none(), + option::none(), + option::none() + ); + assert!(name(metadata) == string::utf8(b"mutated_name"), 8); + assert!(symbol(metadata) == string::utf8(b"mutated_symbol"), 9); + assert!(decimals(metadata) == 0, 10); + assert!(icon_uri(metadata) == string::utf8(b"http://www.example.com/favicon.ico"), 11); + assert!(project_uri(metadata) == string::utf8(b"http://www.example.com"), 12); + } + #[test(creator = @0xcafe)] fun test_merge_and_exact(creator: &signer) acquires Supply, ConcurrentSupply { - let (mint_ref, _transfer_ref, burn_ref, _) = create_fungible_asset(creator); + let (mint_ref, _transfer_ref, burn_ref, _mutate_metadata_ref, _) = create_fungible_asset(creator); let fa = mint(&mint_ref, 100); let cash = extract(&mut fa, 80); assert!(fa.amount == 20, 1); @@ -1266,8 +1386,8 @@ module aptos_framework::fungible_asset { #[test(creator = @0xcafe, aaron = @0xface)] #[expected_failure(abort_code = 0x10006, location = Self)] fun test_fungible_asset_mismatch_when_merge(creator: &signer, aaron: &signer) { - let (_, _, _, metadata1) = create_fungible_asset(creator); - let (_, _, _, metadata2) = create_fungible_asset(aaron); + let (_, _, _, _, metadata1) = create_fungible_asset(creator); + let (_, _, _, _, metadata2) = create_fungible_asset(aaron); let base = FungibleAsset { metadata: metadata1, amount: 1, @@ -1292,7 +1412,7 @@ module aptos_framework::fungible_asset { features::change_feature_flags_for_testing(fx, vector[], vector[supply_feature, balance_feature, default_balance_feature]); let (creator_ref, token_object) = create_test_token(creator); - let (mint_ref, transfer_ref, _burn) = init_test_metadata(&creator_ref); + let (mint_ref, transfer_ref, _burn, _mutate_metadata_ref) = init_test_metadata(&creator_ref); let test_token = object::convert(token_object); assert!(exists(object::object_address(&test_token)), 1); assert!(!exists(object::object_address(&test_token)), 2); @@ -1337,7 +1457,7 @@ module aptos_framework::fungible_asset { features::change_feature_flags_for_testing(fx, vector[supply_feature, balance_feature, default_balance_feature], vector[]); let (creator_ref, token_object) = create_test_token(creator); - let (mint_ref, transfer_ref, _burn) = init_test_metadata(&creator_ref); + let (mint_ref, transfer_ref, _burn, _mutate_metadata_ref) = init_test_metadata(&creator_ref); let test_token = object::convert(token_object); assert!(!exists(object::object_address(&test_token)), 1); assert!(exists(object::object_address(&test_token)), 2); diff --git a/aptos-move/framework/aptos-framework/tests/deflation_token.move b/aptos-move/framework/aptos-framework/tests/deflation_token.move index fa98e45a27e85..58c1e711d68a9 100644 --- a/aptos-move/framework/aptos-framework/tests/deflation_token.move +++ b/aptos-move/framework/aptos-framework/tests/deflation_token.move @@ -58,7 +58,7 @@ module 0xcafe::deflation_token { creator: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); diff --git a/aptos-move/framework/aptos-framework/tests/deflation_token_tests.move b/aptos-move/framework/aptos-framework/tests/deflation_token_tests.move index 29bfe73c5fd32..32f4f153a2cd4 100644 --- a/aptos-move/framework/aptos-framework/tests/deflation_token_tests.move +++ b/aptos-move/framework/aptos-framework/tests/deflation_token_tests.move @@ -17,7 +17,7 @@ module 0xcafe::deflation_token_tests { aaron: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); @@ -64,7 +64,7 @@ module 0xcafe::deflation_token_tests { aaron: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); @@ -87,7 +87,7 @@ module 0xcafe::deflation_token_tests { creator: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); @@ -112,7 +112,7 @@ module 0xcafe::deflation_token_tests { aaron: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); @@ -138,7 +138,7 @@ module 0xcafe::deflation_token_tests { creator: &signer, ) { let (creator_ref, _) = fungible_asset::create_test_token(creator); - let (_, _, _) = fungible_asset::init_test_metadata(&creator_ref); + let (_, _, _, _) = fungible_asset::init_test_metadata(&creator_ref); deflation_token::initialize(creator, &creator_ref); let withdraw = function_info::new_function_info( @@ -272,7 +272,7 @@ module 0xcafe::deflation_token_tests { creator: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); @@ -360,7 +360,7 @@ module 0xcafe::deflation_token_tests { aaron: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, transfer_ref, _) = fungible_asset::init_test_metadata(&creator_ref); + let (mint, transfer_ref, _, _) = fungible_asset::init_test_metadata(&creator_ref); let metadata = object::convert(token_object); let creator_store = fungible_asset::create_test_store(creator, metadata); 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 index 5749acbc18a41..d4bf6abbdba52 100644 --- a/aptos-move/framework/aptos-framework/tests/nil_op_token_tests.move +++ b/aptos-move/framework/aptos-framework/tests/nil_op_token_tests.move @@ -12,7 +12,7 @@ module aptos_framework::nil_op_token_tests { creator: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); diff --git a/aptos-move/framework/aptos-framework/tests/permissioned_token_tests.move b/aptos-move/framework/aptos-framework/tests/permissioned_token_tests.move index 683b0e9c8afd1..02f12ce85abf5 100644 --- a/aptos-move/framework/aptos-framework/tests/permissioned_token_tests.move +++ b/aptos-move/framework/aptos-framework/tests/permissioned_token_tests.move @@ -12,7 +12,7 @@ module 0xcafe::permissioned_token_tests { aaron: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); @@ -47,7 +47,7 @@ module 0xcafe::permissioned_token_tests { aaron: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); @@ -81,7 +81,7 @@ module 0xcafe::permissioned_token_tests { aaron: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); diff --git a/aptos-move/framework/aptos-framework/tests/reentrant_token_tests.move b/aptos-move/framework/aptos-framework/tests/reentrant_token_tests.move index d68af4bbceb76..c60edb17d5f5f 100644 --- a/aptos-move/framework/aptos-framework/tests/reentrant_token_tests.move +++ b/aptos-move/framework/aptos-framework/tests/reentrant_token_tests.move @@ -12,7 +12,7 @@ module 0xcafe::reentrant_token_tests { creator: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); diff --git a/aptos-move/framework/aptos-framework/tests/simple_dispatchable_token_fa_tests.move b/aptos-move/framework/aptos-framework/tests/simple_dispatchable_token_fa_tests.move index 1fb4a844ab033..eee226f7d567c 100644 --- a/aptos-move/framework/aptos-framework/tests/simple_dispatchable_token_fa_tests.move +++ b/aptos-move/framework/aptos-framework/tests/simple_dispatchable_token_fa_tests.move @@ -28,7 +28,7 @@ module aptos_framework::simple_token_fa_tests { aaron: &signer, ) { let (creator_ref, test_token) = create_test_token(creator); - let (mint_ref, transfer_ref, _burn_ref) = init_test_metadata(&creator_ref); + let (mint_ref, transfer_ref, _burn_ref, _mutate_metadata_ref) = init_test_metadata(&creator_ref); let metadata = object::convert(test_token); simple_token::initialize(creator, &creator_ref); @@ -49,7 +49,7 @@ module aptos_framework::simple_token_fa_tests { #[test(creator = @0xcafe)] fun test_merge_and_exact(creator: &signer) { let (creator_ref, _test_token) = create_test_token(creator); - let (mint_ref, _transfer_ref, burn_ref) = init_test_metadata(&creator_ref); + let (mint_ref, _transfer_ref, burn_ref, _mutate_metadata_ref) = init_test_metadata(&creator_ref); simple_token::initialize(creator, &creator_ref); let fa = mint(&mint_ref, 100); @@ -73,7 +73,7 @@ module aptos_framework::simple_token_fa_tests { features::change_feature_flags_for_testing(fx, vector[], vector[feature]); let (creator_ref, token_object) = create_test_token(creator); - let (mint_ref, transfer_ref, _burn) = init_test_metadata(&creator_ref); + let (mint_ref, transfer_ref, _burn_ref, _mutate_metadata_ref) = init_test_metadata(&creator_ref); let test_token = object::convert(token_object); simple_token::initialize(creator, &creator_ref); @@ -101,7 +101,7 @@ module aptos_framework::simple_token_fa_tests { creator: &signer ) { let (creator_ref, test_token) = create_test_token(creator); - let (mint_ref, transfer_ref, _burn_ref) = init_test_metadata(&creator_ref); + let (mint_ref, transfer_ref, _burn_ref, _mutate_metadata_ref) = init_test_metadata(&creator_ref); let metadata = object::convert(test_token); simple_token::initialize(creator, &creator_ref); 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 index 6ec82bac2b94a..d62278c6c54d0 100644 --- a/aptos-move/framework/aptos-framework/tests/ten_x_token_tests.move +++ b/aptos-move/framework/aptos-framework/tests/ten_x_token_tests.move @@ -11,7 +11,7 @@ module aptos_framework::ten_x_token_tests { creator: &signer, ) { let (creator_ref, token_object) = fungible_asset::create_test_token(creator); - let (mint, _, _) = fungible_asset::init_test_metadata(&creator_ref); + 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); diff --git a/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs b/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs index 13d9b5611950b..521d62bd6ae22 100644 --- a/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs +++ b/aptos-move/framework/src/natives/aggregator_natives/aggregator_v2.rs @@ -36,9 +36,6 @@ use std::{cell::RefMut, collections::VecDeque}; /// The generic type supplied to aggregator snapshots is not supported. pub const EUNSUPPORTED_AGGREGATOR_SNAPSHOT_TYPE: u64 = 0x03_0005; -/// The aggregator api feature is not enabled. -pub const EAGGREGATOR_API_NOT_ENABLED: u64 = 0x03_0006; - /// The generic type supplied to the aggregators is not supported. pub const EUNSUPPORTED_AGGREGATOR_TYPE: u64 = 0x03_0007; @@ -54,16 +51,6 @@ pub const EAGGREGATOR_FUNCTION_NOT_YET_SUPPORTED: u64 = 0x03_0009; /// If we want to increase this, we need to modify BITS_FOR_SIZE in types/src/delayed_fields.rs. pub const DERIVED_STRING_INPUT_MAX_LENGTH: usize = 1024; -macro_rules! abort_if_aggregator_api_not_enabled { - ($context:expr) => { - if !$context.aggregator_v2_api_enabled() { - return Err(SafeNativeError::Abort { - abort_code: EAGGREGATOR_API_NOT_ENABLED, - }); - } - }; -} - fn get_width_by_type(ty_arg: &Type, error_code_if_incorrect: u64) -> SafeNativeResult { match ty_arg { Type::U128 => Ok(16), @@ -113,11 +100,7 @@ fn get_context_data<'t, 'b>( context: &'t mut SafeNativeContext<'_, 'b, '_, '_>, ) -> Option<(&'b dyn DelayedFieldResolver, RefMut<'t, DelayedFieldData>)> { let aggregator_context = context.extensions().get::(); - if aggregator_context - .delayed_field_resolver - .is_delayed_field_optimization_capable() - && context.aggregator_v2_delayed_fields_enabled() - { + if aggregator_context.delayed_field_optimization_enabled { Some(( aggregator_context.delayed_field_resolver, aggregator_context.delayed_field_data.borrow_mut(), @@ -157,8 +140,6 @@ fn native_create_aggregator( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(args.len(), 1); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_CREATE_AGGREGATOR_BASE)?; @@ -176,8 +157,6 @@ fn native_create_unbounded_aggregator( ty_args: Vec, args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(args.len(), 0); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_CREATE_AGGREGATOR_BASE)?; @@ -194,8 +173,6 @@ fn native_try_add( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(args.len(), 2); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_TRY_ADD_BASE)?; @@ -242,8 +219,6 @@ fn native_try_sub( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(args.len(), 2); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_TRY_SUB_BASE)?; @@ -287,8 +262,6 @@ fn native_is_at_least_impl( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(args.len(), 2); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_IS_AT_LEAST_BASE)?; @@ -327,8 +300,6 @@ fn native_read( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(args.len(), 1); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_READ_BASE)?; @@ -365,8 +336,6 @@ fn native_snapshot( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(args.len(), 1); debug_assert_eq!(ty_args.len(), 1); context.charge(AGGREGATOR_V2_SNAPSHOT_BASE)?; @@ -402,8 +371,6 @@ fn native_create_snapshot( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(ty_args.len(), 1); debug_assert_eq!(args.len(), 1); context.charge(AGGREGATOR_V2_CREATE_SNAPSHOT_BASE)?; @@ -438,35 +405,13 @@ fn native_create_snapshot( **************************************************************************************************/ fn native_copy_snapshot( - context: &mut SafeNativeContext, + _context: &mut SafeNativeContext, _ty_args: Vec, _args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - Err(SafeNativeError::Abort { abort_code: EAGGREGATOR_FUNCTION_NOT_YET_SUPPORTED, }) - - // debug_assert_eq!(ty_args.len(), 1); - // debug_assert_eq!(args.len(), 1); - // context.charge(AGGREGATOR_V2_COPY_SNAPSHOT_BASE)?; - - // let snapshot_type = SnapshotType::from_ty_arg(context, &ty_args[0])?; - // let snapshot_value = snapshot_type.pop_snapshot_field_by_type(&mut args)?; - - // let result_value = if context.aggregator_execution_enabled() { - // let id = aggregator_snapshot_value_field_as_id(snapshot_value, resolver)?; - - // // snapshots are immutable so we can just return the id - // SnapshotValue::Integer(id.id() as u128) - // } else { - // snapshot_value - // }; - - // Ok(smallvec![Value::struct_(Struct::pack(vec![ - // snapshot_type.create_snapshot_value_by_type(result_value)? - // ]))]) } /*************************************************************************************************** @@ -478,8 +423,6 @@ fn native_read_snapshot( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(ty_args.len(), 1); debug_assert_eq!(args.len(), 1); context.charge(AGGREGATOR_V2_READ_SNAPSHOT_BASE)?; @@ -505,14 +448,11 @@ fn native_read_snapshot( * native fun string_concat(before: String, snapshot: &AggregatorSnapshot, after: String): AggregatorSnapshot; **************************************************************************************************/ fn native_string_concat( - context: &mut SafeNativeContext, + _context: &mut SafeNativeContext, _ty_args: Vec, _args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - // Deprecated function in favor of `derive_string_concat`. - Err(SafeNativeError::Abort { abort_code: EAGGREGATOR_FUNCTION_NOT_YET_SUPPORTED, }) @@ -527,8 +467,6 @@ fn native_read_derived_string( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(ty_args.len(), 0); debug_assert_eq!(args.len(), 1); context.charge(AGGREGATOR_V2_READ_SNAPSHOT_BASE)?; @@ -554,8 +492,6 @@ fn native_create_derived_string( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(ty_args.len(), 0); debug_assert_eq!(args.len(), 1); context.charge(AGGREGATOR_V2_CREATE_SNAPSHOT_BASE)?; @@ -597,8 +533,6 @@ fn native_derive_string_concat( ty_args: Vec, mut args: VecDeque, ) -> SafeNativeResult> { - abort_if_aggregator_api_not_enabled!(context); - debug_assert_eq!(ty_args.len(), 1); debug_assert_eq!(args.len(), 3); context.charge(AGGREGATOR_V2_STRING_CONCAT_BASE)?; diff --git a/aptos-move/framework/src/natives/aggregator_natives/context.rs b/aptos-move/framework/src/natives/aggregator_natives/context.rs index 38286cb82abf3..4e536394e42e3 100644 --- a/aptos-move/framework/src/natives/aggregator_natives/context.rs +++ b/aptos-move/framework/src/natives/aggregator_natives/context.rs @@ -49,6 +49,7 @@ pub struct NativeAggregatorContext<'a> { txn_hash: [u8; 32], pub(crate) aggregator_v1_resolver: &'a dyn AggregatorV1Resolver, pub(crate) aggregator_v1_data: RefCell, + pub(crate) delayed_field_optimization_enabled: bool, pub(crate) delayed_field_resolver: &'a dyn DelayedFieldResolver, pub(crate) delayed_field_data: RefCell, } @@ -59,6 +60,7 @@ impl<'a> NativeAggregatorContext<'a> { pub fn new( txn_hash: [u8; 32], aggregator_v1_resolver: &'a dyn AggregatorV1Resolver, + delayed_field_optimization_enabled: bool, delayed_field_resolver: &'a dyn DelayedFieldResolver, ) -> Self { Self { @@ -66,6 +68,7 @@ impl<'a> NativeAggregatorContext<'a> { aggregator_v1_resolver, aggregator_v1_data: Default::default(), delayed_field_resolver, + delayed_field_optimization_enabled, delayed_field_data: Default::default(), } } @@ -220,7 +223,7 @@ mod test { #[test] fn test_v1_into_change_set() { let resolver = get_test_resolver_v1(); - let context = NativeAggregatorContext::new([0; 32], &resolver, &resolver); + let context = NativeAggregatorContext::new([0; 32], &resolver, true, &resolver); test_set_up_v1(&context); let AggregatorChangeSet { @@ -458,7 +461,7 @@ mod test { #[test] fn test_v2_into_change_set() { let resolver = get_test_resolver_v2(); - let context = NativeAggregatorContext::new([0; 32], &resolver, &resolver); + let context = NativeAggregatorContext::new([0; 32], &resolver, true, &resolver); test_set_up_v2(&context); let delayed_field_changes = context.into_delayed_fields(); assert!(!delayed_field_changes.contains_key(&DelayedFieldID::new_with_width(1000, 8))); diff --git a/aptos-move/vm-genesis/Cargo.toml b/aptos-move/vm-genesis/Cargo.toml index b8d7e7efb3a11..59927cdd791a7 100644 --- a/aptos-move/vm-genesis/Cargo.toml +++ b/aptos-move/vm-genesis/Cargo.toml @@ -19,7 +19,6 @@ aptos-framework = { workspace = true } aptos-gas-schedule = { workspace = true } aptos-types = { workspace = true } aptos-vm = { workspace = true } -aptos-vm-types = { workspace = true } bcs = { workspace = true } bytes = { workspace = true } move-core-types = { workspace = true } diff --git a/aptos-move/vm-genesis/src/lib.rs b/aptos-move/vm-genesis/src/lib.rs index 65657b7ed6194..bb1333021ca07 100644 --- a/aptos-move/vm-genesis/src/lib.rs +++ b/aptos-move/vm-genesis/src/lib.rs @@ -33,16 +33,15 @@ use aptos_types::{ randomness_api_v0_config::{AllowCustomMaxGasFlag, RequiredGasDeposit}, FeatureFlag, Features, GasScheduleV2, OnChainConsensusConfig, OnChainExecutionConfig, OnChainJWKConsensusConfig, OnChainRandomnessConfig, RandomnessConfigMoveStruct, - TimedFeaturesBuilder, APTOS_MAX_KNOWN_VERSION, + APTOS_MAX_KNOWN_VERSION, }, transaction::{authenticator::AuthenticationKey, ChangeSet, Transaction, WriteSetPayload}, write_set::TransactionWrite, }; use aptos_vm::{ data_cache::AsMoveResolver, - move_vm_ext::{MoveVmExt, SessionExt, SessionId}, + move_vm_ext::{GenesisMoveVM, SessionExt}, }; -use aptos_vm_types::storage::change_set_configs::ChangeSetConfigs; use move_core_types::{ account_address::AccountAddress, identifier::Identifier, @@ -122,24 +121,15 @@ pub fn encode_aptos_mainnet_genesis_transaction( assert!(!genesis_config.is_test, "This is mainnet!"); validate_genesis_config(genesis_config); - // Create a Move VM session so we can invoke on-chain genesis intializations. + // Create a Move VM session, so we can invoke on-chain genesis initializations. let mut state_view = GenesisStateView::new(); for (module_bytes, module) in framework.code_and_compiled_modules() { state_view.add_module(&module.self_id(), module_bytes); } - let data_cache = state_view.as_move_resolver(); - let move_vm = MoveVmExt::new( - LATEST_GAS_FEATURE_VERSION, - Ok(&AptosGasParameters::zeros()), - ChainId::test().id(), - Features::default(), - TimedFeaturesBuilder::enable_all().build(), - &data_cache, - false, - ) - .unwrap(); - let id1 = HashValue::zero(); - let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1), None); + + let vm = GenesisMoveVM::new(chain_id); + let resolver = state_view.as_move_resolver(); + let mut session = vm.new_genesis_session(&resolver, HashValue::zero()); // On-chain genesis process. let consensus_config = OnChainConsensusConfig::default_for_genesis(); @@ -170,17 +160,16 @@ pub fn encode_aptos_mainnet_genesis_transaction( // Reconfiguration should happen after all on-chain invocations. emit_new_block_and_epoch_event(&mut session); - let configs = ChangeSetConfigs::unlimited_at_gas_feature_version(LATEST_GAS_FEATURE_VERSION); + let configs = vm.genesis_change_set_configs(); let mut change_set = session.finish(&configs).unwrap(); - // Publish the framework, using a different session id, in case both scripts creates tables + // Publish the framework, using a different session id, in case both scripts create tables. let state_view = GenesisStateView::new(); - let data_cache = state_view.as_move_resolver(); + let resolver = state_view.as_move_resolver(); - 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), None); + let mut new_id = [0u8; 32]; + new_id[31] = 1; + let mut session = vm.new_genesis_session(&resolver, HashValue::new(new_id)); publish_framework(&mut session, framework); let additional_change_set = session.finish(&configs).unwrap(); change_set @@ -239,24 +228,15 @@ pub fn encode_genesis_change_set( ) -> ChangeSet { validate_genesis_config(genesis_config); - // Create a Move VM session so we can invoke on-chain genesis intializations. + // Create a Move VM session so we can invoke on-chain genesis initializations. let mut state_view = GenesisStateView::new(); for (module_bytes, module) in framework.code_and_compiled_modules() { state_view.add_module(&module.self_id(), module_bytes); } - let data_cache = state_view.as_move_resolver(); - let move_vm = MoveVmExt::new( - LATEST_GAS_FEATURE_VERSION, - Ok(&AptosGasParameters::zeros()), - ChainId::test().id(), - Features::default(), - TimedFeaturesBuilder::enable_all().build(), - &data_cache, - false, - ) - .unwrap(); - let id1 = HashValue::zero(); - let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1), None); + + let resolver = state_view.as_move_resolver(); + let vm = GenesisMoveVM::new(chain_id); + let mut session = vm.new_genesis_session(&resolver, HashValue::zero()); // On-chain genesis process. initialize( @@ -307,17 +287,16 @@ pub fn encode_genesis_change_set( // Reconfiguration should happen after all on-chain invocations. emit_new_block_and_epoch_event(&mut session); - let configs = ChangeSetConfigs::unlimited_at_gas_feature_version(LATEST_GAS_FEATURE_VERSION); + let configs = vm.genesis_change_set_configs(); let mut change_set = session.finish(&configs).unwrap(); let state_view = GenesisStateView::new(); - let data_cache = state_view.as_move_resolver(); + let resolver = state_view.as_move_resolver(); - // Publish the framework, using a different session id, in case both scripts creates tables - 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), None); + // Publish the framework, using a different id, in case both scripts create tables. + let mut new_id = [0u8; 32]; + new_id[31] = 1; + let mut session = vm.new_genesis_session(&resolver, HashValue::new(new_id)); publish_framework(&mut session, framework); let additional_change_set = session.finish(&configs).unwrap(); change_set @@ -387,10 +366,7 @@ fn exec_function( let storage = TraversalStorage::new(); session .execute_function_bypass_visibility( - &ModuleId::new( - account_config::CORE_CODE_ADDRESS, - Identifier::new(module_name).unwrap(), - ), + &ModuleId::new(CORE_CODE_ADDRESS, Identifier::new(module_name).unwrap()), &Identifier::new(function_name).unwrap(), ty_args, args, @@ -1080,20 +1056,11 @@ pub fn test_genesis_module_publishing() { { state_view.add_module(&module.self_id(), module_bytes); } - let data_cache = state_view.as_move_resolver(); - - let move_vm = MoveVmExt::new( - LATEST_GAS_FEATURE_VERSION, - Ok(&AptosGasParameters::zeros()), - ChainId::test().id(), - Features::default(), - TimedFeaturesBuilder::enable_all().build(), - &data_cache, - false, - ) - .unwrap(); - let id1 = HashValue::zero(); - let mut session = move_vm.new_session(&data_cache, SessionId::genesis(id1), None); + + let vm = GenesisMoveVM::new(ChainId::test()); + let resolver = state_view.as_move_resolver(); + + let mut session = vm.new_genesis_session(&resolver, HashValue::zero()); publish_framework(&mut session, aptos_cached_packages::head_release_bundle()); } diff --git a/aptos-move/writeset-transaction-generator/Cargo.toml b/aptos-move/writeset-transaction-generator/Cargo.toml index 26933dca31782..b35659a241013 100644 --- a/aptos-move/writeset-transaction-generator/Cargo.toml +++ b/aptos-move/writeset-transaction-generator/Cargo.toml @@ -14,17 +14,9 @@ rust-version = { workspace = true } [dependencies] anyhow = { workspace = true } -aptos-cached-packages = { workspace = true } aptos-crypto = { workspace = true } -aptos-framework = { workspace = true } -aptos-gas-schedule = { workspace = true } aptos-types = { workspace = true } aptos-vm = { workspace = true } -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/release/artifacts.json b/aptos-move/writeset-transaction-generator/release/artifacts.json deleted file mode 100644 index 0b2619def8012..0000000000000 --- a/aptos-move/writeset-transaction-generator/release/artifacts.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "chain_id": 1, - "version": 15408203, - "commit_hash": "b99b027e142f6169fd25b2e946d553d98f3e9359", - "stdlib_hash": "ab590b216554b9eadca01e86ff630e760d3729c84463b650a51c3bcbe668e985", - "diem_version": 2, - "release_name": "release-1.2.0-rc0" - }, - { - "chain_id": 1, - "version": 51131474, - "commit_hash": "70b660ab70264c775f7f0ee5835c4138332803ec", - "stdlib_hash": "7513478cd1fc3388969b0dd5371d237579a94b9dccac3d23b87f46f9a76f322a", - "diem_version": 3, - "release_name": "release-1.4.0-rc0" - } -] diff --git a/aptos-move/writeset-transaction-generator/release/release-1.2.0-rc0.blob b/aptos-move/writeset-transaction-generator/release/release-1.2.0-rc0.blob deleted file mode 100644 index 40f2b9e76d646..0000000000000 Binary files a/aptos-move/writeset-transaction-generator/release/release-1.2.0-rc0.blob and /dev/null differ diff --git a/aptos-move/writeset-transaction-generator/release/release-1.4.0-rc0.blob b/aptos-move/writeset-transaction-generator/release/release-1.4.0-rc0.blob deleted file mode 100644 index f8c2a4f0d7f58..0000000000000 Binary files a/aptos-move/writeset-transaction-generator/release/release-1.4.0-rc0.blob and /dev/null differ diff --git a/aptos-move/writeset-transaction-generator/src/admin_script_builder.rs b/aptos-move/writeset-transaction-generator/src/admin_script_builder.rs deleted file mode 100644 index 0fee6788fb569..0000000000000 --- a/aptos-move/writeset-transaction-generator/src/admin_script_builder.rs +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright © Aptos Foundation -// Parts of the project are originally copyright © Meta Platforms, Inc. -// SPDX-License-Identifier: Apache-2.0 - -use anyhow::Result; -use aptos_types::{ - account_address::AccountAddress, - account_config::aptos_test_root_address, - transaction::{Script, WriteSetPayload}, -}; -use handlebars::Handlebars; -use move_compiler::{compiled_unit::AnnotatedCompiledUnit, Compiler, Flags}; -use serde::Serialize; -use std::{collections::HashMap, io::Write, path::PathBuf}; -use tempfile::NamedTempFile; - -/// The relative path to the scripts templates -pub const SCRIPTS_DIR_PATH: &str = "templates"; - -pub fn compile_script(source_file_str: String, bytecode_version: Option) -> Vec { - let (_files, mut compiled_program) = Compiler::from_files( - vec![source_file_str], - aptos_cached_packages::head_release_bundle() - .files() - .unwrap(), - aptos_framework::named_addresses().clone(), - Flags::empty() - .set_sources_shadow_deps(false) - .set_skip_attribute_checks(false), - aptos_framework::extended_checks::get_all_attribute_names(), - ) - .build_and_report() - .unwrap(); - assert!(compiled_program.len() == 1); - match compiled_program.pop().unwrap() { - AnnotatedCompiledUnit::Module(_) => panic!("Unexpected module when compiling script"), - x @ AnnotatedCompiledUnit::Script(_) => x.into_compiled_unit().serialize(bytecode_version), - } -} - -fn compile_admin_script(input: &str, bytecode_version: Option) -> Result